December 12, 2022

Unify your e-commerce checkout with GraphQL

Shane Myrick

Shane Myrick

This post is a part of our “How to power modern retail apps with Apollo GraphOS” series. Also in this series:


17% of online shoppers abandon their carts due to long, complicated checkout experiences (Baymard Institute). GraphQL can help you elevate, modernize, and improve your checkout functionality faster. As a result, you can ensure shoppers are experiencing a frictionless checkout process across all your applications, so you can capitalize on every revenue opportunity. 

GraphQL provides a single endpoint that developers can query to get all of the information they need to render a view in a client app by connecting disparate backend data sources and standardizing functionality like authorization. In doing so, client teams can save time rewriting the same code across customer-facing apps and spend more time shipping product features, like enhanced checkout experiences.

Implementing a digital cart with GraphOS

Apollo GraphOS—the only end-to-end supergraph platform that unifies all cloud data and services into a single, connected GraphQL schema—can provide a single platform with all the capabilities you need to iterate on your checkout.

When designing checkout functionality, the complexity of implementing this experience tends to land outside a single service. For example, it may require calls to additional services to process credit cards, send invoice orders to warehouses, and create shipping labels. 

GraphOS can help your clients by giving them focused operations to perform, so each client team can focus on creating the best UX flow instead of independently writing duplicate logic to call the various services.

Below is a sample schema we created that helps shoppers to view a cart and the payments options they can use:

type Query {
  user: User
}

type User @key(fields: "id") {
  id: ID!

  """
  Saved payment methods that can be used to submit orders
  """
  paymentMethods: [PaymentMethod]

  """
  The user's active cart session. Once the cart items have been purchases, they transition to an Order
  """
  cart: Cart
}

"""
An user's saved cart session. Only one cart can be active at a time
"""
type Cart {
  """
  Items saved in the cart session
  """
  items: [Variant]

  """
  The current total of all the items in the cart, before taxes and shipping
  """
  subtotal: Float
}

"""
A saved payment option for an user
"""
type PaymentMethod {
  id: ID!
  name: String
  description: String
  type: PaymentType!
}

"""
A fix set of payment types that we accept
"""
enum PaymentType {
  CREDIT_CARD
  DEBIT_CARD
  BANK_ACCOUNT
}

Lucky for us, the cart is already set up for a few users in our example retail supergraph. If you look at the schema for the user query, the user ID is not supplied as a query variable. That’s by design—the user is pulled from a header. In a real production application, this would come from your auth provider and be extracted from a JWT or something similar. In our case, the user ID is pulled from the header x-user-id for this demo.

We have already created a few example operations that you can try, like fetching all the items in a cart or getting all the user’s payment methods.

With this data, we should be able to present the user with all of the items in their cart and create a checkout page, but we still need a way to perform our checkout flow actions.

Modifying our cart and checking out

With a few schema enhancements, we can start describing a basic checkout workflow with GraphQL mutations.

type Mutation {
  cart: CartMutaitons
}

type CartMutaitons {
  checkout(paymentMethodId: ID!): CheckoutResult
  addVariantToCart(variantId: ID!, quantity: Int = 1): ResultWithMessage
  removeVariantFromCart(variantId: ID!, quantity: Int = 1): ResultWithMessage
}

type ResultWithMessage {
  successful: Boolean
  message: String
}

type CheckoutResult {
  successful: Boolean
  orderID: ID
}

Before we check out, we need to allow users to set up their own cart, including adding and removing cart items. Our schema uses the concepts of Products and Variants, where a Product is a root type that describes the item and it has many Variants which are different sizes, colors, or price options. Since Variants are the items that are actually purchasable, they will be the ones included in our cart. You can try an example add-to-cart mutation to add a variant to the cart in Apollo Explorer.

Note that all mutations in the example supergraph can be run but the example server does not store or modify any state, so it just returns a mock response.

We have designed our mutations to inform the end user of the result, so instead of returning status codes we have a generic message field that the server can populate with whatever message it wants to show to users. The same idea can be applied when we remove a variant from the cart or when we go to checkout with all the items in the cart. With this message, we can display a banner if the mutation was successful or display a warning if it failed, but we don’t need to update every client to have them use the same logic or message string.

Get started with a retail supergraph today

Beyond unifying checkout experiences across client apps, the best way to see the possibilities of a supergraph is to try one out. You can explore a retail supergraph schema and run real queries against it here.

We also have additional posts in this series of retail best practices that dive into different elements of this schema to illustrate how Apollo GraphOS help power essential features of modern retail applications.

If you’d like to talk to an Apollo expert about how a supergraph can power your retail experience, please reach out to us.

Written by

Shane Myrick

Shane Myrick

Read more by Shane Myrick