Using version 2 of the Frontend SDK

Learn about using various features of version 2 of the Frontend SDK.

The Frontend SDK, its integrations, components, and dependencies are ready to use out-of-the-box and should not require further installation. To check if the SDK is successfully installed for your project, or to manually install it, see Installing the Frontend SDK.

API methods

The base SDK provides various methods to interact with the backend extensions API. We recommend using the SDK methods for all backend extension requests because the base SDK lets you configure options such as the locale, currency, endpoint, and extension version, and it maintains these and the user session throughout your application.

All API methods return the SDKResponse type, which has an isError boolean property that you can use for narrowing. When isError is false, the response contains a data property with the return type from the API hub. When true, the response contains an error property that includes the error details. In both responses, the SDKResponse also contains tracing information for use in debugging and logging.

callAction

The callAction method lets you make requests to the action extensions. The method takes the expected return type as its generic argument that defines the type of data returned in the SDKResponse of a successful request. It also accepts the following options:

  • actionName - String - Required. The name of the action extension to call. For example, use product/getProduct to call the following extension: { actions: { product: { getProduct: (...) => { ... } } } }.

  • payload - AcceptedPayloadTypes - Optional. A payload object with key-value pairs to be serialized into the request body.

  • query - AcceptedQueryTypes - Optional. An object of key-value pairs to be serialized into the request query parameters.

  • parallel - Boolean - Optional. Defaults to true. If set to true, the action is executed asynchronously. If set to false, the action is added to a queue and executed in sequence. Setting to false is useful for actions that may cause race conditions.

  • customHeaderValue - String - Optional. The value to assign to the coFE-Custom-Configuration header value. Overrides the global customHeaderValue option set when configuring the SDK.

  • serverOptions - ServerOptions - Optional for client-side configuration and required for server-side session management. Contains the req object of type IncomingMessage and res object of type ServerResponse with cookies.

The following code example uses the callAction method to call a custom extension customActions/getCustomerCoupons with a custom header, query, and payload to be executed in sequence.

You only need to use the callAction method for custom actions. For commercetools extensions, you can use the sdk.composableCommerce integration to access the extensions which internally use callAction and already have the types and parameters completed.

Example of the callAction method to get customer's coupon informationTypeScript
const response = await sdk.callAction<Customer>({
actionName: 'customActions/getCustomerCoupons',
payload: { customer: { email: 'username@example.com' } },
query: { customerId: '4' },
parallel: false,
customHeaderValue: '{"customerAuthId":9188377992}',
});
if (response.isError) {
setError(response.error);
} else {
setCustomer(response.data);
}

getPage

The getPage method retrieves the page or redirect data for static and dynamic pages from the API hub. This method is primarily used to fetch the page data from the Studio and render the pages with the Frontend components. This method is used at the catch-all route packages/<projectName>/frontend/app/[locale]/[[...slug]]/page.tsx. This method accepts the following options:

  • path - String - Required. The relative path of the page of which you want to fetch the data. For example, /sale or /home/best-sellers.

  • query - Object - Optional. An object of key-value pairs to be serialized into the URL query parameters. It accepts the value types specified in AcceptedQueryTypes.

  • customHeaderValue - String - Optional. The value to assign to the coFE-Custom-Configuration header value. Overrides the global customHeaderValue option set when configuring the SDK.

  • serverOptions - ServerOptions - Optional for client-side configuration and required for server-side session management. Contains the req object of type IncomingMessage and res object of type ServerResponse with cookies.

The following code example uses the getPage method to get the /sale page information with a query and custom header:

Example of the getPage method to get page dataTypeScript
const response = await sdk.page.getPage({
path: '/sale',
query: { size: 'M' },
customHeaderValue: '{"customerAuthId":9188377992}',
});
if (response.isError) {
const router = useRouter();
router.push('/404');
} else {
setPageData(response.data);
}

getPreview

The getPreview method retrieves the preview data for Studio page previews, used at packages/<projectName>/frontend/app/[locale]/preview/[previewId]/page.tsx. This method accepts the following options:

  • previewId - String - Required. A string representing the ID of the preview to fetch.

  • customHeaderValue - String - Optional. The value to assign to the coFE-Custom-Configuration header value. Overrides the global customHeaderValue option set when configuring the SDK.

  • serverOptions - ServerOptions - Optional for client-side configuration and required for server-side session management. Contains the req object of type IncomingMessage and res object of type ServerResponse with cookies.

The following code example uses the getPreview method to get page preview data with the previewId and custom header:

Example of the getPreview method to get page preview dataTypeScript
const response = await sdk.page.getPreview({
previewId: 'p9986b2d', // Replace this with the variable containing the previewId
customHeaderValue: '{"customerAuthId":9188377992}',
});
if (response.isError) {
handleError(response.error);
} else {
setPreviewData(response.data);
}

getPages

The getPages method lets you fetch the page data for a page folder and all its sub-pages. This method is primarily used in B2C projects to generate the sitemap for static pages at packages/<projectName>/frontend/app/[locale]/sitemap-static.xml/route.ts. This method accepts the following options:

  • path - String - Optional. Defaults to /. The relative path of the page of which you want to fetch the data.

  • depth - Number - Optional. Defaults to 16. The depth of the page folder tree up to which you want to fetch the data.

  • types - String - Optional. Defaults to static. The types of pages to fetch.

  • customHeaderValue - String - Optional. Defaults to an empty string. The value to assign to the coFE-Custom-Configuration header value. Overrides the global customHeaderValue option set when configuring the SDK.

  • serverOptions - ServerOptions - Optional for client-side configuration and required for server-side session management. Contains the req object of type IncomingMessage and res object of type ServerResponse with cookies.

The following code example uses the getPages method to get the page data for all pages under the /sale hierarchy up to two levels deep. For example, /sale, /sale/shirts, /sale/shirts/special, and so on.

Example of the getPages method to get page data for multiple pagesTypeScript
const response = await sdk.page.getPages({
path: '/sale',
depth: 2,
customHeaderValue: '{"customerAuthId":9188377992}',
});
if (response.isError) {
handleError(response.error);
} else {
generateSitemap(response.data.pageFolderStructure);
}

Add SDK integrations

It is possible to extend the SDK with the integrations you develop. To do so, set up the integrations in the CommercetoolsSDK constructor and pass the SDK instance, such as the ComposableCommerce instance. For example:

Initialize an integration in the SDKTypeScript
//.... Other code
constructor() {
super();
// customIntegration is an example name here
this.customIntegration = new CustomIntegration(this);
}
//.... Other code

Additionally, any custom events must be added to the SDK generic type as a type intersection. For example:

Add custom integration events type using intersectionTypeScript
class CommercetoolsSDK extends SDK<ComposableCommerceEvents & CustomIntegrationEvents> {
...
}

The backend actions must be added to your backend service to extend your extensions API.

The event engine

The commercetools Frontend SDK comes with event management tools to let integrations communicate with other integrations and the user of the integration to add or create an event handler. The source for this functionality is the EventManager class, extended by the SDK. It is also possible to extend the event types with custom events with the generic argument passed from the SDK.

Following is a description of the three methods available on the SDK to manage event handlers:

  • trigger is called to trigger an event, for which an instance of the Event class from @comercetools/frontend-sdk is passed.
    An event is constructed with eventName and data. The eventName corresponds to the [key: string] value in @comercetools/frontend-sdk's StandardEvents. In custom events data corresponds to the type of value set for the event.
    For example, to trigger the marketingBannerClicked custom event, trigger is called on the sdk and an event constructed with eventName: 'marketingBannerClicked' and data: { id: "<string>" } is passed.
  • on is called to add an event handler for an event. The method takes the eventName and handler arguments.
    For example, for the marketingBannerClicked custom event, marketingBannerClicked is passed for the eventName argument and a function with event parameter of type { data: { id: "<string>" } } is passed for the handler argument.
  • off is called to remove an event handler. For example, to persist the handler only for the lifecycle of a particular component.
    The function takes the same arguments as the on function. For it to work, a named function for the handler argument must be defined. To successfully pass a named function to the handler parameter, the event type in the function's argument must be fully typed, as shown in the following examples.

Events are likely to be triggered only during action calls. The integrations you use may also create handlers so they can communicate with other integrations. However, you must be careful to avoid infinite recursion by mistakenly triggering events from event handlers.

The SDK event engine should only be used for events specific to the base SDK and integrations. The standard React events should be used for component events such as onclick and onchange.

Create custom events handlers

The commercetools Frontend SDK lets you create custom events that you can trigger from within the application, such as when clicking on a particular component or holding the pointer over it.

By default, event triggers and handlers will exist for the website's lifetime. However, you may want some to exist only during the lifetime of a specific React component. In that case, you must remove the event handlers on component unmounts. Otherwise, events can stack up due to component unmounting and remounting and may attempt to perform state updates on unmounted components, depending on the nature of the custom events.

To understand event handlers better, let's suppose you have a MarketingBanner component and you want to track how many times the banner image is clicked using the marketingBannerClicked event. To achieve this behavior, the MarketingBanner component can use the onClick React event handler, which triggers the marketingBannerClicked event.

To add custom event triggers to the SDK event definition, follow these steps:

  1. Create a MyCustomEvents.ts file in the packages/PROJECT_NAME/frontend/sdk folder with the following content:

    Custom events type definitionTypeScript
    // packages/PROJECT_NAME/frontend/sdk/MyCustomEvents.ts
    export type MyCustomEvents = {
    marketingBannerClicked: { id: string };
    };
  2. Add the type you created to the CommercetoolsSDK class in the generic SDK argument. The type must be added in the form of an intersection, as shown in the following example:

    Extend the base SDK type with custom events typeTypeScript
    // packages/PROJECT_NAME/frontend/sdk/CommercetoolsSDK.ts
    import { SDK } from "@commercetools/frontend-sdk";
    import {
    ComposableCommerce,
    ComposableCommerceEvents
    } from "@commercetools/frontend-composable-commerce";
    import { MyCustomEvents } from "./MyCustomEvents";
    class CommercetoolsSDK extends SDK<ComposableCommerceEvents & MyCustomEvents> {
    ...
    }
    ...
  3. Implement the MarketingBanner React component. In this example, we're making a simple banner component with an image.

    MarketingBanner React component implementation with event handlersTypeScript React
    import Image from 'next/image';
    import { useEffect } from 'react';
    import { sdk } from '../../sdk';
    import { Event } from '@commercetools/frontend-sdk';
    interface Props {
    marketingId: string;
    imageSrc: string;
    }
    const MarketingBanner = ({ marketingId, imageSrc }: Props) => {
    const marketingBannerClickedHandler = (
    event: Event<
    'marketingBannerClicked',
    {
    id: string;
    }
    >
    ) => {
    // Perform custom event handling logic here.
    console.log('Marketing banner clicked, id: ' + event.data.id);
    };
    const clickHandler = (id: string) => {
    sdk.trigger(
    new Event({
    eventName: 'marketingBannerClicked',
    data: {
    id: id,
    },
    })
    );
    };
    useEffect(() => {
    sdk.on('marketingBannerClicked', marketingBannerClickedHandler);
    return () => {
    sdk.off('marketingBannerClicked', marketingBannerClickedHandler);
    };
    }, []);
    return <Image src={imageSrc} onClick={() => clickHandler(marketingId)} />;
    };
    export default MarketingBanner;

    We define a function named marketingBannerClickedHandler that takes a parameter event of class Event from the @commercetools/frontend-sdk library. This class takes the EventName and EventData parameters as the generic arguments, matching the event we defined earlier in the MyCustomEvents.ts file by name (key) and data (value) respectively.

    Then, we define a function clickHandler that constructs the marketingBannerClicked event and triggers it using the sdk.trigger method. The event has the following properties:

    • eventName: the name of the custom event.
    • data: value of the custom event where id is the identifier of the clicked marketing banner.

    Then, we use the React useEffect hook to call sdk.on to set up the event handler on component mount and sdk.off to remove the handler on component unmount by passing the named handler on both occasions.

    Finally we call the clickHandler from the onClick event of the Image component.

For more information about how you can extend the SDK with integrations, see Developing SDK integrations.