@volvo-cars/content-delivery-client v0.9.1
@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
clientConfigapplicationId: stringId of your applicationapiKey: stringContent Delivery API key for your product.defaultDataSource?: stringDefault 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 tofetch. By default includes a Keep-Alive https Agent in Node.js. Passagent: nullor a customhttps.Agentinstance to disable the default agent.path?: stringFile system path where local fallback content is available, if local fallbacks are used.forceLocalData?: booleanUse content from the local (English) master files, no API calls are made. Useful in development. Defaults tofalse. Only available in Node.js.fallbackToLocalData?: booleanUse local (English) master content if the data is missing in the datasource. Defaults tofalse. 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: stringWhich locale to fetch content for.environment?: live | authoringPreview | master: Environment to fetch content from in the CMS. Defaults tolive.preview?: booleanFetch preview content from the CMS. Defaults tofalsemarket?: booleanFetch content from within a market node.operationId?: stringVCC-Api-OperationId header to send with the request.timeout?: numberTimeout in seconds after which to stop waiting for a response and throw an error instead.dataSource?Data Source to fetch from. Defaults todefaultDataSourcefrom the Client Config.
ContentDeliveryError
Base class for all errors and always what's returned from any errors when using the Content Delivery API.
name: stringContentDeliveryErrorerrors: Error[]The original runtime error(s).dataSource: stringlocale: stringpreview: booleanmarket?: stringoperationId?: string
DictionaryNotFoundError
Thrown if a language version for a dictionary could not be found, or if no dictionaries are available in an application.
name: stringDictionaryNotFoundErrordata?: DictionariesPartial 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');
)10 months ago
9 months ago
1 year ago
1 year ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago