Vue Storefront is now Alokai! Learn More
Data Federation

Data Federation

Optimizing server requests through data federation is a common technique used within composable architectures that improves performance and reduces coupling between frotnend and backend API's. This guide shows how to use the getApiClient method to retrieve and interact with integrations within the context of another integration to mix them together in one request.

Why?

  • Minimized Network Traffic: Fewer server calls lead to reduced latency and enhanced responsiveness.
  • Simplified Frontend Architecture: By grouping related server requests, the frontend logic becomes less complex and less coupled.
  • Data Unification: You can retrieve data from multiple sources and unify it in one response under common data model unrelated to the details of underlying API's.

How?

Uisng getApiClient Method to access different API client

If you want to retrieve a loaded integration within the context of another, you can use the getApiClient method. This method serves as a bridge between various integrations, ensuring seamless data flow and interaction.

Usage:

const sapcc = await context.getApiClient("sapcc");

The getApiClient method takes a single argument, which is the key of the api client you wish to retrieve. This is the key you would define in the middleware.config.js file for the integration you wish to retrieve. The key is essentially an identifier for the integration.

Here's a basic example of what this might look like:

middleware.config.ts
export const integrations = {
  sapcc: {
    location: "@vsf-enterprise/sapcc-api/server",
    configuration: {
      // ...
    },
    extensions: (extensions) => [
      ...extensions,
      {
        name: "sapcc-contentful-extension",
        extendApiMethods: {
          getPDP: async (context, params: { id: string }) => {
            const sapccApi = context.api; // You can access integration methods directly
            const contentful = await context.getApiClient("contentful"); // You can access other integrations using getApiClient

            const [product, content] = Promise.all(
              sapccApi.getProduct({ id: params.id }),
              contentful.api.getEntries({
                content_type: "product",
                "fields.sku": params.id,
              })
            );

            return {
              product,
              content,
            };
          },
        },
      },
    ],
  },
  contentful: {
    location: "@vsf-enterprise/contentful-api/server",
    configuration: {
      // ...
    },
  },
};
  1. Extend the integration with new endpoint: Create a new endpoint that will act as the main entry point for the grouped requests.
  2. Group Server Requests: Within this endpoint, utilize the getApiClient method to retrieve and interact with the required integrations.
  3. Aggregate Data: Once data from all required integrations is retrieved, aggregate and format it as needed.
  4. Return Unified Response: Send a consolidated response back to the frontend.

Using federation methods in the frontend

To call the federation endpoint, you can follow the Using extension methods in the frontend guide.

Real-World Examples

The examples provided demonstrate practical uses of data federation:

Example 1: Fetching Custom Product Properties from Legacy Systems

This use case involves calling the commerce backend to fetch specific product data. Additionally, a separate call is made to a legacy custom system of the customer, to retrieve a custom product property (e.g., stock of the product). This data is used, for example, to display stock information on the product page.

Example implementation might look like this:

middleware.config.ts
export const integrations = {
  sapcc: {
    // ...
    extensions: (extensions) => [
      ...extensions,
      {
        name: "federation-extension",
        extendApiMethods: {
          enrichedSearch: async (context, params: { productId: string }) => {
            const sapccApi = context.api;
            const legacyCustomSystem = await context.getApiClient("legacyCustomSystem");

            const [prouctStock, product] = await Promise.all([
              legacyCustomSystem.api.getProductStock({
                productId: params.productId,
              }),
              sapccApi.getProduct({
                { id: params.productId },
              }),
            ]);

            return {
              ...product,
              stock: productStock,
            };
          },
        },
      },
    ],
  },
  legacyCustomSystem: {
    // ...
  },
};

TypeScript Support

getApiClient helper returns the ApiClient interface, which is a generic type. It takes three type arguments:

  • Api - the type of the API object returned by the integration,
  • Config - the type of the configuration object passed to the integration,
  • Client - the type of the HTTP client object returned by the integration.

Usually, an integration exports those types. For example, the sapcc integration exports the following types:

import {
  Endpoints,
  MiddlewareConfig,
  AxiosInstance,
} from "@vsf-enterprise/sapcc-api";

Type of endpoints

Sometimes, the Endpoints type is not exported by the integration. If that's the case, you can import the {xyz}IntegrationContext type from the integration package.

For example, the sapcc integration exports the SapccIntegrationContext type, which contains the following:

import { SapccIntegrationContext } from "@vsf-enterprise/sapcc-api";

SapccIntegrationContext.api // the endpoints type
SapccIntegrationContext.config // the configuration object type
SapccIntegrationContext.client // the HTTP client object type

This applies to all integrations.