All Tutorials

Migrate your app from REST to GraphQL

All Tutorials

Migrate your app from REST to GraphQL

Migrate your app from REST to GraphQL

GraphQL is a query language and a runtime system. While REST offers multiple endpoints that return fixed data structures, GraphQL only exposes a single endpoint and allows you to navigate a graph of related data or fetch resources directly by their ID.

This tutorial covers the following topics:

Requirements

Retrieve GraphQL object IDs

To migrate to GraphQL, you need to query the GraphQL object IDs that correspond to REST resource IDs. You can retrieve GraphQL IDs for both the GraphQL Admin API and the GraphQL Storefront API.

GraphQL Admin API IDs

To help with migrating from the REST Admin API to the GraphQL Admin API, all REST responses include the admin_graphql_api_id property. You can use the ID value in this property to query the object directly using the GraphQL Admin API.

The following example retrieves a product variant in REST, and then uses the admin_graphql_api_id property to query the product variant in GraphQL.

REST request

GET /admin/api/2021-04/products/1321540747320/variants/12195007594552.json

View response

JSON response

{
    "variant": {
        "id": 12195007594552,
        "product_id": 1321540747320,
        "title": "Default Title",
        "...": "...",
        "admin_graphql_api_id": "gid://shopify/ProductVariant/12195007594552"
    }
}

GraphQL query

POST /admin/api/2021-04/graphql.json

{
  productVariant (id: "gid://shopify/ProductVariant/12195007594552") {
    id
    title
  }
}

View response

JSON response

{
    "data": {
        "productVariant": {
            "id": "gid://shopify/ProductVariant/12195007594552",
            "title": "Default Title"
        }
    },
}

Anatomy of a GraphQL ID

Always treat the admin_graphql_api_id string as an opaque ID.

GraphQL ID generation is implementation dependent and doesn't follow any convention other than being a URI. There's no guarantee that GraphQL IDs will follow a structure (gid -> shopify -> resource -> rest_id) that's similar to the previous example, so you shouldn't generate IDs programatically.

The following example shows how the admin_graphql_api_id property doesn't always follow an expected structure.

REST request

GET /admin/api/2021-04/inventory_levels.json?inventory_item_ids=12261979488312

View response

JSON response

{
    "inventory_levels": [
        {
            "inventory_item_id": 12261979488312,
            "location_id": 6884556842,
            "available": 5,
            "updated_at": "2018-05-17T12:58:30-04:00",
            "admin_graphql_api_id": "gid://shopify/InventoryLevel/6485147690?inventory_item_id=12261979488312"
        },
        {
            "inventory_item_id": 12261979488312,
            "location_id": 13968834616,
            "available": 7,
            "updated_at": "2018-05-17T12:58:35-04:00",
            "admin_graphql_api_id": "gid://shopify/InventoryLevel/13570506808?inventory_item_id=12261979488312"
        },
        {
            "inventory_item_id": 12261979488312,
            "location_id": 13968867384,
            "available": 9,
            "updated_at": "2018-05-17T12:58:35-04:00",
            "admin_graphql_api_id": "gid://shopify/InventoryLevel/13570539576?inventory_item_id=12261979488312"
        }
    ]
}

GraphQL Storefront API IDs

The Storefront API is also queried using GraphQL, and it uses its own separate IDs. The GraphQL Admin API provides the storefrontId field, which you can use to get an object's Storefront API ID.

The following example shows how to request the storefrontId field on a product.

GraphQL query

POST /admin/api/2021-04/graphql.json

{
  product(id:"gid://shopify/Product/1324932956216") {
    id
    title
    storefrontId
  }
}

View response

JSON response

{
  "data": {
    "product": {
      "id": "gid://shopify/Product/1324932956216",
      "title": "GQL Lego Connector",
      "storefrontId": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzEzMjQ5MzI5NTYyMTY="
    }
  },
}

Combine multiple REST requests into a single GraphQL query

In GraphQL, you can use connections to get information about related objects with a single request. For example, for an Order, you might want to know the total price set, the customer's name, metafields, and the title of other variants belonging to the product in the order.

Using REST, you need to make a request to the following endpoints and filter out unnecessary data:

  • /admin/api/2021-04/orders/{order_id}.json
  • /admin/api/2021-04/products/{product_id}/variants.json
  • /admin/api/2021-04/customers/{customer_id}/metafields.json

Using GraphQL, you can make a single request using connections to get your desired data:

GraphQL query

POST /admin/api/2021-04/graphql.json

{
  order(id:"gid://shopify/Order/1938703319062") {
    id
    totalPriceSet {
      presentmentMoney {
        amount
        currencyCode
      }
    }
    customer {
      displayName
      metafields (first:10) {
        edges {
          node {
            namespace
            key
            value
          }
        }
      }
    }
    lineItems (first:10) {
      edges {
        node {
          variant {
            product {
              variants(first:10) {
                edges {
                  node {
                    title
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

View response

JSON response

{
  "data": {
    "order": {
      "id": "gid://shopify/Order/1938703319062",
      "totalPriceSet": {
        "presentmentMoney": {
          "amount": "7.99",
          "currencyCode": "CAD"
        }
      },
      "customer": {
        "displayName": "John Smith",
        "metafields": {
          "edges": [
            {
              "node": {
                "namespace": "instructions",
                "key": "wash",
                "value": "cold wash"
              }
            }
          ]
        }
      },
      "lineItems": {
        "edges": [
          {
            "node": {
              "variant": {
                "product": {
                  "variants": {
                    "edges": [
                      {
                        "node": {
                          "title": "Brown"
                        }
                      },
                      {
                        "node": {
                          "title": "Yellow"
                        }
                      },
                      {
                        "node": {
                          "title": "Red"
                        }
                      },
                      {
                        "node": {
                          "title": "Purple"
                        }
                      },
                      {
                        "node": {
                          "title": "Blue"
                        }
                      }
                    ]
                  }
                }
              }
            }
          }
        ]
      }
    }
  },
}

Switch from page-based to cursor-based pagination

In REST, you paginate results using query parameters. For example, using the limit parameter, you can split the total entries into manageable groups and paginate through them with page:

/admin/api/2021-04/products.json?limit=1&page=2

In GraphQL, you can apply similar concepts with cursor-based pagination. When using connections, you need to provide the first or last argument, which specifies the number of items you want returned. This is equivalent to the limit parameter in REST.

Requesting cursor and pageInfo fields

Requesting the cursor field in GraphQL lets you get a reference to the position of a node within the connections. You can use that reference to obtain the next set of items. The cursor field in GraphQL is equivalent to page in REST, but with more precision, robustness, and flexibility.

You can also request the pageInfo field in GraphQL to determine if there are any more pages to request. The nested fields hasNextPage and hasPreviousPage are boolean fields which let you know if you can paginate forwards or backwards. If both are false, then there are no more results or pages.

Tie it all together

The following example query explores the connection between a shop and its orders and shows how to retrieve specific fields. The query requests the first three elements on the orders connection. On each of the orders, the id, name, and email fields are requested. The cursor and pageInfo fields are also included in the query to handle pagination.

GraphQL query

POST /admin/api/2021-04/graphql.json

{
  orders(first: 3) {
    edges {
      cursor
      node {
        id
        name
        email
      }
    }
    pageInfo {
      hasNextPage
    }
  }
}

View response

JSON response

{
  "data": {
    "orders": {
      "edges": [
        {
          "cursor": "eyJsYXN0X2lkIjo0MTA0Nzk0OTMxNzYsImxhc3RfdmFsdWUiOiIyMDE3LTA0LTMwIDA0OjQ2OjA3In0=",
          "node": {
            "id": "gid://shopify/Order/410479493176",
            "name": "#1592",
            "email": "Maya.Schinner@developer-tools.shopifyapps.com"
          }
        },
        {
          "cursor": "eyJsYXN0X2lkIjo0MTA0Nzg1NDI5MDQsImxhc3RfdmFsdWUiOiIyMDE3LTA1LTAyIDA4OjU5OjM4In0=",
          "node": {
            "id": "gid://shopify/Order/410478542904",
            "name": "#1564",
            "email": "Verda.Fritsch@developer-tools.shopifyapps.com"
          }
        },
        {
          "cursor": "eyJsYXN0X2lkIjo0MTA0ODA5Njc3MzYsImxhc3RfdmFsdWUiOiIyMDE3LTA1LTAyIDE1OjQyOjQ3In0=",
          "node": {
            "id": "gid://shopify/Order/410480967736",
            "name": "#1633",
            "email": "Gino.Davis@developer-tools.shopifyapps.com"
          }
          }],
          "pageInfo": {
            "hasNextPage": true
          }
        }
      }
    }
  }
}

The query returns the data for the first three orders. To get the next three orders, you need to add the cursor value to the connection arguments.

The data returned indicates that each node has a cursor. Using the last cursor that was returned allows you to continue from that point. You can continue paginating using the same method until hasNextPage returns false.

GraphQL query

POST /admin/api/2021-04/graphql.json

{
  orders(first: 3, after: "eyJsYXN0X2lkIjo0MTA0ODA5Njc3MzYsImxhc3RfdmFsdWUiOiIyMDE3LTA1LTAyIDE1OjQyOjQ3In0=") {
    edges {
      cursor
      node {
        id
        name
        email
      }
    }
    pageInfo {
      hasNextPage
    }
  }
}

View response

JSON response

{
  "data": {
    "orders": {
      "edges": [
        {
          "cursor": "eyJsYXN0X2lkIjo0MTA0ODU1ODgwMjQsImxhc3RfdmFsdWUiOiIyMDE3LTA1LTA0IDAxOjI3OjAxIn0=",
          "node": {
            "id": "gid://shopify/Order/410485588024",
            "name": "#1768",
            "email": "Gino.Davis@developer-tools.shopifyapps.com"
          }
        },
        {
          "cursor": "eyJsYXN0X2lkIjo0MTA0ODY3Njc2NzIsImxhc3RfdmFsdWUiOiIyMDE3LTA1LTA0IDEzOjQ1OjM2In0=",
          "node": {
            "id": "gid://shopify/Order/410486767672",
            "name": "#1799",
            "email": "Chanel.Auer@developer-tools.shopifyapps.com"
          }
        },
        {
          "cursor": "eyJsYXN0X2lkIjo0MTA0Nzg4Mzc4MTYsImxhc3RfdmFsdWUiOiIyMDE3LTA1LTA0IDIwOjU1OjQ5In0=",
          "node": {
            "id": "gid://shopify/Order/410478837816",
            "name": "#1573",
            "email": "Harmon.Bernhard@developer-tools.shopifyapps.com"
          }
        }],
      "pageInfo": {
        "hasNextPage": true
      }
    }
  }
}

Next steps

  • Learn about the benefits of using GraphQL APIs over REST APIs.
  • Get familiar with making GraphQL queries and modifying data using mutations.
  • Explore resources to learn more about GraphQL and how to use it in your apps.