Vue Storefront is now Alokai! Learn More
Custom Queries

Custom Queries

Introduction

Sometimes you need to fetch data from commercetools that the default methods don't cover. You have two ways to do this:

  • Add a custom API method (recommended) - write your own middleware method with a GraphQL query. You get full editor support: syntax highlighting, schema-aware autocompletion, and type safety.
  • Use the customQuery feature - pass an inline GraphQL query string to an existing method to extend its default query.

This guide covers both, and shows how to set up your editor so writing GraphQL feels like writing GraphQL - not editing a plain string.

For most cases, a custom API method is the better developer experience. Because the query lives in a regular TypeScript file, you can tag it with gql (from the graphql-tag package, already available in the middleware) and your editor treats it as a real GraphQL document.

apps/storefront-middleware/api/custom-methods/custom.ts
import { type CommercetoolsIntegrationContext } from '@vsf-enterprise/commercetools-api';
import gql from 'graphql-tag';

// The `/* GraphQL */` comment + the `gql` tag give you syntax highlighting and,
// with a GraphQL editor extension installed, autocompletion against the commercetools schema.
export const activeCartQuery = /* GraphQL */ gql`
  query activeCart {
    me {
      activeCart {
        id
        version
      }
    }
  }
`;

interface ActiveCartResponse {
  me: {
    activeCart: {
      id: string;
      version: number;
    } | null;
  };
}

export async function getActiveCart(
  context: CommercetoolsIntegrationContext,
): Promise<ActiveCartResponse> {
  const { data } = await context.client.query<ActiveCartResponse>({
    context: { req: context.req, res: context.res },
    fetchPolicy: 'no-cache',
    query: activeCartQuery,
  });

  return data;
}

The method is automatically exposed on the SDK with full type inference, so the frontend gets a typed response for free.

Where to look next

The generated middleware already ships a boilerplate exampleCustomMethod in api/custom-methods/custom.ts that follows exactly this pattern - use it as a starting point. For the full walkthrough, see Creating New API Methods, and browse the queries the default methods already run in commercetools API GraphQL Queries.

Custom queries

If you only need to tweak the query of an existing method, the customQuery feature lets you do that without writing a new method.

To use custom queries, add them to the customQueries object in the integration config file located at apps/storefront-middleware/integrations/commercetools/config.ts.

The #graphql comment at the start of the template string is what gives you syntax highlighting here - the query is passed to the method as a plain string, so don't wrap it with the gql tag.

In the example below, we add a custom query called get-me-basic-custom-query:

apps/storefront-middleware/integrations/commercetools/config.ts
export const config = {
  // ...
  customQueries: {
    'get-me-basic-custom-query': ({ query, variables, metadata }) => ({
      variables,
      query: `#graphql
        query getBasicProfile {
          me {
            activeCart {
              ${metadata}
            }
          }
        }
      `,
    }),
  },
};

Using custom queries

To use a custom query, pass the custom query descriptor as the second argument to the method. The descriptor contains the custom query name and its metadata.

In our example, we're fetching a basic user profile and using the custom GraphQL query from the previous example.

Overwriting the default response interface

Notice how we are using the type parameter to overwrite the default response interface.

type CustomGetMeResponse = {
  me: {
    activeCart: {
      id: string;
      version: string;
    };
  };
};

const { me } = await sdk.ct.getMe<CustomGetMeResponse>(undefined, {
  getBasicProfile: 'get-me-basic-custom-query',
  metadata: 'id,version',
});

Let's try with another example:

Creating a custom GraphQL query for fetching a full user profile in apps/storefront-middleware/integrations/commercetools/config.ts.

apps/storefront-middleware/integrations/commercetools/config.ts
export const config = {
  // ...
  customQueries: {
    'get-me-full-custom-query': ({ query, variables, metadata }) => ({
      variables,
      query: `#graphql
        query getFullProfile {
          me {
            activeCart {
              ${metadata.activeCart}
            }
            customer {
              ${metadata.customer}
            }
          }
        }
      `,
    }),
  },
};

Fetching the full user profile and using the customQuery parameter to leverage the custom GraphQL query from the previous example.

Overwriting the default response interface

Notice how we are using the type parameter to overwrite the default response interface.

type CustomGetMeResponse = {
  me: {
    activeCart: {
      id: string;
    };
    customer: {
      id: string;
    };
  };
};

const { me } = await sdk.ct.getMe<CustomGetMeResponse>({ customer: true }, {
  getFullProfile: 'get-me-full-custom-query',
  metadata: { activeCart: 'id', customer: 'id' },
});

By doing that, we've just fetched the full user profile using a custom GraphQL query. The me object contains the activeCart and customer objects.

Custom queries for other methods

To check out our examples, how to add a custom query to other methods, check out the API Reference: Functions. Each method has at least one example of how to use a custom query.

Editor setup: syntax highlighting and autocompletion

Out of the box, a GraphQL query embedded in a TypeScript file is just a string - no colors, no validation, no autocompletion. Two small things fix that.

1. Mark the query as GraphQL

Editors recognize GraphQL inside a template literal in two ways:

  • a gql tagged template (or a /* GraphQL */ comment before the literal) - use this in custom API methods,
  • a leading #graphql comment inside the string - use this for customQuery strings, which can't be tagged.

Both are shown in the examples above.

2. Install a GraphQL editor extension

Highlighting (and, with a schema, autocompletion) is provided by an editor extension, not by Alokai. For VS Code and Cursor, install the official GraphQL extension by The GraphQL Foundation.

To unlock schema-aware autocompletion and validation, point the extension at your commercetools schema with a graphql.config file at your project root:

graphql.config.yaml
schema:
  - 'https://api.${COMMERCETOOLS_REGION}.commercetools.com/${COMMERCETOOLS_PROJECT_KEY}/graphql':
      headers:
        Authorization: 'Bearer ${COMMERCETOOLS_ACCESS_TOKEN}'
documents:
  - 'apps/storefront-middleware/**/*.ts'

The commercetools GraphQL API requires authentication, so introspection needs a valid OAuth access token in the Authorization header. Without a reachable, authenticated schema you still get syntax highlighting - you just won't get suggestions or validation.