Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

dc-delivery-sdk-js

Package Overview
Dependencies
Maintainers
0
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dc-delivery-sdk-js

Amplience Dynamic Content Delivery SDK

  • 0.13.0
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
16K
increased by26.74%
Maintainers
0
Weekly downloads
 
Created
Source

dc-delivery-sdk-js

Official Javascript SDK for the Amplience Dynamic Content Delivery API

npm version

This SDK is designed to help build client side and server side content managed applications.

Features

So we can have nice things:

  • ES6 module & tree-shaking support for tools capable of using ES6 imports (like Rollup, Webpack, or Parcel)
  • Backwards compatibility for Node.js-style (CommonJS) imports
  • TypeScript type definitions
  • Universal Module Definition (UMD) to support direct use in the browser

Installation

Using npm:

npm install dc-delivery-sdk-js --save

Using cdn:

<script src="https://unpkg.com/dc-delivery-sdk-js/dist/dynamicContent.browser.umd.min.js"></script>

for legacy browsers:

<script src="https://unpkg.com/dc-delivery-sdk-js/dist/dynamicContent.browser.umd.legacy.min.js"></script>

Usage

This SDK supports browser and Node.js applications using ES6 or CommonJS style imports.

ES6:

import { ContentClient } from 'dc-delivery-sdk-js';

const client = new ContentClient({
  hubName: 'myhub',
});

CommonJS:

const ContentClient = require('dc-delivery-sdk-js').ContentClient;

const client = new ContentClient({
  hubName: 'myhub',
});

If your application does not use a package manager you can directly include the pre-bundled version of the SDK and access the features using the global "ampDynamicContent".

<script src="https://unpkg.com/dc-delivery-sdk-js/dist/dynamicContent.browser.umd.min.js"></script>
const client = new ampDynamicContent.ContentClient({
  hubName: 'myhub',
});

If you need to support old browsers a legacy version of the bundle is provided, however we strongly recommend using a tool like babel in your project to compile the SDK to your exact browser requirements.

Configuration options

OptionDescription
accountContent Delivery 1 API - Required* - Account to retrieve content from
hubNameContent Delivery 2 API - Required* - hubName to retrieve content from - finding the hub name
apiKeyFresh API - Required* - API key required for use with the Fresh API service. hubName must also be set
retryConfigAllows override of the default retry configuration used by the Fresh API client
stagingEnvironmentIf set, the SDK will request content and media from the staging environment host name specified.
localeIf set, the SDK will request content using the locale settings provided.
mediaHostAllows users with custom hostnames to override the hostname used when constructing media URLs.
secureMediaHostAllows users with custom hostnames to override the hostname used when constructing secure media URLs.
baseUrlOverride for the content delivery API base URL
adaptorAllows custom handling of requests which makes testing and supporting non-standard environments easier.
timeoutIf set, requests made will timeout after the number of milliseconds specified.

* see Content Delivery versions

Content Delivery versions

In order to use the client, it must be configured with either account or hubName. If apiKey is set a Fresh API client will be created.

If account & hubName are supplied, the SDK will only use the Content Delivery 2 API. If hubName and apiKey are supplied, the SDK will only use the Fresh API.

To create a Fresh API client both hubName and apiToken must be specified

Fetch content by delivery ID

Once your client is created you can request content for a slot or content item id. This will return a promise which will resolve to the JSON of your slot or content item. If no content is found with the provided id the promise will reject with an error.

const slotId = 'cb671f37-0a66-46c3-a011-54ce3cdff241';
client
  .getContentItemById(slotId)
  .then((content) => {
    console.log(content.body);
  })
  .catch((error) => {
    console.log('content not found', error);
  });

The format of the content object will be specific to your content types, which define the JSON structure of content items and slots, however a set of standard metadata is always included in a property called "_meta".

If the slot or content item requested returns a graph of content, for example a carousel may also return linked slides, these will be included inline in the JSON.

Example:

{
  "_meta": {
    "schema": "https://www.anyafinn.online/content-types/carousel.json",
    "deliveryId": "543246b7-5948-4849-884c-b295402a95b4",
    "name": "example-carousel"
  },
  "slides": [
    {
      "_meta": {
        "schema": "https://www.anyafinn.online/content-types/slide.json",
        "deliveryId": "d6ccc158-6ab7-48d0-aa85-d9fbf2aef000",
        "name": "example-slide"
      },
      "heading": "Free shipping until Sunday!"
    }
  ]
}

Fetch content by delivery key (Content Delivery 2 and Fresh API only)

Note: Fetching content by delivery key via getContentItemByKey() is only supported when using Content Delivery 2 or Fresh API

Once you have set a delivery key for a slot or content item, the content item must be published before it can be retrieved using this SDK.

The getContentItemByKey() method will return a promise which will resolve to the JSON of your slot or content item. If no content is found with the provided key the promise will reject with an error.

const client = new ContentClient({
  hubName: 'myhub',
});

const slot = 'homepage-banner-slot';
client
  .getContentItemByKey(slot)
  .then((content) => {
    console.log(content.body);
  })
  .catch((error) => {
    console.log('content not found', error);
  });

The format of the content object will be specific to your content types, which define the JSON structure of content items and slots, however a set of standard metadata is always included in a property called "_meta" along with the deliveryKey on content items that have it defined.

If the slot or content item requested returns a graph of content, for example a carousel may also return linked slides, these will be included inline in the JSON.

The delivery key

Example:

{
  "_meta": {
    "schema": "https://www.anyafinn.online/content-types/carousel.json",
    "deliveryId": "543246b7-5948-4849-884c-b295402a95b4",
    "deliveryKey": "homepage-banner-slot",
    "name": "example-carousel"
  },
  "slides": [
    {
      "_meta": {
        "schema": "https://www.anyafinn.online/content-types/slide.json",
        "deliveryId": "d6ccc158-6ab7-48d0-aa85-d9fbf2aef000",
        "name": "example-slide"
      },
      "heading": "Free shipping until Sunday!"
    }
  ]
}

Filtering Content Items

Note: Filtering content via filterBy() | filterByContentType() | filterByParentId() | filterContentItems() is only supported when using Content Delivery 2 or Fresh API.

Filtering by Content Type or Parent ID is enabled by default. You can also filter by any other field in your schema once you enable it.

Constructing a request

The filterBy() | filterByContentType() | filterByParentId() method will return a instance of the FilterBy class which has helper functions to construct a filterBy request.

filterByContentType() | filterByParentId() are helper methods.

client.filterByContentType('https://bigcontent.io/blog.json');
// is equivalent to this:
client.filterBy('/_meta/schema', 'https://bigcontent.io/blog.json');

client.filterByParentId('c6d9e038-591b-4ca2-874b-da354f5d6e61');
// is equivalent to this:
client.filterBy(
  '/_meta/hierarchy/parentId',
  'c6d9e038-591b-4ca2-874b-da354f5d6e61'
);

Calling request executes the request returning a Promise if no content is found an empty response object will be returned. If invalid options are provided it will reject with an error.

const client = new ContentClient({
  hubName: 'myhub',
});

const res = await client
  .filterByContentType('https://example.com/blog-post-filter-and-sort')
  .filterBy('/category', 'Homewares')
  .sortBy('readTime', 'DESC')
  .page(2)
  .request({
    format: 'inlined',
    depth: 'all',
  });

console.log(res);

The response from filterBy() | filterByContentType() | filterByParentId() | filterContentItems() will match the API response but with an added helper function if the next page is available under page.next().

{
  responses: [
    {
      content: {
        _meta: {
          name: 'Homewares blog post',
          schema: 'https://example.com/blog-post-filter-and-sort',
          deliveryKey: 'new/homeware-collection/about',
          deliveryId: '1024dc7a-f255-46a7-b374-be85081a562f',
        },
        title: 'All about our new homeware collection',
        category: 'Homewares',
        date: '2021-05-05',
        ranking: 4,
        description:
          'Our new homeware has just landed. Find out how you can fill your home with some exciting designs.',
        readTime: 5,
      },
    },
    {
      content: {
        _meta: {
          name: 'Summer collection blog',
          schema: 'https://example.com/blog-post-filter-and-sort',
          deliveryKey: 'new/summer-fashion/about',
          deliveryId: 'fb466729-b604-496f-be36-521013a752d2',
        },
        title: 'Our new summer collection blog',
        category: 'Homewares',
        date: '2021-05-05',
        ranking: 2,
        description: 'A sneak peak at our new summer collection',
        readTime: 4,
      },
    },
  ],
  page: {
    responseCount: 2,
    next: () => // next page
    nextCursor:
      'eyJzb3J0S2V5IjoiXCIgNUAmJTYwOTJiZjBhNGNlZGZkMDAwMWVhZTY3ZCIsIml0ZW1JZCI6ImFtcHByb2R1Y3QtZG9jOjg2Y2E2YjgxLTJkOGYtNDRiMi1iNGQ1LTFlZjU0MzgzMzMyMyJ9',
  },
}
Alternative constructing a filterBy request

We also provide a way of requesting by a request object which is identical to the the request above

const client = new ContentClient({
  hubName: 'myhub',
});

const res = await client.filterContentItems({
  filterBy: [
    {
      path: '/_meta/schema',
      value: 'https://example.com/blog-post-filter-and-sort',
    },
    {
      path: '/category',
      value: 'Homewares',
    },
  ],
  sortBy: {
    key: 'readTime',
    order: 'DESC',
  },
  page: {
    size: 2,
  },
  parameters: {
    format: 'inlined',
    depth: 'all',
  },
});

console.log(res);

Fetching hierarchies in a single request

Note: Fetching content via getByHierarchy() is only supported when using Content Delivery 2 or Fresh API. This method wraps the Hierarchies endpoint of CDv2 and allows the fetching of hierarchical content from it's root node.

client.getByHierarchy({rootId: '90d6fa96-6ce0-4332-b995-4e6c50b1e233'})

The response from the delivery service is then reconstructed from the flat data structure of the response into a content tree

{
  "content": {
    "_meta": {
      "name": "Root",
      "schema": "https://hierarchies.com",
      "hierarchy": {
        "root": true
      },
      "deliveryId": "90d6fa96-6ce0-4332-b995-4e6c50b1e233"
    },
    "propertyName1": "Root"
  },
  "children": [
    {
      "content": {
        "_meta": {
          "name": "A",
          "schema": "https://hierarchies.com",
          "hierarchy": {
            "parentId": "90d6fa96-6ce0-4332-b995-4e6c50b1e233",
            "root": false
          },
          "deliveryId": "1ebab07d-acd8-4e19-a614-ec632cdf95d5"
        },
        "propertyName1": "A"
      },
      "children": [
        {
          "content": {
            "_meta": {
              "name": "B",
              "schema": "https://hierarchies.com",
              "hierarchy": {
                "parentId": "1ebab07d-acd8-4e19-a614-ec632cdf95d5",
                "root": false
              },
              "deliveryId": "4db37251-0c86-4f45-ad8a-583ebf6efc80"
            },
            "propertyName1": "B"
          },
          "children": []
        },
        {
          "content": {
            "_meta": {
              "name": "C",
              "schema": "https://hierarchies.com",
              "hierarchy": {
                "parentId": "1ebab07d-acd8-4e19-a614-ec632cdf95d5",
                "root": false
              },
              "deliveryId": "68676cda-5ab2-4a5e-bcfb-58c5cf3eb8ed"
            },
            "propertyName1": "C"
          },
          "children": []
        }
      ]
    }
  ]
}

Fetching multiple Content Items or Slots in a single request

Note: Fetching content via getContentItemsById() | getContentItemsByKey() | getContentItems() | fetchContentItems() is only supported when using Content Delivery 2 or Fresh API.

Wraps /content/fetch endpoint. Additional documentation.

Get content items by delivery ID

Fetch multiple by delivery id e.g.,

client.getContentItemsById([
  'd6ccc158-6ab7-48d0-aa85-d9fbf2aef000',
  'b322f84a-9719-42ff-a6a0-6e2924608d19',
]);
Get content items by key

Fetch multiple by delivery key e.g.,

client.getContentItemsByKey(['blog/article-1', 'blog/article-2']);
Get content items

Less verbose version of fetchContentItems allowing fetching of content by both delivery keys and ids as well as per request parameters and global parameter overrides

client.getContentItems([{
  key: 'blog/article-1', overrides: {locale: 'en-US'}
  key: 'blog/article-2'
}], {locale: 'en'});
Fetch content items

Allows full construction of the request body.

client.fetchContentItems({
  requests: [{
    key: 'blog/article-1', overrides: {locale: 'en'}
    key: 'blog/article-2'
  }],
  parameters: {depth: 'root'}
});

Preview staging content

By default, the content client will request content from the production content delivery services. When a user wants to preview content before it is published you can re-point the client to a virtual staging environment (VSE):

const client = new ContentClient({
  account: 'myaccount',
  stagingEnvironment: 'fhboh562c3tx1844c2ycknz96.staging.bigcontent.io',
});

Dynamic Content generates a VSE for each user and typically passes the "stagingEnvironment" value into your application using a URL parameter. This allows each user to effectively have their own staging environment which allows content producers to work in parallel.

Previewing staging content for a given Snapshot or at a given point in time (time machine)

You can use the StagingEnvironmentFactory to generate a new staging environment that is 'pinned' to a Snapshot or a timestamp, which then can be passed into the ContentClient.

Previewing content for a given Snapshot:

const factory = new StagingEnvironmentFactory(
  'fhboh562c3tx1844c2ycknz96.staging.bigcontent.io'
);
const stagingEnvironmentAtSnapshot = await factory.generateDomain({
  snapshotId: 'abcdef123456',
});

const client = new ContentClient({
  account: 'myaccount',
  stagingEnvironment: stagingEnvironmentAtSnapshot,
});

Previewing content at a given timestamp (epoch milliseconds):

const factory = new StagingEnvironmentFactory(
  'fhboh562c3tx1844c2ycknz96.staging.bigcontent.io'
);
const stagingEnvironmentAtTimestamp = await factory.generateDomain({
  timestamp: 1546264721816,
});

const client = new ContentClient({
  account: 'myaccount',
  stagingEnvironment: stagingEnvironmentAtTimestamp,
});

Localize content

Content types can make use of field-level localization to give content producers the ability to enter locale specific values for a field.

By default, every locale value will be returned in the content object:

{
  "_meta": {
    "schema": "https://www.anyafinn.online/content-types/slide.json",
    "deliveryId": "d6ccc158-6ab7-48d0-aa85-d9fbf2aef000",
    "name": "example-slide"
  },
  "heading": {
    "_meta": {
      "schema": "http://bigcontent.io/cms/schema/v1/core#/definitions/localized-value"
    },
    "values": [
      {
        "locale": "en-US",
        "value": "Free shipping until Sunday!"
      },
      {
        "locale": "de-de",
        "value": "Kostenloser Versand bis Sonntag!"
      }
    ]
  }
}

If desired, you can configure the SDK with a locale query. If set, the locale matching is performed server side and only a single value will be returned.

const client = new ContentClient({
  account: 'myaccount',
  locale: 'en-US,en-*',
});

Returns

{
  "_meta": {
    "schema": "https://www.anyafinn.online/content-types/slide.json",
    "deliveryId": "d6ccc158-6ab7-48d0-aa85-d9fbf2aef000",
    "name": "example-slide"
  },
  "heading": "Free shipping until Sunday!"
}

Transform images

In addition to serving image and Video content, Dynamic Content can also transform media on the fly allowing you to target multiple channels and deliver just the pixels required from a single master asset.

The SDK attaches helper functions to Image and Video properties to simplify constructing Dynamic Media URLs:

const ImageFormat = require('dc-delivery-sdk-js').ImageFormat;

const imageUrl = content.body.imageProperty
  .url()
  .width(500)
  .height(500)
  .sharpen()
  .format(ImageFormat.WEBP)
  .build();

See the SDK reference documentation for further details.

Transform content

Using the Content Rendering Service, you can convert the JSON content into any format you choose by applying a template previously setup in the back-office. This is typically used to convert content into fragments of HTML, XML or even rewrite the JSON.

client
  .renderContentItem('b322f84a-9719-42ff-a6a0-6e2924608d19', 'templateName')
  .then((response) => {
    console.log(response.body);
  })
  .catch((error) => {
    console.log('unable to find content', error);
  });

Advanced

Override Fresh API retry configuration

By default, if a 429 status code is received the SDK will retry up to 3 more times using exponential backoff. The configuration options below may be overridden.

NameTypeDefaultDescription
retriesNumber3The number of times to retry before failing.
retryDelayFunctionexponentialDelayA callback to further control the delay in milliseconds between retried requests. By default there is an exponential delay between retries (Exponential Backoff). The function is passed retryCount and error.
retryConditionFunctionisThrottledA callback to further control if a request should be retried. By default, it retries if the response status is 429.

Detecting content types

When displaying content you may need to detect the content type to decide which UI widget should be used to display the content.

Every content item in the body includes a built-in property _meta.schema which identifies the content type that was used to create that fragment of content. This can be used by your application to influence how the content is processed.

Example:

{
  "_meta": {
    "schema": "https://www.anyafinn.online/content-types/slot.json",
    "deliveryId": "62ece7d6-b541-411c-b776-0a6704ede1fb",
    "name": "homepage-hero"
  },
  "slotContent": {
    "_meta": {
      "schema": "https://www.anyafinn.online/content-types/banner.json",
      "deliveryId": "28583572-c964-4755-825b-044718312a29",
      "name": "example-banner"
    },
    "heading": "Free shipping until Sunday!"
  }
}
import React from 'react';
import { Banner, Carousel, Empty } from './components';

class App extends React.Component {
  //...

  getComponentForContentType(contentItem) {
    switch (contentItem._meta.schema) {
      case 'https://www.anyafinn.online/content-types/banner.json':
        return Banner;
      case 'https://www.anyafinn.online/content-types/carousel.json':
        return Carousel;
      default:
        return Empty;
    }
  }

  render() {
    const slotContent = this.props.content.slotContent;
    const TagName = this.getComponentForContentType(slotContent);
    return <TagName content={slotContent} />;
  }
}

Strongly typed content

Applications that support TypeScript can optionally create interfaces to represent content types within the code. This can be passed as a generic parameter when loading content which will result in a typed content body.

interface Banner extends ContentBody {
  heading: string;
}

client.getContentItem<Banner>('ec5d12cc-b1bb-4df4-a7b3-fd7796326cfe');
interface BlogPost {
  title: string;
  category: string;
  date: string;
  ranking: number;
  description: string;
  readTime: number;
}

const res = await client
  .filterByContentType<BlogPost>(
    'https://example.com/blog-post-filter-and-sort'
  )
  .request();

console.log(res);

Custom media CNAMEs

If you have previously configured custom CNAMEs for your media hosting, you can override the hostname used by the SDK when constructing image URLs as shown below:

const client = new ContentClient({
  account: 'myaccount',
  mediaHost: 'images.mybrand.com',
  secureMediaHost: 'images.mybrand.com',
});

Documentation

Please use the following documentation resources to assist building your application:

Getting Help

If you need help using the SDK please reach out using one of the following channels:

License

This software is licensed under the Apache License, Version 2.0,

Copyright 2019-2021 Amplience

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

FAQs

Package last updated on 30 Oct 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc