Creating an API Client

Creating an API Client

The API client is used by the server middleware to create a server-to-server communication with your custom backend.

Creating the integration client

To start, create a new folder called api-client in the src folder of your integration. This package will contain your integration API client.

First, you should create the index.server.ts file. It will be the entry point for the server middleware. It should look like this:

// index.server.ts
import { apiClientFactory } from '@vue-storefront/middleware';

const onCreate = (settings: any) => {
  // TODO: create a client here and return it with the integration configuration
};

const { createApiClient } = apiClientFactory({
  onCreate,
  api: {},
});

export { createApiClient };

The apiClientFactory is a function that creates a factory for creating API clients.

The onCreate function is called when the server middleware is initialized. It should return an object with the integration configuration and the client.

The api object is a set of functions that will be available in the integration client.

Now, let's create the client.

In the following example we used the axios library to create a client. However, you can use any client that you suits your needs.

The buildClient function creates an instance of the axios client. It's a good practice to create a separate function for creating the client, so you can easily mock it in the tests.

The onCreate function returns accepts the integration configuration, and we recommend that you create an interface for it.

// types/config/index.ts

/**
 * Settings to be provided in the `middleware.config.js` file.
 */
export interface MiddlewareConfig {
  // Add the fields provided in the `middleware.config.js` file.
}

You should use the MiddlewareConfig interface in the onCreate function.

// index.server.ts
import { apiClientFactory } from '@vue-storefront/middleware';
import axios from 'axios';
import { MiddlewareConfig } from './types/config';

const buildClient = () => {
  const axiosInstance = axios.create();
  return axiosInstance;
};

const onCreate = (settings: MiddlewareConfig) => {
  const client = buildClient();

  return {
    config: settings,
    client,
  };
};

const { createApiClient } = apiClientFactory({
  onCreate,
  api: {},
});

export { createApiClient };

The server middleware can be initialized now, but it does not contain any API functions. Before adding them, let's type the integration context. Vue Storefront uses the context object to pass the integration client and the configuration to the API functions. Create a types/context/index.ts file and add the following code:

// types/context/index.ts
import { IntegrationContext } from '@vue-storefront/middleware';
import { AxiosInstance } from 'axios';
import { MiddlewareConfig } from '../config';

/**
 * All available API Endpoints without first argument - `context`, because this prop is set automatically.
 */
export type ContextualizedEndpoints = {
  [T in keyof Endpoints]: Endpoints[T] extends (x: any, ...args: infer P) => infer R ? (...args: P) => R : never;
};

/**
 * Runtime integration context, which includes API client instance, settings, and endpoints that will be passed via middleware server.
 * This interface name is starting with `MyIntegration`, but you should use your integration name in here.
 **/
export type MyIntegrationIntegrationContext = IntegrationContext<
  AxiosInstance, // HTTP client instance
  MiddlewareConfig,
  ContextualizedEndpoints
>;

/**
 * Global context of the application which includes runtime integration context.
 **/
export interface Context {
  // This property is named `myIntegration`, but you should use your integration name in here.
  $myIntegration: MyIntegrationIntegrationContext;
}

The ContextualizedEndpoints type is a set of API functions without the context argument. It's necessary for the IntegrationContext type. It also requires the type of client used in the integration and the type of integration configuration.

The Context type is the global context of the application. It's used by api-client methods to access the integration client and the configuration.

Now you can add the interface for the API functions.

// types/api/index.ts
import { MyIntegrationContext } from '../config';

type TODO = any;

/**
 * Definition of all API-client methods available in {@link https://docs.vuestorefront.io/v2/advanced/context.html#context-api | context}.
 */
export interface Endpoints {
  /**
   * Here you can find an example endpoint definition. Based on this example, you should define how your endpoint will look like.
   * This description will appear in the API extractor, so try to document all endpoints added here.
   */
  exampleEndpoint: (context: MyIntegrationContext, params: TODO) => Promise<TODO>;
}

Finally, you can create the exampleEndpoint function.

// api/exampleEndpoint/index.ts
import { Endpoints } from '../../types';

export const exampleEndpoint: Endpoints['exampleEndpoint'] = async (context, params) => {
  console.log('exampleEndpoint has been called');

  // Example request could look like this:
  // return await context.client.get(`example-url?id=${params.id}`);
  return Promise.resolve({ success: true });
};

You should also export the exampleEndpoint function in the api/index.ts file.

// api/index.ts
export * from './exampleEndpoint';

To be able to call the exampleEndpoint function, you should add it to the api object in the index.server.ts file.

import { apiClientFactory } from '@vue-storefront/middleware';
import axios from 'axios';
import * as api from './api';
import { MiddlewareConfig } from './types/config';

const buildClient = () => {
  const axiosInstance = axios.create();
  return axiosInstance;
};

const onCreate = (settings: MiddlewareConfig) => {
  const client = buildClient();

  return {
    config: settings,
    client,
  };
};

const { createApiClient } = apiClientFactory({
  onCreate,
  api,
});

export { createApiClient };

Running the integration

Your integration is ready to use. You can test it by setting up the middleware.config.js file and running the middleware

Building your integration

This guide described the details of creating the integration, but it does not cover the details of the building process. You can find the tools and configuration we use by default in our integrations in our integration boilerplate repository

// middleware.config.js

module.exports = {
  integrations: {
    boilerplate: {
      location: '@vsf-enterprise/my-integration-api/server', // This should be the path to your built index.server.js file
      configuration: {
        // Add your configuration here
      },
    },
  },
};

You can run the server middleware with this example script:

// server.js
const { createServer } = require('@vue-storefront/middleware');
const { integrations } = require('./middleware.config');
const cors = require('cors');

(async () => {
  const app = await createServer({ integrations });
  const host = process.argv[2] ?? '0.0.0.0';
  const port = process.argv[3] ?? 8181;
  const CORS_MIDDLEWARE_NAME = 'corsMiddleware';

  const corsMiddleware = app._router.stack.find((middleware) => middleware.name === CORS_MIDDLEWARE_NAME);

  corsMiddleware.handle = cors({
    origin: ['http://localhost:3000'],
    credentials: true,
  });

  app.listen(port, host, () => {
    console.log(`Middleware started: ${host}:${port}`);
  });
})();

To run the middleware, you should run the following command:

node server.js

To call the endpoint, simply run a POST request to the http://localhost:8181/myIntegration/exampleEndpoint endpoint.