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
- Create a new Middleware extension in the
/integrations/<integration>/extensions/myExtension.ts
file.
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.
export * from "./unified";
export * from "./multistore";
export * from "./myExtension";
- Create a new API method in the
/api/myExtension
directory.
First, define the arguments and response types in the /api/myExtension/types.ts
file.
export interface GetHomePageArgs {
// your arguments
}
export interface GetHomePageResponse {
// interface for the response
}
Then, implement an API method in the /api/myExtension/getHomepage.ts
file.
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.
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.
- Create a new Middleware extension in the
apps/storefront-middleware/integrations/<integration>/extensions
directory and register custom API method.
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.
import type { ApiClientExtension } from "@vue-storefront/middleware";
export const myExtension = {
name: "myExtension",
isNamespaced: true,
extendApiMethods: {
getHomepage: async (context, args) => {
// your implementation
},
},
} satisfies ApiClientExtension;
- Export the type of the endpoints, to use them later in the SDK configuration.
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
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";
- Register the extension in the integration config file.
import { myExtension } from "./extensions";
export const config = {
// ...
extensions: (extensions: ApiClientExtension[]) => [
...extensions,
unifiedApiExtension,
...(IS_MULTISTORE_ENABLED ? [multistoreExtension] : []),
myExtension, ],
} satisfies Integration<MiddlewareConfig>;
- Export
MyExtensionEndpoints
type from theapps/storefront-middleware/
app.
export type { MyExtensionEndpoints } from "./integrations/<integration>/types";
- 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.
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.
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.
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",
//...
},
// ...
},
};