Go to main content

Multiple requests to Kentico Kontent Delivery API in Node.js

In this article I will give you a code example that demonstrates how to make multiple endpoint requests and get one response object. 

Multiple requests to Kentico Kontent Delivery API in Node.js

In the Request Kentico Kontent Delivery API in Node.js article I have demonstrated how to get content from your Kentico Kontent project with the use of the Delivery API. The article describes how to make one endpoint request at a time. In the real world where you create websites in Node.js you probably need to request multiple endpoints to render a single page.

Imagine we have a website and need to render a page. The page consists of:

  • Master page which is content that is shared across all pages. E. g. navigation, company logo, and footer. 
  • Page specific content which is unique for each page.
  • Resource strings are small pieces of text that might be shared across multiple pages.

All of these elements are kept separate in our Kentico Kontent project because we don't want to have repetitions in our content storage. 

I would like to share an elegant approach to how to get all the data with a single method call. Imagine that we make a request with a simple object:

{
    masterPage: '?system.type=master',
    page: '?system.type=home',
    resourceStrings: '?system.type=resource_strings'
}

And get a response in the same format:

{
    masterPage: {items: [...]},
    page:{items: [...]},
    resourceStrings: {items: [...]}
}

Exactly this is possible with the code example below. I won't explain the code step by like I did in the previous article because the example in this article is just an enhanced version of the previous one. 

See live demo on Runkit.

const request = require('request'),
    requestPromise = require("request-promise"),
    Promise = require('bluebird');

'use strict';

/**
 * Initializes class with Project ID and Preview API Key that represent a Kentico Kontent project.
 * @constructor Delivery
 * @param {string} projectID Project ID.
 * @param {string} previewKey Preview API Key.
 * @example
 * var project = new Delivery('82594550-e25c-8219-aee9-677f600bad53', 'ew0KICAiYWxnIjo...QvV8puicXQ');
 */
class Delivery {
    constructor(projectID, previewKey) {
        this.projectID = projectID;
        this.previewKey = typeof previewKey === 'undefined' ? null : previewKey;
    }

    /**
     * Returns promise with data from the Kentico Kontent storage specified by the passed object of filtering URL parameters.
     * @method getContent
     * @param {object} params Object that contains filtering URL parameters that are used for requesting Kentico Kontent storage.
     * @param {boolean} isPreview Flag that controls whether only published or all items should be requested.
     * @return {promise} with an object of responses for each passed parameter from the Kentico Kontent storage.
     * @example
     * // returns
     * // {
     * //   master: {items: [...]},
     * //   page: {items: [...]}
     * // }
     * project.getContent({
     *   master: '?system.type=master',
     *   page: '?system.type=home'
     * }, true)
     */
    getContent(params, isPreview) {
        // Reject operation if params parameter in not provided
        if (typeof params === 'undefined') {
            Promise.reject('Please, specify the params parameter in the getContent method.');
        }

        // Set default state if maethod parameter are not provided
        if (typeof isPreview === 'undefined') {
            isPreview = false;
        }

        // Split categories and filtering urls in separate arrays
        var categories = [],
            values = [];

        Object.keys(params).forEach((key, index) => {
            categories.push(key);
            values.push(params[key]);
        });

        params = values.slice();

        // Create options that will represent your request to the Kentico Kontent storage
        let options = Delivery.getOptions(params, this.projectID, this.previewKey, isPreview);

        // Request the Kentico Kontent storage and get content from it
        return Delivery.getRawData(options)
            .then(function(data) {
                // And assemble an object structure of the original object
                return Delivery.categorizeContent(data, categories);
            })
            .catch(console.error);
    }


    /*
     * Helper methods section
     */

    // Retrun array of promises with objects obtained from the Kentico Kontent storage
    static getRawData(options) {
        return Promise.map(options, (item) => {
            return requestPromise(item).catch(console.error);
        });
    }

    // Return url that should be requested
    static getDeliveryUrl(projectID, isPreview) {
        let url = '';

        // If we want to preview our content we need request a slightly different url
        if (isPreview) {
            url = 'https://preview-deliver.kontent.ai/' + projectID + '/items';
        } else {
            url = 'https://deliver.kontent.ai/' + projectID + '/items';
        }

        return url;
    }

    // Returns options for the request
    // Structure of the options object is defined by the request-promise package (https://www.npmjs.com/package/request-promise)
    static getOptions(params, projectID, previewKey, isPreview) {
        var options = [];

        // Create request options of each param
        if (isPreview && previewKey !== null) {
            params.forEach((item) => {
                options.push({
                    uri: Delivery.getDeliveryUrl(projectID, isPreview) + item,
                    json: true,
                    simple: false,
                    headers: {
                        Authorization: 'Bearer ' + previewKey
                    }
                });
            });
        } else {
            params.forEach((item) => {
                options.push({
                    uri: Delivery.getDeliveryUrl(projectID, isPreview) + item,
                    json: true,
                    simple: false
                });
            });
        }

        return options;
    }

    // Join array of category names and array of responses to fit the original object structure
    static categorizeContent(content, categories) {
        let categorizedContent = {};

        content.forEach((item, index) => {
            categorizedContent[categories[index]] = item;
        });

        return categorizedContent;
    }
};


/*
 * Usage
 */

// Initialize Delivery with Project ID and Preview API Key
let kenticoKontentProject = new Delivery('2548121d-cad8-4458-a910-5e4b54cb0956', 'ew0KICAiYWxnIjogIkhTMjU2IiwNCiAgInR5cCI6ICJKV1QiDQp9.ew0KICAidWlkIjogInVzcl8wdlVJVzkwTnRQSVNxNm1GSDN2ZFhiIiwNCiAgImVtYWlsIjogImhlbGxvQG1pbGFubHVuZC5jb20iLA0KICAicHJvamVjdF9pZCI6ICIyNTQ4MTIxZC1jYWQ4LTQ0NTgtYTkxMC01ZTRiNTRjYjA5NTYiLA0KICAianRpIjogInhrU1BLUjlzbzgxSV9rel8iLA0KICAidmVyIjogIjEuMC4wIiwNCiAgImdpdmVuX25hbWUiOiAiTWlsYW4iLA0KICAiZmFtaWx5X25hbWUiOiAiTHVuZCIsDQogICJhdWQiOiAicHJldmlldy5kZWxpdmVyLmtlbnRpY29jbG91ZC5jb20iDQp9.PpBh6wTk57e1_tPHzROiqWPTpr3IjrEoGN8J4rtfPIg');

// Request the Kentico Kontent storage with filtering url parameters and a boolean flag defining whether you want preview content or not
kenticoKontentProject.getContent({
        master: '?system.type=master',
        page: '?system.type=home'
    }, true)
    .then(console.log) // Show results
    .catch(console.error); // Or error

Further reading

all posts
  • Kentico EMS & Xperience

    Safe attachment URLs resolution in srcset attribute in Page Builder in Kentico Xperience

    In this post, I will provide you with a quick tip on how to fix the attachment URLs resolution in srcset attribute in Page Builder in Kentico Xperience.

  • Front-end & JavaScript

    Simple cookie bar

    EU cookie legislation requires website owners to inform visitors about the use of cookies. In this article, I will provide you with a simple solution of an informative cookie bar.

  • Front-end & JavaScript

    Simple scroll parallax

    Recently, a designer asked me to add a parallax background image on a website. I researched the web to find a suitable solution. Regrettably, I found only massive libraries that wo…