# Create a GraphQL query Having seen the advantages of using GraphQL to improve performance, stability, and maintainability of our application, let’s now focus on querying. We will use GraphQL to: - request only specific fields instead of the entire record when fetching resources. - create reusable queries using parameters. - determine the existence of a commercetools resource. - retrieve data from multiple endpoints in one GraphQL query. - retrieve large amounts of data using pagination. - use query fragments to modularize our GraphQL queries. ## Request specific fields in returned data As already mentioned, one of the main features of GraphQL is the ability to specify the fields in a resource that you are interested in-you don’t have to fetch the data of the entire record. This approach saves time and improves performance in cases when you're returning multiple records across the network. Less data per record means you can have more records in each response. Let’s look at another example of overfetching. Say you want to read Customer records, but only need the customer’s first name, last name, and email address. When making this request with the REST API, you will get the full Customer information in your response. This would look like the following: ```json { "limit": 20, "offset": 0, "count": 6, "total": 6, "results": [ { "id": "e5ab352e-7be2-4562-8bc5-4d9ba763489c", "version": 1, "createdAt": "2024-01-17T23:51:35.600Z", "lastModifiedAt": "2024-01-17T23:51:35.600Z", "lastModifiedBy": { "isPlatformClient": true, "user": { "typeId": "user", "id": "c950c084-f5d0-4a42-8761-229d5c7a8598" } }, "createdBy": { "isPlatformClient": true, "user": { "typeId": "user", "id": "c950c084-f5d0-4a42-8761-229d5c7a8598" } }, "email": "jen@example.uk", "firstName": "Jennifer", "lastName": "Jones", "password": "****hO4=", "addresses": [ { "id": "mjNpcegk", "firstName": "Jennifer", "lastName": "Jones", "streetName": "Main Road", "streetNumber": "100", "postalCode": "SW1A2AA", "city": "Westminster", "country": "GB" } ], "shippingAddressIds": [], "billingAddressIds": [], "isEmailVerified": true, "key": "jennifer-jones", "stores": [], "authenticationMode": "Password" } ] } } ] ``` In this example, we’re only showing one Customer record of the returned data for brevity. You could imagine how much data would be included if you were requesting multiple records. This is more information than necessary, consuming excessive bandwidth if you are not using all of this data. With a GraphQL query specifying only the fields you want, you could instead get a response like this: ```json { "data": { "customers": { "results": [ { "firstName": "Jennifer", "lastName": "Jones", "email": "jen@example.uk" }, ... ] } } } ``` A much cleaner and more efficient representation of the data. What does a GraphQL query look like? If we wanted to write a request to generate the response above, it would look like this: ```graphql query queryCustomers { customers { results { firstName lastName email } } } ``` How is this query put together? Let’s take a closer look. - First, the word `query` indicates that this is a request to retrieve information, as opposed to an update or deletion. - Next is the name of the query. Here we’ve chosen `queryCustomers` because that’s a nice description of what this query does. - Then comes the resource that we want to query. We are using Customers, and this allows one or many customers to be returned. If we only want to return one Customer, then we can use a `where` condition or use the [Customer](/api/general-concepts.md#single-resource-query-response) resource and query by a Customer ID. When there are multiple results we use [PagedQueryResult](/api/general-concepts.md#pagedqueryresult) to manage the pagination. - The last element is a list of the fields that you want to have returned. Here we see that we list subfields from the results array. `results` here is an array of Customer records, so we call out the individual fields we want from each Customer record that is returned. In this case, the first name, last name, and email. ## Build your query with parameters In addition to querying, you can use predicates to define which records to return. Predicates are included in parentheses after the resource name and before the opening bracket for the return values. The GraphQL API supports the `where`, `sort`, `limit`, and `offset` query parameters. For the full definitions and example usage of each parameter, see [Add query parameters](/api/graphql.md#add-query-parameters) in the GraphQL API reference. When querying multiple resources, you can also request metadata fields alongside `results`. For the full list of available return fields, see [Choose what to return](/api/graphql.md#choose-what-to-return) in the GraphQL API reference. Here’s a sample query using the `where` and the `sort` query parameters. The query returns data for all Customers whose first name is `Jennifer` in ascending order by `id`. ```graphql highlightLines="2" query queryCustomersWithWhere { customers(where: "firstName=\"Jennifer\"", sort: "id asc") { results { firstName lastName email } } } ``` ## Use variables in your query parameters In addition to sending hardcoded values in query parameters, like the previous example (`where: "firstName=\"Jennifer\""`), you can also use variables for those parameters: ```graphql highlightLines="2" query queryCustomersWithWhereVariable($customerName: String!) { customers(where: $customerName, sort: "id asc") { results { firstName lastName email } } } ``` This gives your GraphQL queries much greater flexibility! As you can see, you define the variable right after the query name using the dollar sign ($) as the first character and then using that same variable in the where clause. In this case, the variable `customerName` could contain a string like `"firstName=\"Jennifer\""` or `"lastName=\"Jones\""`. You can also use variables in a single response query where, for example, you set the variable `custKey` to a string like `jennifer-jones`. ```graphql query queryCustomerByKeyWithVariable($custKey: String!) { customer(key: $custKey) { firstName lastName email } } ``` You define the value for the variable in the variables section of the request, or in the **QUERY VARIABLES** window of GraphQL Explorer. ![GraphQL Explorer shows a customer query that uses query variables.](https://docs.commercetools.com/learning-developer-essentials/images/graphql/gql-custkey-with-variable.png) ## Check whether resources exist Instead of retrieving full records, you can use the `exists` field to check whether at least one resource matches your query predicate. For the full syntax and examples, see [Check if resources exist](/api/graphql.md#check-if-resources-exist) in the GraphQL API reference. ## Retrieve data from multiple resource endpoints GraphQL not only lets you select specific fields within a requested record but also retrieves data from multiple commercetools resources in a single request. This approach reduces the latency associated with multiple network calls. Moreover, when accessing data from various resources, GraphQL can process these requests in parallel, making it more efficient than REST. Let’s assume you would like to build a customer's profile section on a webshop including their personal record and their last five orders. The following example achieves this in one request. It uses variables in the parameters to simultaneously retrieve details about the Customer and all of their Orders, sorted in descending order by creation time. ```graphql highlightLines="2,11" query queryCustomerAndOrders($custId: String!, $whereCustId: String!) { customer(id: $custId) { id firstName lastName email defaultShippingAddress { country } } orders(where: $whereCustId, sort: "createdAt desc", limit: 5) { results { customerId customerEmail createdAt orderState totalPrice { type currencyCode centAmount fractionDigits } } } } ``` The variables are: ```graphql { "custId": "{id}", "whereCustId": "customerId=\"{id}\"" } ``` Which, in our case, retrieves the following: ```json { "data": { "customer": { "id": "e5ab352e-7be2-4562-8bc5-4d9ba763489c", "firstName": "Jennifer", "lastName": "Jones", "email": "jen@example.uk", "defaultShippingAddress": null }, "orders": { "results": [ { "customerId": "e5ab352e-7be2-4562-8bc5-4d9ba763489c", "customerEmail": "jen@example.uk", "createdAt": "2024-01-17T23:51:48.354Z", "orderState": "Confirmed", "totalPrice": { "type": "centPrecision", "currencyCode": "GBP", "centAmount": 461799, "fractionDigits": 2 } } ] } } } ``` ## Retrieve large amounts of data using pagination If you run a successful webshop with thousands of customers and even more orders, retrieving pages of data in the most efficient way possible is a task that will require a sound strategy. Generally, you may want to sort records by ID (in commercetools, IDs can be sorted) and then retrieve a set number of them at a time. If commercetools knows what the last ID is at the end of a given page, then we can pass zeros as the initial ID (`00000000-0000-0000-0000-000000000000`). To do that with GraphQL, we could use a query like the following and update the ID value on each subsequent query. ```graphql query queryCustomersWithPagination { customers( limit: 20 sort: "id asc" where: "id>\"00000000-0000-0000-0000-000000000000\"" ) { count results { id firstName lastName email } } } ``` This starts off with the lowest ID possible and returns 20 records. You would, in your code, take the value of the ID in the last record returned and use it in the `where` clause of the next query. When the count returned is less than the limit you requested, you have reached the end of your dataset. To do this, it is not necessary to include the `total` field; you can exclude this field to decrease the latency. This is because the `total` count adds a slight computation overhead to each query. Optimizing paged requests is an important topic. See our docs for more on the concept of [pagination](/api/general-concepts.md#pagination) in commercetools. ## Use fragments to modularize your queries Suppose you need to find specific information for all addresses of a customer, including different data for their default billing and shipping addresses. Instead of repeatedly specifying the same information in your GraphQL query, why not simplify the process by dividing the address data into reusable fragments? This approach allows you to efficiently query only the necessary subsets of information for each address. In this case, you could use one fragment to return only postal codes and country fields, and another fragment for a larger set of address fields. To define a fragment, you use the keyword `fragment`. To include a fragment in your query, you precede the fragment with three periods ( `…` ). Here’s an example where we define a fragment to return postal code and country, and a second fragment that includes those fields along with additional ones. We will first show how to write this query without using fragments, and then illustrate how using fragments can simplify the query. This is what the query would look like without fragments: ```graphql query queryCustomerWithAddresses($custId: String!) { customer(id: $custId) { firstName lastName email id version addresses { postalCode country } defaultShippingAddress { streetNumber streetName apartment additionalStreetInfo city state postalCode country additionalAddressInfo } defaultBillingAddress { streetNumber streetName apartment additionalStreetInfo city state postalCode country additionalAddressInfo } } } ``` The result would look like this: ```json { "data": { "customer": { "firstName": "Jennifer", "lastName": "Jones", "email": "jen@example.uk", "id": "e5ab352e-7be2-4562-8bc5-4d9ba763489c", "version": 7, "addresses": [ { "postalCode": "SW1A2AA", "country": "GB" }, { "postalCode": "SWA 2AS", "country": "GB" } ], "defaultShippingAddress": { "streetNumber": "70", "streetName": "Whitehall", "apartment": null, "additionalStreetInfo": null, "city": "London", "state": null, "postalCode": "SWA 2AS", "country": "GB", "additionalAddressInfo": null }, "defaultBillingAddress": { "streetNumber": "70", "streetName": "Whitehall", "apartment": null, "additionalStreetInfo": null, "city": "London", "state": null, "postalCode": "SWA 2AS", "country": "GB", "additionalAddressInfo": null } } } } ``` Now, let’s introduce the first fragment, which will return only the postal code and country: ```graphql fragment CountryInfo on Address { postalCode country } ``` Now the second fragment, returning more address info and referencing the first fragment: ```graphql highlightLines="7" fragment AddressInfo on Address { streetNumber streetName apartment additionalStreetInfo city ...CountryInfo additionalAddressInfo } ``` Let’s rewrite our original query utilizing these newly defined fragments: ```graphql highlightLines="9,12,15" query queryCustomerWithFragments($custId: String!) { customer(id: $custId) { firstName lastName email id version addresses { ...CountryInfo } defaultShippingAddress { ...AddressInfo } defaultBillingAddress { ...AddressInfo } } } ``` This much shorter query returns exactly the same data as the original one above. Let’s try another example. This example returns Product information. Let’s look at the fragments first and then build them into a query. Here’s the first fragment defining the return values in ProductData of SKUs and the English localization for the name field: ```graphql fragment Product on ProductData { skus name(locale: "en") } ``` You can then reference that fragment in a query, or even in another fragment, using the three periods syntax: ```graphql highlightLines="6" fragment StagedProduct on ProductQueryResult { results { id masterData { staged { ...Product } } } } ``` And now we can build a larger query, like the following: ```graphql highlightLines="3-4" query queryProduct { products(limit: 1) { ...StagedProduct ...CurrentProduct } } fragment Product on ProductData { skus name(locale: "en-us") } ``` Which returns something like this: ```graphql { "data": { "products": { "results": [ { "id": "6840d46f-bfd8-4bb1-9ae6-4a1a544a9e74", "masterData": { "staged": { "skus": [ "SQB-034" ], "name": "Ecru Double Bed" }, "current": { "skus": [ "SQB-034" ], "name": "Ecru Double Bed" } } } ] } } } ``` ## Related pages - [Area overview page with navigation](/learning-developer-essentials.md) - [Previous page: Use the GraphQL Explorer and the SDK](/learning-developer-essentials/graphql/use-graphiql-and-the-sdk.md) - [Next page: Create a GraphQL mutation](/learning-developer-essentials/graphql/create-a-graphql-mutation.md)