Add GraphQL Edge Caching to commercetools

Add GraphQL Edge Caching to commercetools

commercetools is a cloud-native, headless commerce platform that provides APIs for building custom e-commerce solutions. It separates the frontend from the backend, allowing for tailored shopping experiences across multiple channels like web, mobile, and IoT. With features like product information management, order processing, and customer management, it offers a flexible and scalable solution for businesses of all sizes.

Together with Grafbase we can extend and join other APIs so data can be fetched from multiple sources in one GraphQL request. In this guide, we will focus on adding commercetools as a data source and enabling GraphQL Edge Caching to improve commerce experiences as well as:

  1. Speed — Get even faster responses and lessen server load with Grafbase Edge Caching.
  2. Flexibility — Combine data from multiple APIs effortlessly using Grafbase Edge Gateway.
  3. Savings — Stay within your API limits and save money.
  4. Insights — Monitor your data in real-time with Grafbase Analytics.

You should already have a commercetools project setup, and access to the Merchant Center to continue.

Begin by executing the following command inside a new or existing project's directory:

npx grafbase init --template graphql-commercetools

This command will generate a new folder grafbase in the root of your project.

Next, open the file grafbase.config.ts and make any adjustments.

By default, Grafbase will:

  • Add commercetools as a data source
  • Cache all queries for 60 seconds
  • Enable public access to the Grafbase Edge Gateway
  • Set the Authorization header for introspection requests
  • Forward Authorization header to commercetools for API requests
import { config, connector, graph } from '@grafbase/sdk'

const g = graph.Standalone()

const commercetools = connector.GraphQL('commercetools', {
  url: g.env('COMMERCETOOLS_API_URL'),
  headers: headers => {
    headers.set('Authorization', { forward: 'Authorization' })
    headers.introspection(
      'Authorization',
      `Bearer ${g.env('COMMERCETOOLS_API_TOKEN')}`,
    )
  },
})

// Disabling namespace may cause conficts with other connectors
g.datasource(commercetools, { namespace: false })

export default config({
  graph: g,
  cache: {
    rules: [
      {
        types: ['Query'],
        maxAge: 60,
      },
    ],
  },
  auth: {
    rules: rules => {
      rules.public()
    },
  },
})

If you plan to add other data sources, you should enable namespaces to prevent schema conflicts.

The configuration above uses the environment variables COMMERCETOOLS_API_URL, and COMMERCETOOLS_API_TOKEN for introspection requests Make sure to create the file .env with the correct values:

# COMMERCETOOLS_API_URL=
# COMMERCETOOLS_API_TOKEN=

To generate an COMMERCETOOLS_API_TOKEN you will want to create an API Client from the Developer Settings:

Create API Client

You can then use this token to generate an access token to pass with API requests. Here's what it looks like to create a read only access token using cURL:

curl -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&scope=view_stores:[PROJECT_NAME] view_key_value_documents:[PROJECT_NAME] view_categories:[PROJECT_NAME] view_associate_roles:[PROJECT_NAME] view_business_units:[PROJECT_NAME] view_orders:[PROJECT_NAME] view_products:[PROJECT_NAME] view_types:[PROJECT_NAME] view_shopping_lists:[PROJECT_NAME] view_quote_requests:[PROJECT_NAME] view_staged_quotes:[PROJECT_NAME] view_connectors_deployments:[PROJECT_NAME] view_project_settings:[PROJECT_NAME] view_standalone_prices:[PROJECT_NAME] view_discount_codes:[PROJECT_NAME] view_messages:[PROJECT_NAME] view_import_containers:[PROJECT_NAME] view_shipping_methods:[PROJECT_NAME] view_product_selections:[PROJECT_NAME] view_tax_categories:[PROJECT_NAME] view_connectors:[PROJECT_NAME] view_attribute_groups:[PROJECT_NAME] view_payments:[PROJECT_NAME] view_order_edits:[PROJECT_NAME] view_audit_log:[PROJECT_NAME] view_cart_discounts:[PROJECT_NAME] view_quotes:[PROJECT_NAME] view_customer_groups:[PROJECT_NAME] view_published_products:[PROJECT_NAME] view_customers:[PROJECT_NAME] view_states:[PROJECT_NAME]" \
  -u "[CLIENT_ID]:[CLIENT_SECRET]" \
  https://auth.[YOUR_REGION].gcp.commercetools.com/oauth/token

You should create this as you normally do and pass it with requests to Grafbase. Since API tokens expire, you might not want to store this as an environment variable.

Finally, run the Grafbase development server by using the command below:

npx grafbase dev

You now have a GraphQL API running locally that acts as a proxy to commercetools! 🎉

You can execute any GraphQL query or mutation you normally would with commercetools using the new endpoint (locally): http://127.0.0.1:4000/graphql.

Grafbase Pathfinder can be found at http://127.0.0.1:4000 where you can explore the Grafbase Edge Gateway API and schema.

💡 Make sure to commit the grafbase folder with the rest of your application.

You can and should use the Grafbase CLI when building locally (or in a branch) to proxy your commercetools store but you will need to deploy to Grafbase to take advantage of GraphQL Edge Caching.

Follow these steps to deploy to production:

  • Signup for a Grafbase account
  • Create a new project
  • Connect and deploy your application where the grafbase was added
  • Make sure to add your COMMERCETOOLS_API_URL and COMMERCETOOLS_API_TOKEN when deploying, unless you made it optional
  • Update your host (Netlify, Vercel, Fly, etc.) with the new GraphQL API endpoint that Grafbase supplied for your new project.

That's it!

Grafbase is programmed to autonomously deploy a fresh gateway each time it identifies a change to grafbase/grafbase.config.ts. Consequently, if you need to adjust any cache settings, including parameters like maxAge, staleWhileRevalidate, and mutationInvalidation, you're free to do so.

Grafbase will handle the rest of the process seamlessly. We'll explore extending the commercetools GraphQL API with custom fields in another post.

Get Started

Start building your backend of the future now.