Vue Storefront is now Alokai! Learn More
Custom Queries in Unified Data Layer

Custom Queries in Unified Data Layer

When working with integrations that use GraphQL APIs, you might encounter scenarios where you need to fetch additional or custom fields that are not included in the default queries. To locate the methods and queries being used, refer to the documentation for your specific integration. For example, see the Commercetools API documentation on GraphQL queries. This guide provides step-by-step instructions on how to configure custom queries within the Unified Data Layer (UDL) of your integration.

Introduction

In some cases, the methods provided by your integration may need to be adjusted to accommodate specific requirements, such as fetching additional fields or altering input parameters. This is a common scenario when dealing with customized data needs. This guide will help you add a custom query to your integration and use it within your integration.

Custom Queries vs. Normalizers

If the default query already contains the data you are looking for, consider using normalizers to transform the data as needed. Custom queries should be used primarily for fetching additional fields that are not included in the default queries.

Configuring Custom Queries

Custom queries are defined in the integrations/<integration>/config.ts file of your integration. Each custom query function provides the flexibility to modify the default query and variables. Currently, this functionality is available for the Commercetools and Magento 2 integrations.

Understanding Custom Query Functions

Custom query functions receive the following arguments:

  • query: the default GraphQL query
  • variables: the default variables passed to the query
  • metadata: additional parameters that provide context or extra data for the custom query. The metadata variable is of type unknown and requires either a type definition or type casting to function correctly in TypeScript

The function must return an object with query and variables keys. Within the function body, you can modify or replace these parameters as needed.

Example structure:

// integrations/<integration>/config.ts

export const config = {
  ct: {
    location: '@vue-storefront/commercetools-api/server',
    configuration: {
      /* ... existing configuration ... */
    },
    customQueries: {
      'custom-query-name': ({ query, variables, metadata }) => {
        // Modify query and variables as needed
        return { query, variables };
      }
    }
  }
}

Keeping the Configuration Tidy

To maintain a clean and manageable configuration, it's recommended to extract custom queries into separate files or folders. This prevents the config.ts file from becoming cluttered.

Example

Create a separate file for custom queries:

// <integration>/customQueries/myCustomQueries.ts

export const myCustomQueries = {
  'my-custom-products-query': ({ variables, metadata }) => ({
    // Modify variables or use metadata as needed
    const typedMetadata = metadata as { size?: number };
    variables.size = typedMetadata.size || 10;

    query: `
      query products($where: String, $locale: String, $size: Int) {
        products(where: $where, locale: $locale, size: $size) {
          results {
            id
            name
            // Fields...
          }
        }
      }
    `,
    variables,
  }),
  // ...other custom queries
};

Import it in config.ts:

// <integration>/config.ts

import { myCustomQueries } from './customQueries/myCustomQueries';

export const config = {
  integrations: {
    ct: {
      location: '@vue-storefront/commercetools-api/server',
      configuration: {
        /* ... existing configuration ... */
      },
      customQueries: {
        ...myCustomQueries,
        // ...other custom queries
      },
    },
  },
};

Creating new custom queries

Step 1: Create a Custom Query

Define a new custom query with a unique name and adjust the parameters and fields as required. Using the example structure from the Keeping the Configuration Tidy section.

Step 2: Use the custom query in a method

Create a new method in your extension that uses the custom query. Extending the Middleware

// apps/storefront-middleware/api/yourExtension/customGetProducts.ts

export async function customGetProducts(context, args) {
  const customQuery = {
    products: 'my-custom-products-query',
    variables: {
      locale: args.locale || 'en',
      // Include other variables as needed
    },
    metadata: {
      size: 10, // Hardcoded 'size' in metadata
    },
  };

  /*
   * `context.api.getProducts` is a method that fetches product data from the API.
   * It takes two arguments:
   * 1. An object containing search parameters (e.g., `where`, `skus`).
   * 2. A custom query object that specifies the GraphQL query to be used.
   */

  const response = await context.api.getProducts(
          buildProductSearchParams(args),
          customQuery
  );

  const products = response.products.results;

  if (!products || products.length === 0) {
    return [];
  }

  return products;
}

function buildProductSearchParams(args) {
  return {
    where: args.where,
    // Include other parameters as needed
  };
}

Note:

  • If the query specifies additional fields not contained in the typedef, you need to extend the existing type definitions to include these new fields
  • You don't need to override the existing UDL method; you can create a new method that uses your custom query

Warnings and Best Practices

  • Testing: thoroughly test your custom queries and methods to confirm they work as intended and do not introduce regressions
  • Documentation: keep your custom queries and extensions well-documented to facilitate maintenance and updates
  • Avoid Overcomplicating: Ooerriding too many default behaviors can make your integration harder to maintain