JavaScript Delivery SDK Documentation
JavaScript Delivery SDK is a client library for retrieving data from Kontent.ai. Works
both in browser & node.js environments.
Kontent.ai Delivery SDK
Installation
You can install this library using npm
or you can use global CDNs such jsdelivr
.
npm
npm i @kontent-ai/delivery-sdk --save
UMD Bundles
When using UMD bundle and including this library in script
tag on your html
page, you can find it under the
kontentDelivery
global variable.
Bundles are distributed in dist/bundles
folder:
dist/bundles/kontent-delivery.umd.js
dist/bundles/kontent-delivery.umd.min.js
CDN
kontent-delivery.umd.js
https://cdn.jsdelivr.net/npm/@kontent-ai/delivery-sdk@latest/dist/bundles/kontent-delivery.umd.js
kontent-delivery.umd.min.js
https://cdn.jsdelivr.net/npm/@kontent-ai/delivery-sdk@latest/dist/bundles/kontent-delivery.umd.min.js
TypeScript & ES6
import { type IContentItem, type Elements, createDeliveryClient } from '@kontent-ai/delivery-sdk';
export type Movie = IContentItem<{
title: Elements.TextElement;
plot: Elements.RichTextElement;
released: Elements.DateTimeElement;
length: Elements.NumberElement;
poster: Elements.AssetsElement;
category: Elements.MultipleChoiceElement;
stars: Elements.LinkedItemsElement<Actor>;
seoname: Elements.UrlSlugElement;
releaseCategory: Elements.TaxonomyElement;
}>;
const deliveryClient = createDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>'
});
const response = await deliveryClient.items<Movie>().type('<CONTENT_TYPE_CODENAME>').toPromise();
const movieText = response.data.items[0].elements.title.value;
JavaScript & CommonJS
const KontentDelivery = require('@kontent-ai/delivery-sdk');
const deliveryClient = KontentDelivery.createDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>',
});
const response = await deliveryClient.items()
.type('<CONTENT_TYPE_CODENAME>')
.toPromise();
const movieText = response.data.items[0].elements.title.value;
HTML & UMD & CDN
<!DOCTYPE html>
<html>
<head>
<title>Kontent.ai SDK - Html sample</title>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/@kontent-ai/delivery-sdk@11.0.0/dist/bundles/kontent-delivery.umd.min.js"
></script>
</head>
<body>
<script type="text/javascript">
var KontentDelivery = window['kontentDelivery'];
var deliveryClient = KontentDelivery.createDeliveryClient({
environmentId: 'da5abe9f-fdad-4168-97cd-b3464be2ccb9'
});
deliveryClient
.items()
.type('movie')
.toPromise()
.then((response) => console.log(response));
</script>
<h1>See console</h1>
</body>
</html>
SDK Documentation
Client configuration
Following is a list of configuration options for DeliveryClient (IDeliveryClientConfig
):
Property | type | description |
---|
environmentId | string | environmentId of your Kontent.ai project |
elementResolver? | ElementResolver | Element resolver used to map custom elements |
previewApiKey? | string | Preview API key used to get unpublished content items |
defaultLanguage? | string | Sets default language that will be used for all queries unless overridden with query parameters |
proxy? | IDeliveryClientProxyConfig | Can be used to configure custom URLs. Useful when you use reverse proxy or have a need to transform URL - e.g. to remove 'environmentId' |
secureApiKey? | string | Secured API key: Use secured API only when running on Node.JS server, otherwise you can expose your key |
defaultQueryConfig? | IQueryConfig | Default configuration for all queries. Can be overridden by individual queries |
httpService ? | IHttpService | Can be used to inject custom http service for performing requests |
globalHeaders? | (queryConfig: IQueryConfig) => IHeader[] | Adds ability to add extra headers to each http request |
retryStrategy? | IRetryStrategyOptions | Retry strategy configuration |
linkedItemsReferenceHandler? | LinkedItemsReferenceHandler | Indicates if content items are automatically mapped. Available values: 'map' or 'ignore' |
propertyNameResolver? | PropertyNameResolver | Used to map properties. Choose one of the following default resolvers: snakeCasePropertyNameResolver , pascalCasePropertyNameResolver & camelCasePropertyNameResolver or create your own PropertyNameResolver function |
assetsDomain? | string | Custom domain for assets. Changes url of assets in both asset & rich text elements |
defaultRenditionPreset? | string | Codename of rendition preset to be applied by default to the base asset URL path when present. When set, the SDK will provide the URL of customized images by default. Right now the only supported preset codename is default . |
excludeArchivedItems? | boolean | Can be used to exclude archived items from all queries by default. Only applicable when preview API is used. |
Create typed models
Recommended: Use the Model Generator to automatically
generate TypeScript models based on the content types in your Kontent.ai project.
You may define optional models in Typescript representing your actual data defined in Kontent.ai projects. You can also
auto-generate these models (see below).
import { IContentItem, Elements } from '@kontent-ai/delivery-sdk';
export type Movie = IContentItem<{
title: Elements.TextElement;
plot: Elements.RichTextElement;
released: Elements.DateTimeElement;
length: Elements.NumberElement;
poster: Elements.AssetsElement;
category: Elements.MultipleChoiceElement;
stars: Elements.LinkedItemsElement<Actor>;
seoname: Elements.UrlSlugElement;
releaseCategory: Elements.TaxonomyElement;
}>;
Fetch data
To get multiple content items, use the items
method. You can specify the content type with the type
method:
deliveryClient.items<Movie>().type('typeCodename').toPromise();
deliveryClient.item<Movie>('itemCodename').toPromise();
Supported elements: TextElement
, MultipleChoiceElement
, DateTimeElement
, RichTextElement
, NumberElement
,
AssetsElement
, UrlSlugElement
, TaxonomyElement
, LinkedItemsElement
and CustomElement
. Additionally, you might
also get UnknownElement
or a custom model if you register it for your custom elements.
Use custom models for Custom elements
You can register an ElementResolver
to map custom elements into dedicated element models and work with data more
effectively.
For example, if you have a custom color
element in your Kontent.ai project with json data like:
"color": {
"type": "custom",
"name": "Color",
"value": "{\"red\":167,\"green\":96,\"blue\":197}"
}
You can create a ColorElement
type with strongly typed properties for red
, green
& blue
values that you will
parse from the json.
import { ElementModels, Elements, createDeliveryClient } from '@kontent-ai/delivery-sdk';
type ColorElement = Elements.CustomElement<{
red: number;
green: number;
blue: number;
}>;
To resolve your custom element into ColorElement
, use the ElementResolver
in your delivery client config:
const client = createDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>',
elementResolver: (elementWrapper) => {
if (elementWrapper.rawElement.type === 'color') {
const parsed = JSON.parse(elementWrapper.rawElement.value);
return {
red: parsed.red,
green: parsed.green,
blue: parsed.blue
};
}
return undefined;
}
});
You can then use this custom element type in your models:
type Movie = IContentItem<{
color: ColorElement;
title: Elements.TextElement;
}>;
Query parameters
The SDK supports the following query parameters: depthParameter
, elementsParameter
, limitParameter
,
orderParameter
, skipParameter
and languageParameter
. For more information about the parameters, see the
SDK query methods below. You can also head over to
Delivery API reference.
deliveryClient.items<Movie>().type('movie').limitParameter(5).skipParameter(2).toPromise();
Filter content
This example returns all Movie content items whose title element is equal to Warrior. Filters are also
considered query parameters and can be combined. See
Content filtering in API reference for more
general examples.
Supported filters: type
, types
, allFilter
, anyFilter
, containsFilter
, equalsFilter
, greaterThanFilter
,
greaterThanOrEqualFilter
, infilter
, lessThanFilter
, lessThanOrEqualFilter
, rangeFilter
, emptyFilter
,
notEmptyFilter
, notEqualsFilter
, NotInFilter
.
deliveryClient.items<Movie>().type('movie').equalsFilter('elements.title', 'Warrior').toPromise();
Filtering methods
Filter | Description |
---|
type | Retrieve only content items based on the given type. |
types | Retrieve only content items based on the given types. |
allFilter | Element with an array of values contains the specified list of values. |
anyFilter | Element with an array of values contains any value from the specified list of values. |
containsFilter | Element with an array of values contains the specified value. |
equalsFilter | Element value is the same as the specified value |
greaterThanFilter | Element value is greater than the specified value. |
greaterThanOrEqualFilter | Element value is greater than or equals the specified value. |
infilter | Element value is in the specified list of values. |
lessThanFilter | Element value is less than the specified value. |
lessThanOrEqualFilter | Element value is less than or equals the specified value |
rangeFilter | Element value falls in the specified range of two values, both inclusive. |
emptyFilter | Property value is empty. |
NotEmptyFilter | Property value is not empty. |
notEqualsFilter | Property value does not equal the specified value. |
notInFilter | Property value is not in the specified list of values. |
Sort content
You can sort data by using any of the following methods:
deliveryClient.items<Movie>().type('movie').orderByDescending('elements.title').toPromise();
deliveryClient.items<Movie>().type('movie').orderByAscending('elements.title').toPromise();
deliveryClient.items<Movie>().type('movie').orderParameter('elements.title', 'desc').toPromise();
Execute queries with a custom URL
When you have an URL (i.e. for next page
in paging, for testing purposes or just if you prefer to build it on your
own) and still want to leverage SDK functionality such as type mapping, property resolving etc., use withUrl
parameter
on any query such as:
deliveryClient
.items<Movie>()
.withUrl('https://deliver.kontent.ai/da5abe9f-fdad-4168-97cd-b3464be2ccb9/items?system.type=movie')
.toPromise();
Custom parameters
In case you need to use custom parameters to build up an URL, use withParameter
method:
deliveryClient.items<Movie>().withParameter('name', 'value').toPromise();
Get localized items
You can specify language of items with
languageParameter
of a particular query. You can also define default language that will be used if languageParameter
is not used during the initialization of delivery client.
import { createDeliveryClient } from '@kontent-ai/delivery-sdk';
var deliveryClient = new createDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>',
defaultLanguage: 'es'
});
deliveryClient.item('warrior').toPromise();
deliveryClient.item('warrior').languageParameter(`en`).toPromise();
Property name resolvers
Kontent.ai element codenames are always in lowercase and use underscore as a replacement for special characters.
Using underscores might not be what you want to use in your code. Maybe you want to use camelCase
, which is exactly
what you can do by registering a propertyNameResolver
. The following example converts first_name
element name to
firstName
.
import { ContentItem, Elements, createDeliveryClient } from '@kontent-ai/delivery-sdk';
type Actor = IContentItem<{
firstName: Elements.TextElement;
}>;
const deliveryClient = createDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>';
propertyNameResolver: (contentType, element) => {
if (element === 'first_name') {
return 'firstName';
}
return element;
}
});
Rather than registering all elements manually, you can also use one of the built-in property name resolvers: snakeCasePropertyNameResolver
, pascalCasePropertyNameResolver
& camelCasePropertyNameResolver
import { createDeliveryClient, snakeCasePropertyNameResolver, pascalCasePropertyNameResolver, camelCasePropertyNameResolver } from '@kontent-ai/delivery-sdk';
const deliveryClient = createDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>';
propertyNameResolver: camelCasePropertyNameResolver,
});
Preview mode
You can enable the preview mode either globally (when initializing the DeliveryClient) or
per query. In each case, you need to set previewApiKey
in the delivery client global configuration.
Enable preview mode globally
import { createDeliveryClient } from '@kontent-ai/delivery-sdk';
const deliveryClient = createDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>';
previewApiKey: '<YOUR_PREVIEW_API_KEY>',
defaultQueryConfig: {
usePreviewMode: true
}
});
Enable preview mode per query
deliveryClient
.items()
.queryConfig({
usePreviewMode: true
})
.toPromise();
Secure Delivery API
Using the Delivery API with secure access enabled
is recommend only when the request is not being executed on the client (browser) because otherwise you will expose the
API key publicly.
import { createDeliveryClient } from '@kontent-ai/delivery-sdk';
const deliveryClient = createDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>';
secureApiKey: '<YOUR_SECURE_ACCESS_KEY>',
defaultQueryConfig: {
useSecuredMode: true
}
});
As with preview mode, you can also override global settings on query level.
deliveryClient
.items()
.queryConfig({
useSecuredMode: true
})
.toPromise();
Image transformation
Use ImageUrlBuilder
for your image transformations on asset
URLs.
import { transformImageUrl } from '@kontent-ai/delivery-sdk';
const assetUrl = `https://assets-eu-01.kc-usercontent.com/ede994d8-bb05-01b5-9c33-8b65e7372306/4f45e0a8-4fc3-4143-a81f-55b7e4ce7daa/warrior.jpg`;
const transformedUrl = transformImageUrl(assetUrl)
.withDpr(2)
.withCompression('lossless')
.withQuality(4)
.withHeight(200)
.withWidth(100)
.getUrl();
Paging
All listing queries support automatic paging. To use automatic paging, use toAllPromise
extension method:
const response = await deliveryClient.items().limitParameter(5).toAllPromise();
Alternatively, you may also specify a maximum number of pages you want to get:
const response = await deliveryClient.items().limitParameter(5).toAllPromise({
pages: 3
});
Resolving rich text elements
Rich text elements in
Kontent.ai may contain linked items and components. For example, if you write a blog post, you might want to
insert a video or testimonial to a specific place in your article.
You need to define how these objects resolve to the HTML that will be rendered. This SDK provides you with few resolvers
that help you to transform the input HTML to your desired HTML, JSON or object.
Built-in resolvers provided by SDK:
Resolver | Description | Usage |
---|
RichTextHtmlResolver | Tranforms rich text HTML by replacing linked items, links or images with custom HTML | createRichTextHtmlResolver().resolveRichText(data) |
RichTextJsonResolver | Tranforms rich text HTML into JSON | createRichTextJsonResolver().resolveRichText(data) |
RichTextObjectResolver | Tranforms rich text HTML into javascript Object | createRichTextObjectResolver().resolveRichText(data) |
AsyncRichTextHtmlResolver | Async version of RichTextHtmlResolver | await createAsyncRichTextHtmlResolver().resolveRichTextAsync(data) |
Example use of RichTextHtmlResolver
import { createRichTextHtmlResolver, createDeliveryClient, linkedItemsHelper } from '@kontent-ai/delivery-sdk';
export type Movie = IContentItem<{
plot: Elements.RichTextElement;
}>;
export type Actor = IContentItem<{
firstName: Elements.RichTextElement;
}>;
const response = (await createDeliveryClient({ environmentId: '<YOUR_ENVIRONMENT_ID>' }).item<Movie>('itemCodename').toPromise()).data;
const richTextElement = response.item.plot;
const resolvedRichText = createRichTextHtmlResolver().resolveRichText({
element: richTextElement,
linkedItems: linkedItemsHelper.convertLinkedItemsToArray(response.data.linkedItems),
imageResolver: (imageId, image) => {
return {
imageHtml: `<img class="xImage" src="${image?.url}">`,
imageUrl: 'customUrl'
};
},
urlResolver: (linkId, linkText, link) => {
return {
linkHtml: `<a class="xLink">${link?.link?.urlSlug}</a>`,
linkUrl: 'customUrl'
};
},
contentItemResolver: (itemId, contentItem) => {
if (contentItem && contentItem.system.type === 'actor') {
const actor = contentItem as Actor;
return {
contentItemHtml: `<div class="xClass">${actor.elements.firstName.value}</div>`
};
}
return {
contentItemHtml: ''
};
}
});
const resolvedHtml = resolvedRichText.html;
Example use of RichTextJsonResolver
import { createRichTextHtmlResolver, createDeliveryClient, linkedItemsHelper } from '@kontent-ai/delivery-sdk';
const response = (await createDeliveryClient({ environmentId: '<YOUR_ENVIRONMENT_ID>' }).item<Movie>('itemCodename').toPromise()).data;
const richTextElement = response.item.plot;
const json = createRichTextJsonResolver().resolveRichText({
element: response.item.elements.plot,
linkedItems: linkedItemsHelper.convertLinkedItemsToArray(response.data.linkedItems),
});
Resolving rich text in node.js
If you need to resolve rich text in node.js
, you have to install the following parser:
npm i @kontent-ai/delivery-node-parser --save
Once installed, it can be used by passing the parser to rich text resolver:
import { createRichTextHtmlResolver, createAsyncRichTextHtmlResolver } from '@kontent-ai/delivery-sdk';
import { nodeParser, asyncNodeParser } from '@kontent-ai/delivery-node-parser';
const json = createRichTextHtmlResolver(nodeParser).resolveRichText(data);
const html = await createAsyncRichTextHtmlResolver(asyncNodeParser).resolveRichTextAsync(data);
Creating custom rich text resolvers
This SDK provides you with browserParser
which you can use to implement your own rich text resolver. A common usecase for creating custom resolvers is when you want to convert rich text element into, for example, react components
, angular commponents
or components in some other popular framework. The parser will take care of actually parsing html, while you can focus on creating specific logic for creating components dynamically.
Get content types
To retrieve information about your content types, you can use the type
and types
methods.
deliveryClient
.type('movie')
.toPromise();
deliveryClient.types().toPromise();
deliveryClient.types().toAllPromise();
Get taxonomies
To retrieve information about your taxonomies, you can use the taxonomy
and taxonomies
methods.
deliveryClient
.taxonomy('taxonomyGroupName')
.toPromise();
deliveryClient.taxonomies().toPromise();
deliveryClient.taxonomies().toAllPromise();
Proxy configuration
If you want to use a proxy server, you need to use a different domain or otherwise transform the URL. By using proxy
configuration option you can define your own base domains as well as URL format. This is useful if you need to for
example hide the environmentId
from the URL.
IDeliveryClientProxyConfig
offers 3 ways of configuring proxy URL:
baseUrl
- Base URL used for all requests. Defaults to 'deliver.kontent.ai'basePreviewUrl
- Base url used for preview requests. Defaults to 'preview-deliver.kontent.ai'advancedProxyUrlResolver
- Resolver function where you get IProxyUrlData
context data (includes domain, action,
query parameters..) and can fully customize the final URL.
Examples:
const client = createDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>',
proxy: {
baseUrl: 'http://my-proxy.io'
}
});
const client = createDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>',
proxy: {
advancedProxyUrlResolver: (data) => {
const action = data.action;
const domain = data.domain;
const environmentId = data.environmentId;
const queryString = data.queryString;
const queryParameters = data.queryParameters;
const queryConfig = data.queryConfig;
return `http://my-proxy.io${action}${queryString}`;
}
}
});
Error handling
If the error originates in Kontent.ai (see error responses), you will get a DeliveryError
object
instance with more specific information. Otherwise, you will get the original error.
import { DeliveryError } from '@kontent-ai/delivery-sdk';
try {
await deliveryClient.item('invalid_codename').toPromise();
} catch (error) {
if (error instanceof DeliveryError) {
console.log(err.message, err.errorCode);
} else {
console.log(error);
}
}
Remapping json responses
In some scenarios, you might want to store json
response for later use and use SDK to map the response for you. There are 2 ways you can map previously stored json
:
const result = await deliveryClient.item<Movie>('codename').toPromise();
const json = result.response.data;
const remappedData = deliveryClient.mappingService.viewContentItemResponse<Movie>(json);
const remappedData = deliveryClient.item<Movie>(movieCodename).map(json);
Handling circular references
By default, the SDK automatically maps content items present in linked items
& rich text
elements. Linked items can reference other linked items in their tree (e.g. child item referencing parent) which may cause infinite nesting (circular reference). This behavior is not an issue for most scenarios, in fact it is beneficial as you can easily access all linked items. However, you cannot easily serialize such model. Using e.g. JSON.stringify
would fail if there are circular references.
For this reason, you may disable mapping of linked items with linkedItemsReferenceHandler
configuration option.
const client = getTestDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>',
linkedItemsReferenceHandler: 'ignore'
});
Using custom HTTP service
The SDK allows you to inject your own instance of a class implementing the IHttpService
interface. This way you can
easily mock responses, implement your own http service, or modify the requests in some other way.
Sample of a test HttpService
implementation can be found at https://github.com/kontent-ai/core-sdk-js
Once you have your HttpService
, use it in delivery client initialization:
const deliveryClient = createDeliveryClient({
environmentId: '<YOUR_ENVIRONMENT_ID>',
httpService: YourHttpServiceImplementation
});
Debugging
Accessing request data
Every response from this SDK contains additional debug data you can use to inspect when something is not right or if you
need to access response headers or other network related properties.
const deliveryResponse = await createDeliveryClient({ environmentId: 'environmentId' }).item('itemCodename').toPromise();
const rawResponseData = deliveryResponse.response;
const responseHeaders = deliveryResponse.response.headers;
Getting URL of a query
In case you need to get the raw URL of a request before calling it, use the getUrl()
method on any query.
const queryText = deliveryClient
.items()
.type('movie')
.limitParameter(10)
.orderParameter('system.codename', 'desc')
.getUrl();
console.log(queryText);
Upgrade
The major version 11.0.0
is pretty much a complete overhaul of this SDK with many breaking changes. The major benefits
of 11.0.0
are:
- Greatly reduced package size (from
~318KB
to ~95KB
). When Gzipped, this library is now only ~19KB
- Reduced complexity by removing
rxjs
as not everyone needs to use it - Removed classes in favor of interfaces (again to reduce the size of the library)
- Automatic paging support for all listing queries
- Improved resolving of rich text elements along with the
async
support - Simplified custom models without the need of
typeResolvers
- Better retry strategy options
- More extension methods added for all queries that support it (feed listing, content type listing etc..)
- Removal of duplicate
raw
data to reduce the size of mapped responses while still being able to easily access debug
data with typed network response - Simplified mapping of
json
data to SDK response (when you for example store json
in cache and need to re-map it
later on) - Updated all dependencies
If you are upgrading from an older version, please see this documentation first. If you are still unsure how to upgrade or
have some other questions, feel free to submit an issue on this GitHub and we'll get back to you.
Testing
Note: You need to have Chrome
installed in order to run tests via Karma.
npm run test:browser
Runs tests in Chromenpm run test:node
Runs tests in node.jsnpm run test:all
Runs all test
If you want to mock http responses, it is possible to use
custom Http Service as a part of the
delivery client configuration.
Feedback & Contribution
Feedback & Contributions are welcomed. Feel free to take/start an issue & submit PR.