Using queries

A GraphQL query retrieves data from the Magento server in a similar manner as a REST GET call. The current set of Magento GraphQL queries allow a mobile app or browser to render a wide variety of information, including the following:

  • A set of products to be displayed. This can include the entire catalog or those that match customer-specified criteria.
  • Customer data. With a customer token, a query can retrieve basic information about a customer as well as billing and shipping addresses, wish lists, order history, and other sensitive data.
  • Shopping cart contents. GraphQL supports both guest and logged-in customer carts.
  • Store configuration values, including theme and CMS settings, the currency code, and supported countries.

The Magento REST GET endpoints retrieve a wide variety of information on behalf of the merchant. Many of these endpoints are for retrieving backend information. For example, the GET /V1/customers/search endpoint can be used to find a subset of customers that meet certain criteria, such as those that live in a particular state or have a birthday this month. Likewise, the GET /V1/invoices endpoint can return all the recently-generated invoices. This type of functionality is not required for the frontend, so it is not available in GraphQL queries. The queries are designed to improve the customer’s user experience by quickly retrieving the data needed to render pages.

Over time, the Magento GraphQL queries will duplicate the functionality of all storefront-facing GET calls, while making it possible to query more data in one request. The main difference will be that GraphQL will support storefront use cases, while REST will support admin use cases.

Structure of a query

A query contains the following elements:

  • The optional keyword query. If no keyword is specified at the beginning of a request, the processor assumes the request is a query.
  • An operation name for your local implementation. This name is required if you include variables. Otherwise, it is optional.
  • The query name
  • The terms to search for. The terms can be in the form of objects, attributes, or a combination. Queries that don’t require search terms obtain their context from the customer’s authorization token or store ID, both of which are specified in the header of the call.
  • The output object, which specifies which data the query returns.

The following example shows the structure of the cart query:

1
2
3
query myCartQuery{
  cart(cart_id: String!): Cart
}

In the preceding example, myCartQuery identifies your implementation of the cart query. cart_id is a non-nullable string that defines the cart to query. (The exclamation point indicates the value is non-nullable.) The Cart output object defines which fields to return.

Now let’s fully define a query:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
query myCartQuery{
  cart(cart_id: "1WxKm8WUm3uFKXLlHXezew5WREfVRPAn") {
    items {
      id
      quantity
    }
    billing_address {
      firstname
      lastname
      postcode
      }
    shipping_addresses {
      firstname
      lastname
      postcode
    }
  }
}

In this example, we’ve supplied a cart ID as input, (which was generated by the createEmptyCart mutation). The output includes the cart_id as well as selected information about the items in the cart and the billing and shipping addresses.

The following example shows the query response:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "data": {
    "cart": {
      "items": [
        {
          "id": "5",
          "quantity": 1
        }
      ],
      "billing_address": {
        "firstname": "Veronica",
        "lastname": "Costello",
        "postcode": "49628-7978"
      },
      "shipping_addresses": [
        {
          "firstname": "Veronica",
          "lastname": "Costello",
          "postcode": "49628-7978"
        }
      ]
    }
  }
}

Magento will not run a query that is too complex. The number of fields, objects, and nodes are factors in determining the complexity of a query.

Query variables

Specifying variables in a query can help increase code re-use. Consider the following requirements when generating a query that contains one or more variables:

  • All variables must be declared up-front, immediately after the operation name.
  • Variables are typed: they can be scalar or an object.
  • You must use all declared variables. Object variables are defined in JSON.

The following example declares the $cart_id variable. It is referenced in the input statement.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
query myCartQueryWithVariable($cart_id: String!) {
  cart(cart_id: $cart_id) {
    items {
      id
      quantity
    }
    billing_address {
      firstname
      lastname
      postcode
    }
    shipping_addresses {
      firstname
      lastname
      postcode
    }
  }
}

Variables are defined separately in JSON:

1
2
3
{
  "cart_id": "1WxKm8WUm3uFKXLlHXezew5WREfVRPAn"
}

Staging queries

Magento GraphQL allows you to use certain queries to return preview information for staged content. Staging, a Magento Commerce feature, allows merchants to schedule a set of changes to the storefront that run for a prescribed time in the future. These changes, also known as a campaign, are defined within the Admin. Customers do not have access to staged content, and as a result, staging queries have requirements that do not apply to traditional queries and mutations.

Content Staging in the Merchant User Guide describes how to create a campaign.

You can use the following queries to return staged preview information.

  • categoryList
  • products

The products query does not support full text search in the context of staging, because staged content is not indexed. Therefore, omit the search input attribute in your staging products queries.

A staging query requires two specialized headers:

Header name Description
Authorization Bearer: <authorization_token> An admin token. Use the POST /V1/integration/admin/token REST endpoint to generate this token.
Preview-Version A timestamp (seconds since January 1, 1970) that is inside the range of dates of the campaign you are querying.

Magento returns an authorization error if you specify an invalid token or do not include both headers. If the specified timestamp does not correspond to a date in a scheduled campaign, the query results reflect the current storefront settings.

Magento also returns an error if you specify these headers with any other query or any mutation.

Example campaign

The example staging queries in this section are based on a simple campaign that creates a custom category and catalog sales rule using the Luma sample data. By default, the custom category and sales rule are disabled but become enabled when the campaign takes effect.

The following steps describe how to create this example campaign.

  1. Create a subcategory of Sale named End of Year Sale. Set the Enable Category field to No.
  2. Add several products to the subcategory.
  3. Schedule an update named End of Year Sale Update for the subcategory that takes effect at a later date. Configure the update so that the Enable Category field is set to Yes.
  4. Create a catalog sales rule with the following properties:
    • Set the Active switch to No.
    • In the Conditions section, define the condition as **Category is **.
    • In the Actions section, set the Apply field to Apply a percentage of original and the Discount Amount field to 25.
  5. Schedule an update for the catalog sales rule and assign it to the End of Year Sale Update. In this update, set the Active switch to Yes.

Staging products query

The following query returns information about a product (24-UG05) in the End of Year Sale campaign. The Preview-Version header contains the timestamp for a date that is within the duration of the campaign. When you include the proper headers, the query returns prices with applied discounts. Without the headers, the query returns only default prices.

Headers:

1
2
Authorization: Bearer hoyz7k697ubv5hcpq92yrtx39i7x10um
Preview-Version: 1576389600

Request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  products(filter: {sku: {eq: "24-UG05"}}) {
    items {
      name
      sku
      price_range {
        minimum_price {
          discount {
            percent_off
            amount_off
          }
          final_price {
            value
            currency
          }
          regular_price {
            value
          }
        }
      }
    }
  }
}

Response with headers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
  "data": {
    "products": {
      "items": [
        {
          "name": "Go-Get'r Pushup Grips",
          "sku": "24-UG05",
          "price_range": {
            "minimum_price": {
              "discount": {
                "percent_off": 25,
                "amount_off": 4.75
              },
              "final_price": {
                "value": 14.25,
                "currency": "USD"
              },
              "regular_price": {
                "value": 19
              }
            }
          }
        }
      ]
    }
  }
}

Response without headers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
  "data": {
    "products": {
      "items": [
        {
          "name": "Go-Get'r Pushup Grips",
          "sku": "24-UG05",
          "price_range": {
            "minimum_price": {
              "discount": {
                "percent_off": 0,
                "amount_off": 0
              },
              "final_price": {
                "value": 19,
                "currency": "USD"
              },
              "regular_price": {
                "value": 19
              }
            }
          }
        }
      ]
    }
  }
}

Staging categoryList query

In this example campaign, the End of Year Sale subcategory and a catalog price rule are disabled when the campaign is not in effect. When you specify valid headers, the categoryListquery returns full details about the custom category. Otherwise, the query returns an empty array.

Headers:

1
2
Authorization: Bearer hoyz7k697ubv5hcpq92yrtx39i7x10um
Preview-Version: 1576389600

Request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
  categoryList(filters: {ids: {eq: "43"}}) {
    name
    level
    products(
      sort: {
        price: ASC
      }
      pageSize: 20
      currentPage: 1
    ) {
      total_count
      items {
        name
        sku
        price_range {
          minimum_price {
            discount {
              amount_off
              percent_off
            }
            final_price {
              value
            }
            regular_price {
              value
            }
          }
        }
      }
    }
  }
}

Response with headers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
{
  "data": {
    "categoryList": [
      {
        "name": "End of Year Sale",
        "level": 3,
        "products": {
          "total_count": 4,
          "items": [
            {
              "name": "Solo Power Circuit",
              "sku": "240-LV07",
              "price_range": {
                "minimum_price": {
                  "discount": {
                    "amount_off": 3.5,
                    "percent_off": 25
                  },
                  "final_price": {
                    "value": 10.5
                  },
                  "regular_price": {
                    "value": 14
                  }
                }
              }
            },
            {
              "name": "Quest Lumaflex&trade; Band",
              "sku": "24-UG01",
              "price_range": {
                "minimum_price": {
                  "discount": {
                    "amount_off": 4.75,
                    "percent_off": 25
                  },
                  "final_price": {
                    "value": 14.25
                  },
                  "regular_price": {
                    "value": 19
                  }
                }
              }
            },
            {
              "name": "Go-Get'r Pushup Grips",
              "sku": "24-UG05",
              "price_range": {
                "minimum_price": {
                  "discount": {
                    "amount_off": 4.75,
                    "percent_off": 25
                  },
                  "final_price": {
                    "value": 14.25
                  },
                  "regular_price": {
                    "value": 19
                  }
                }
              }
            },
            {
              "name": "Gabrielle Micro Sleeve Top",
              "sku": "WS02",
              "price_range": {
                "minimum_price": {
                  "discount": {
                    "amount_off": 7.00,
                    "percent_off": 25
                  },
                  "final_price": {
                    "value": 21
                  },
                  "regular_price": {
                    "value": 28
                  }
                }
              }
            }
          ]
        }
      }
    ]
  }
}

Response without headers:

1
2
3
4
5
{
  "data": {
    "categoryList": []
  }
}

Introspection queries

Introspection queries allow you to return information about the schema. For example, you might want a list of Magento GraphQL queries or details about a specific data type. The GraphQL specification determines the structure of introspection queries. See Introspection for more information.

A Magento introspection query returns the same result whether or not you assign it an operation name, such as IntrospectionQuery.

Disable introspection querying

Introspection querying is enabled by default. To disable it in production mode to improve security, add the following to your app/etc/env.php file.

1
2
3
'graphql' => [
    'disable_introspection' => true,
]

Example introspection queries

Return a list of Magento queries

The following query returns a list of Magento queries.

Request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
query IntrospectionQuery {
  __schema {
    queryType {
      fields {
        name
        description
        type{
         name
         kind
        }
      }
    }
  }
}

Return a list of Magento mutations

The following query returns a list of Magento mutations.

Request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
query IntrospectionQuery {
  __schema {
    mutationType {
      fields {
        name
        description
        type{
         name
         kind
        }
      }
    }
  }
}

Get details about a data type

The following introspection query returns details about the ProductAttributeFilterInput data type.

Request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
query IntrospectionQuery {
  __type(name: "ProductAttributeFilterInput") {
    name
    kind
    description
    inputFields {
      name
      description
      defaultValue
    }
    fields {
      name
      args {
        name
        description
        type {
          kind
          name
        }
      }
      type {
        kind
        name
      }
    }
  }
}

Response:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
  "data": {
    "__type": {
      "name": "ProductAttributeFilterInput",
      "kind": "INPUT_OBJECT",
      "description": "ProductAttributeFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.",
      "inputFields": [
        {
          "name": "category_id",
          "description": "Filter product by category id",
          "defaultValue": null
        },
        {
          "name": "description",
          "description": "Attribute label: Description",
          "defaultValue": null
        },
        {
          "name": "name",
          "description": "Attribute label: Product Name",
          "defaultValue": null
        },
        {
          "name": "price",
          "description": "Attribute label: Price",
          "defaultValue": null
        },
        {
          "name": "short_description",
          "description": "Attribute label: Short Description",
          "defaultValue": null
        },
        {
          "name": "sku",
          "description": "Attribute label: SKU",
          "defaultValue": null
        },
        {
          "name": "url_key",
          "description": "The part of the URL that identifies the product",
          "defaultValue": null
        }
      ],
      "fields": null
    }
  }
}