Vue Storefront is now Alokai! Learn More
Creating New API Methods

Creating New API Methods

Learn how to create a new Unified Data Layer API methods

The following guide is intended for @vsf-enterprise/unfied-api-<integration> version 1.0.0 and above. Refer to the changelog (for example @vsf-enterprise/unified-api-sapcc) if you are using an older version.

When building your Storefront, you may need additional functionality beyond Unified Data Methods. To achieve this, you can add custom methods.

The following guide will show you how to create the Unified Data Layer API methods.

  • Adding API Methods
  • Using Unified Methods in custom extensions
  • Orchestrating Data with API Methods

Adding New API Methods

To implement a new API method, you have to:

  • On the Middleware side:
    • Create a new Middleware extension
    • Create a new API method
    • Register the new method in the extension
    • Register the extension in the integration configuration
  • On the Storefront side:
    • Add a new module to the SDK configuration
  1. Create a new Middleware extension in the /integrations/<integration>/extensions/myExtension.ts file.
/integrations/<integration>/extensions/myExtension.ts
import type { ApiClientExtension } from "@vue-storefront/middleware";

export const myExtension = {
  name: "myExtension",
  isNamespaced: true,
  extendApiMethods: {},
} satisfies ApiClientExtension;

And export the extension in the /integrations/<integration>/extensions/index.ts file.

/integrations/<integration>/extensions/index.ts
export * from "./unified";
export * from "./multistore";
export * from "./myExtension";  
  1. Create a new API method in the /api/myExtension directory.

First, define the arguments and response types in the /api/myExtension/types.ts file.

/api/myExtension/types.ts
export interface GetHomePageArgs {
  // your arguments
}

export interface GetHomePageResponse {
  // interface for the response
}

Then, implement an API method in the /api/myExtension/getHomepage.ts file.

SAPCC
import type { SapccIntegrationContext } from "@vsf-enterprise/sapcc-api";
import type { GetHomePageArgs, GetHomePageResponse } from "./types";

export async function getHomepage(
  context: SapccIntegrationContext,
  args: GetHomePageArgs
): Promise<GetHomePageResponse> {
  // your implementation
}

And export the method in the /api/myExtension/index.ts file.

/api/myExtension/index.ts
export * from "./getHomepage";

args should be an object

Under the hood, Alokai will transform requests from the SDK to inject the context object into your API methods. By making args an object, not only does ensure that your request will not break during transformation, but you can add new fields to the method in the future without breaking the existing implementation.

  1. Create a new Middleware extension in the apps/storefront-middleware/integrations/<integration>/extensions directory and register custom API method.
apps/storefront-middleware/integrations/<integration>/extensions/myExtension.ts
import type { ApiClientExtension } from "@vue-storefront/middleware";
import { getHomepage } from "../../../api/myExtension"; 
export const myExtension = {
  name: "myExtension",
  isNamespaced: true,
  extendApiMethods: {
    getHomepage,   },
} satisfies ApiClientExtension;

Naming conflicts

If the method you are adding has the same name as an existing method in the integration or other extensions, the new method will override the existing one. We recommend using a isNamespaced flag in the extension to avoid conflicts. If you will use the isNamespaced: true, then the extension will be available at /<integration>/[extensionName] path, for example /commerce/myExtension. Read more about extending the middleware.

Inline method

We recommend defining the method within the api/[extensionName]/ directory to keep the project structure clean and organized. However, you can also define the method directly in the extension file.

/integrations/<integration>/extensions/myExtension.ts
import type { ApiClientExtension } from "@vue-storefront/middleware";

export const myExtension = {
  name: "myExtension",
  isNamespaced: true,
  extendApiMethods: {
    getHomepage: async (context, args) => {
      // your implementation
    },
  },
} satisfies ApiClientExtension;
  1. Export the type of the endpoints, to use them later in the SDK configuration.
apps/storefront-middleware/integrations/integrations/<integration>/types.ts
import { WithoutContext } from "@vue-storefront/middleware";
import { unifiedApiExtension } from "./extensions";  import { unifiedApiExtension, myExtension } from "./extensions"; 
export type UnifiedApiExtension = typeof unifiedApiExtension;
export type UnifiedEndpoints = WithoutContext<UnifiedApiExtension["extendApiMethods"]>;

export type MyExtension = typeof myExtension; export type MyExtensionEndpoints = WithoutContext<MyExtension["extendApiMethods"]>; 

Reusing method types on the Storefront

If you want to reuse the types of the method arguments and response in the Storefront, you can export them from the types.ts file as well

apps/storefront-middleware/integrations/<integration>/types.ts
import { WithoutContext } from "@vue-storefront/middleware";
import { unifiedApiExtension, myExtension } from "./extensions";

export type UnifiedApiExtension = typeof unifiedApiExtension;
export type UnifiedEndpoints = WithoutContext<UnifiedApiExtension["extendApiMethods"]>;

export type MyExtension = typeof myExtension;
export type MyExtensionEndpoints = WithoutContext<MyExtension["extendApiMethods"]>;
export * from "../../api/myExtension/types"; 
  1. Register the extension in the integration config file.
apps/storefront-middleware/integrations/<integration>/config.ts
import { myExtension } from "./extensions"; 
export const config = {
  // ...
  extensions: (extensions: ApiClientExtension[]) => [
    ...extensions,
    unifiedApiExtension,
    ...(IS_MULTISTORE_ENABLED ? [multistoreExtension] : []),
    myExtension,   ],
} satisfies Integration<MiddlewareConfig>;
  1. Export MyExtensionEndpoints type from the apps/storefront-middleware/ app.
apps/storefront-middleware/types.ts

export type { MyExtensionEndpoints } from "./integrations/<integration>/types";  
  1. Finally, register a new SDK module with the MyExtensionEndpoints type under a custom namespace in the SDK configuration.
  • In Nuxt go to apps/storefront-unified-nuxt/sdk.config.ts file.
  • In Next.js go to apps/storefront-unified-nextjs/sdk/config.ts file.
Next.js
import type { UnifiedEndpoints } from 'storefront-middleware/types'; import type { UnifiedEndpoints, MyExtensionEndpoints } from 'storefront-middleware/types'; 
export const { getSdk } = createSdk(
  options,
  ({ buildModule, middlewareModule, config, getRequestHeaders }) => ({
    unified: buildModule(middlewareModule<UnifiedEndpoints>, {
      apiUrl: `${config.middlewareUrl}/commerce`,
      defaultRequestConfig: {
        headers: getRequestHeaders(),
      },
    }),
    myExtension: buildModule(middlewareModule<MyExtensionEndpoints>, {       apiUrl: `${config.middlewareUrl}/commerce/myExtension`,       defaultRequestConfig: {         headers: getRequestHeaders(),       },     }),     cms: buildModule(contentfulModule, {
      apiUrl: `${config.middlewareUrl}/cntf`,
    }),
  })
);

Now, thanks to the SDK synchronization, the getHomepage method will be available and typed under myExtension namespace when you use the SDK in your Storefront.

// Storefront project
const { data } = sdk.myExtension.getHomepage({
  /* args */
});

Using Unified Methods in Custom Extensions

When creating a custom extension, you can use the Unified Data Layer API methods to fetch data from your backend. This is useful when you want to extend the existing API methods with additional data or when you want to use the existing methods to fetch data from your backend.

For example, you can use the getProductDetails method to fetch product details from your backend and then extend the response with additional data.

SAPCC
import { methods } from "@vsf-enterprise/unified-api-sapcc";
import type { SapccIntegrationContext } from "@vsf-enterprise/sapcc-api";
import type { GetProductDetailsExtendedArgs, GetProductDetailsExtendedResponse } from "./types";

export async function getProductDetailsExtended(
  context: SapccIntegrationContext,
  args: GetProductDetailsExtendedArgs
): GetProductDetailsExtendedResponse {
  // fetch product details from your backend
  const response = await methods.getProductDetails(context, args);

  // use the response and add additional data
  return {
    ...response,
    data: "Additional data",
  };
}

Orchestrating Data

Data Orchestration allows you to consolidate multiple server requests into a single endpoint. For example, if you want to fetch data from your CMS, query your eCommerce backend, and return a single response containing all the information.

When creating/overriding an API method, you can query multiple services using the getApiClient method. This method will search your integrations defined in your Middleware Configuration, find one matching a specific key, and return that integration's API client.

For example, we can use Data Orchestration to add additional product information from our CMS when creating a custom getCmsPage method.

SAPCC
import type { SapccIntegrationContext } from "@vsf-enterprise/sapcc-api";
import { methods } from "@vsf-enterprise/unified-api-sapcc";
import type { GetCmsPageArgs, GetCmsPageResponse } from "./types";

export async function getCmsPage(
  context: SapccIntegrationContext,
  args: GetCmsPageArgs
): GetCmsPageResponse {
  const { id } = args;
  // fetch data from your CMS integration
  const { productIds, page } = await context.getApiClient("cms").getPage(id);

  // fetch products data from your eCommerce backend
  const products = await methods.getProducts(context, {
    ids: productIds,
  });

  // if you don't want to use the Unified Methods,
  // you can use the commerce API Client directly from `context.api`

  return {
    ...page,
    products,
  };
}

getApiClient method

The parameter passed to the getApiClient method should match the key of the integration in the Middleware Configuration. For example, if you have a CMS integration with the key cms, you should use context.getApiClient("cms") to fetch the API client.

const config = {
  integrations: {
    //
    cms: {
      location: "@vsf-enterprise/[cms-integration]-api/server",
      //...
    },
    // ...
  },
};