0.6.0 • Published 2 months ago

@volvo-cars/content-delivery-client v0.6.0

Weekly downloads
-
License
UNLICENSED
Repository
github
Last release
2 months ago

@volvo-cars/content-delivery-client

This package is a wrapper around the Content Delivery API. It currently supports consuming dictionaries.

Quick Start

First add @volvo-cars/content-delivery-client to your projects dependecies in your package.json file:

  "dependencies": {
    "@volvo-cars/content-delivery-client": "workspace:*"
  }

Dictionaries

Create Dictionary Client

A single client can be shared across requests to utilize the cache.

import { createClient } from '@volvo-cars/content-delivery-client';

const contentClient = createClient({
  applicationId: 'applicationId',
  defaultDataSource: 'dotcom-sitecore-prod',
  allowedEnvironments: process.env.ALLOW_PREVIEW
    ? ['authoringPreview', 'live']
    : ['live'],
  apiKey: process.env.CONTENT_DELIVERY_API_KEY,
  // Will only fetch from api when revalidate (in seconds) has passed, defaults to 60
  revalidate: 120,
  forceLocalData: process.env.DEPLOY_ENV === 'dev',
});

You can also keep most configurations as environment variables:

import { createClient } from '@volvo-cars/content-delivery-client';

const contentClient = createClient({
  applicationId: 'applicationId',
  defaultDataSource: process.env.DEFAULT_CONTENT_DATA_SOURCE,
  allowedDataSources: process.env.ALLOWED_CONTENT_DATA_SOURCES,
  defaultEnvironment: process.env.DEFAULT_CONTENT_ENVIRONMENT,
  allowedEnvironments: process.env.ALLOWED_CONTENT_ENVIRONMENTS,
  apiKey: process.env.CONTENT_DELIVERY_API_KEY,
});

getAllDictionaries

Fetches all dictionaries in an application in a single API call.

try {
  await contentClient.getAllDictionaries({
    locale: 'en',
  });
} catch (error) {
  // handle error
}

getDictionary

Fetches a single dictionary.

try {
  await contentClient.getDictionary('myNamespace.myDictionaryName', {
    locale: 'en',
  });
} catch (error) {
  // handle error
}

getDictionaries

Convenience method to fetch multiple dictionaries. Sends one HTTP request per dictionary. If a one of the dictionaries were missing in the given locale, the dictionaries from the successful requests will be available as the data property on the thrown error.

let dictionaries;
try {
  dictionaries = await contentClient.getDictionaries(
    ['myNamespace.myDictionaryName', 'myNamespace.otherDictionary'],
    {
      locale: 'en',
    }
  );
} catch (error) {
  if (error.name === 'DictionaryNotFoundError' && error.data) {
    dictionaries = error.data;
  }
}

API

createClient(clientConfig): ContentDeliveryClient

  • clientConfig
    • applicationId: string Id of your application
    • apiKey: string Content Delivery API key for your product.
    • defaultDataSource?: string Default DataSource to fetch from.
    • revalidate?: number | { dictionaries?: number, entries?: number } An optional amount in seconds after which to revalidate cached content in the background. Defaults to 60 seconds. Set to 0 to always fetch from the network and only use the cache on errors.
    • fetchOptions?: { agent?: Agent | null } Options to pass through to fetch. By default includes a Keep-Alive https Agent in Node.js. Pass agent: null or a custom https.Agent instance to disable the default agent.
    • path?: string File system path where local fallback content is available, if local fallbacks are used.
    • forceLocalData?: boolean Use content from the local (English) master files, no API calls are made. Useful in development. Defaults to false. Only available in Node.js.
    • fallbackToLocalData?: boolean Use local (English) master content if the data is missing in the datasource. Defaults to false. Only available in Node.js.
ContentDeliveryClient.getAllDictionaries(options: GetOptions): Promise<Dictionaries>
ContentDeliveryClient.getDictionary(canonicalDictionaryName: string, options: GetOptions): Promise<Dictionaries>
ContentDeliveryClient.getDictionaries(canonicalDictionaryNames: string[], options: GetOptions): Promise<Dictionaries>
ContentDeliveryClient.getEntry(canonicalName: string, options: GetOptions): Promise<unknown>
ContentDeliveryClient.listEntries(contentType: ContentType, options: GetOptions): Promise<ListEntriesResponseData>

Dictionaries

All methods return a Dictionaries object where the key is the Canonical Dictionary Name, and the value is an object of dictionary items.

{
  'namespace1.dictionaryName': {
    'dictionaryItemKey': 'dictionaryItemValue',
  }
}

GetOptions

  • locale: string Which locale to fetch content for.
  • environment?: live | authoringPreview | master: Environment to fetch content from in the CMS. Defaults to live.
  • preview?: boolean Fetch preview content from the CMS. Defaults to false
  • market?: boolean Fetch content from within a market node.
  • operationId?: string VCC-Api-OperationId header to send with the request.
  • timeout?: number Timeout in seconds after which to stop waiting for a response and throw an error instead.
  • dataSource? Data Source to fetch from. Defaults to defaultDataSource from the Client Config.

ContentDeliveryError

Base class for all errors and always what's returned from any errors when using the Content Delivery API.

  • name: string ContentDeliveryError
  • errors: Error[] The original runtime error(s).
  • dataSource: string
  • locale: string
  • preview: boolean
  • market?: string
  • operationId?: string

DictionaryNotFoundError

Thrown if a language version for a dictionary could not be found, or if no dictionaries are available in an application.

  • name: string DictionaryNotFoundError
  • data?: Dictionaries Partial data from any sucessful requests.

Caching

Caching follows the Stale While Revalidate and Stale While Error patterns, which means any fetch except the first one will immediately return a response from a local in-memory cache. If the returned content was stale, meaning the revalidate time has passed since it was last fetched, it will be updated in the background, and on the next fetch the fresh content will be returned.

This means that as long as a single request has ever succeeded in your application the client will continue to return (old, but available) dictionary entries until your server is restarted.

One copy of every entry in every locale in your application will be kept in a memory cache, which should be fine for most use cases. If this becomes a problem you can disable caching by setting revalidate to 0. A Least Recently Used cache expiration is on the TODO list.

Usage with React

Nextjs

// ./src/providers/DictionariesProvider.tsx

// Everytime you update dictionaries with items, a DictionaryItemTypes file will be
// written to ./config.path/. This will help with autocompleting and validating useTranslate hook.
import { DictionaryItemTypes } from '../src/content-management/DictionaryItemTypes';
import { getDictionariesProvider } from '@vcc-www/react-translate';

export const {
  useTranslate,
  DictionariesProvider,
} = getDictionariesProvider<DictionaryItemTypes>();
// ./src/components/MyComponent.tsx
import { useTranslate } from '../src/providers/DictionariesProvider';
export const MyComponent: React.FC = () => {
  const translate = useTranslate();
  return (
    <div>
      {translate('item1', {
        parameter1: 'Some value',
        parameter2: 'Some value',
      })}
    </div>
  );
};
//translate will have typing support and give you hints on what items can be translated and what parameters can be given to that certain item
//pages/index.ts
import {
  createClient,
  Dictionaries,
} from '@volvo-cars/content-delivery-client';
import { DictionariesProvider } from '../src/providers/DictionariesProvider';
import { MyComponent } from '../src/components/MyComponent';

const contentClient = createClient({
  path: './src/content-management',
  apiKey: process.env.CONTENT_DELIVERY_API_KEY,
  defaultDataSource: 'dotcom-sitecore-prod',
  applicationId: 'myApplication',
  forceLocalData: process.env.NODE_ENV === 'development',
});

export default function Index({
  dictionaries,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  return (
    <DictionariesProvider locale="en" dictionaries={dictionaries}>
      <MyComponent />
    </DictionariesProvider>
  );
}

export const getStaticProps: GetStaticProps<{
  dictionaries: Dictionaries,
}> = async (props) => {
  try {
    const dictionaries = await contentClient.getAllDictionaries({
      locale: 'en',
    });
  } catch (error) {
    console.log(error);
  }
  return {
    props: {
      dictionaries,
    },
  };
};

Usage with React SSR

// ./server.tsx
import React from 'react';
import ReactDomServer from 'react-dom/server';
import express from 'express';
import { createClient } from '@volvo-cars/content-delivery-client';
import App from './components/App.tsx';
import htmlTemplate from './build/index.html';

const app = express();
const port = 3000;

const contentClient = createClient({
  path: './src/content-management',
  apiKey: process.env.CONTENT_DELIVERY_API_KEY,
  defaultDataSource: 'dotcom-sitecore-prod',
  applicationId: 'myApplication',
  revalidate: 60,
});

app.get('/', (req, res) => {
  const content = ReactDomServer.renderToString(<App />);
    let dictionaries = {};
  try {
    dictionaries = await contentClient.getAllDictionaries({
      locale: 'en',
    });
  } catch (error) {
    console.error(error);
  }
  const html = html.replace('<div id="root"></div>', `
  <script type="application/json" id="__DICTIONARIES_STATE__">${JSON.stringify(dictionaries)}</script>
  <div id="root">${content}</div>
  `);
  res.send(html)
});

app.listen(port, () => {
  console.info(`Listening on port ${port}`);
});
//client.tsx
import React from 'react';
import ReactDOM from 'react-dom'
import App from './components/App.tsx';
import { DictionariesProvider } from './src/providers/DictionariesProvider';

const stateNode = document.getElementById('__DICTIONARIES_STATE__');
const dictionaries = JSON.parse(stateNode.innerHTML);
  ReactDOM.hydrate(
    <DictionariesProvider locale = "en" dictionaries={dictionaries}>
      <App />
    </DictionariesProvider>
,document.getElementById('app');
  )
0.6.0

2 months ago

0.5.0

12 months ago

0.4.6

1 year ago

0.4.5

1 year ago

0.4.4

1 year ago

0.4.1

2 years ago

0.4.3

1 year ago

0.4.2

1 year ago

0.4.0

2 years ago

0.3.0

2 years ago

0.2.0

2 years ago

0.1.1

2 years ago

0.1.0

2 years ago

0.0.3

3 years ago

0.0.2

3 years ago