Vue Storefront is now Alokai! Learn More
Utilising SDK modules

Utilising SDK modules

Introduction

Alokai SDK is a framework-agnostic communication layer in Alokai Integrations. It communicates with Commerce Platforms and third-party services through the Server Middleware, which works as a proxy. Alokai SDK creates a contract between the storefront and the Server Middleware.

The middlewareModule is a module of the Alokai SDK that allows you to interact with the Storefront API. It is designed to work seamlessly with other Alokai SDK modules, such as those for various eCommerce platforms like SAP Commerce Cloud.

In this guide, we'll show you how to use the SDK modules in your Storefront application.

Installation

To use a new module, for instance the SAP Commerce Cloud, you'll need to follow the below steps:

Installing the middleware API module

Remember that each time you add an SDK module, it should have a relevant middleware API Client installed as well. In Storefront, the middleware API Client should be installed into the apps/storefront-middleware directory.

  1. Install the API Client (the server).
yarn workspace storefront-middleware add @vsf-enterprise/sapcc-api
  1. Update apps/storefront-middleware/middleware.config.ts file.
  • Add new API-client integration to the config (more info here)
// apps/storefront-middleware/middleware.config.ts
const config = {
  integrations: {
      ...,
      sapcc: {
          location: '@vsf-enterprise/sapcc-api/server',
          configuration: {
              OAuth: {
                  uri: process.env.SAPCC_OAUTH_URI,
                  clientId: process.env.SAPCC_OAUTH_CLIENT_ID,
                  clientSecret: process.env.SAPCC_OAUTH_CLIENT_SECRET,
                  tokenEndpoint: process.env.SAPCC_OAUTH_TOKEN_ENDPOINT,
                  tokenRevokeEndpoint: process.env.SAPCC_OAUTH_TOKEN_REVOKE_ENDPOINT,
                  cookieOptions: {
                      'vsf-sap-token': { secure: process.env.NODE_ENV !== 'development' }
                  }
              },
              api: {
                  uri: process.env.SAPCC_API_URI,
                  baseSiteId: 'apparel-uk',
                  catalogId: 'apparelProductCatalog',
                  catalogVersion: 'Online',
                  defaultLanguage: 'en',
                  defaultCurrency: 'GBP'
              },
          }
      }
  },
};
  1. Export the API Client Endpoints type from storefront-middleware/types.ts file.
/types.ts
export type { Endpoints as SapccEndpoints } from "@vsf-enterprise/sapcc-api";
  1. Update sdk.config.ts file.
  • Add the new module inside SDK configuration.
Next
// apps/storefront-unified-nextjs/sdk/index.ts
import { SapccEndpoints } from "storefront-middleware/types";

export const sdk = createSdk(options, ({ buildModule, middlewareModule, middlewareUrl, getRequestHeaders }) => ({
  ...
  sapcc: buildModule(middlewareModule<SapccEndpoints>, {
    apiUrl: `${middlewareUrl}/sapcc`,
    defaultRequestConfig: {
      headers: getRequestHeaders(),
    },
  }),
});

Now you can use both sdk.unified.<methodName>, which returns the Unified Data Model, and sdk.sapcc.<methodName> which returns the raw data.

Real World Examples

Adding Product Reviews with SAP SDK

In this example, we'll create a custom React hook that utilizes useQuery and sdk.sapcc.createProductReview to add product reviews. We'll also create a form component for adding reviews and update the existing ProductReviews component to include the form.

Creating the useAddProductReview Hook

  1. Create a hooks/useAddProductReview/ directory.
  2. Create a new file useAddProductReview.ts in hooks/useAddProductReview/ directory.
  3. Import the necessary dependencies, including the useQuery hook and the SAP SDK module.
  4. Define the useAddProductReview() function hook.
  5. Implement the useAddProductReview() hook to utilize useQuery and the sdk.sapcc.createProductReview method to add a product review.
  6. Return the necessary variables and functions from the hook.
  7. Create a index.ts file in hooks/useAddProductReview/ directory.
  8. Update the index.ts in hooks/.
import { useMutation } from "@tanstack/react-query";
import { sdk } from "~/sdk";

export const useAddProductReview = (productCode: string) => {
  return useMutation(["addProductReview", productCode], ({ review }) =>
    sdk.sapcc.createProductReview({ productCode, review })
  );
};

Now, create a index.ts file in hooks/useAddProductReview/ directory that exports a created hook:

export * from "./useAddProductReview";

Then update the index.ts in the hooks/ directory and export useAddProductReview module:

export * from "./useAddProductReview";

Creating the AddProductReviewForm Component

  1. Create AddProductReviewForm directory in components.
  2. Create a new file called AddProductReviewForm.tsx in the AddProductReviewForm directory.
  3. Import the necessary React components from the @storefront-ui library (e.g., SfInput, SfTextarea).
  4. Import the useAddProductReview hook.
  5. Define the AddProductReviewForm component as a functional component.
  6. Implement the form submission handler function that will utilize the createProductReview function from the useAddProductReview hook.
  7. Render the form fields and UI components using SFUI library.
  8. Export the AddProductReviewForm component for use in other components.
  9. Create a index.ts with exported AddProductReviewForm component.
  10. Update the index.ts in components.
import { useState } from 'react';
import { SfButton, SfInput, SfTextarea, SfRatingButton } from '@storefront-ui/react';
import useAddProductReview from '~/hooks';

export function AddProductReviewForm({ productId }) {
  const [title, setTitle] = useState('');
  const [rating, setRating] = useState(0);
  const [review, setReview] = useState('');

  const { mutate: createProductReview } = useAddProductReview(productId);

const handleSubmit: FormEventHandler<HTMLFormElement> = async (event) => {
  event.preventDefault();
  const reviewData = {
    alias: title,
    rating,
    comment: review,
  };
  createProductReview(
    { review: reviewData },
    {
      onSuccess() {
        // Handle successful review submission
        setTitle('');
        setRating(0);
        setReview('');
      },
      onError() {
        // Handle error
        console.error('Failed to submit product review:', error);
      },
    },
  );
};

  return (
    <div>
      <h3 className="my-3">Write a Review</h3>
      <form onSubmit={handleSubmit} className="space-y-5 mx-3">
        <div>
          <p id="rating">Select Rating</p>
          <SfRatingButton value={rating} onChange={setRating} aria-labelledby="rating" />
        </div>
        <div>
          <label htmlFor="title">Title:</label>
          <SfInput id="title" type="text" value={title} onChange={(event) => setTitle(event.target.value)} required />
        </div>
        <div>
          <label htmlFor="review" className="block">
            Review:
          </label>
          <SfTextarea
            id="review"
            className="w-full"
            value={review}
            onChange={(event) => setReview(event.target.value)}
            required
          />
        </div>
        <div>
          <SfButton type="submit">Submit Review</SfButton>
        </div>
      </form>
    </div>
  );
};

export default AddProductReviewForm;

Now create the index.ts file with the content:

export * from "./AddProductReviewForm";

And then update the index.ts in the components directory:

export * from "./AddProductReviewForm";

Updating the ProductReviews Component

  1. Import the AddProductReviewForm component into the existing ProductReviews component.
  2. Add the AddProductReviewForm component to the JSX of the ProductReviews component.
import { SfLoaderCircular } from "@storefront-ui/react";
import { SfProductReview } from "@vsf-enterprise/unified-api-sapcc";
import { useTranslation } from "next-i18next";
import type { ProductReviewsProps } from "~/components/ProductReviews/types";
import { Review } from "~/components/ui";
import { useProductReviews } from "~/hooks";
import { AddProductReviewForm } from "../AddProductReviewForm";

// ...

export function ProductReviews({ productId }: ProductReviewsProps) {
  // ...

  if (!reviewsList.length) {
    return (
      <>
        {t("noReviews")}
        <AddProductReviewForm />
      </>
    );
  }

  return (
    <>
      {/* Existing code for displaying product reviews */}
      {reviewsList.map((review) => (
        <Review
          className="mb-4"
          key={review.id}
          content={review.text ?? undefined}
          author={review.reviewer ?? undefined}
          title={review.title ?? undefined}
          rating={review.rating ?? undefined}
          date={getReviewDate(review)}
          showLessText={t("readLess")}
          showMoreText={t("readMore")}
        />
      ))}
      {/* Add product review form */}
      <AddProductReviewForm productId={productId} />
    </>
  );
}

export default ProductReviews;