Developing a data source extension

A data source extension makes data available to your website. A data source extension:

  • Can be configured and influenced from the Studio.

  • Is available during the server-side rendering phase and immediately after the website loads.

  • Can be connected simultaneously to multiple Frontend components on the same page by de-duping requests automatically.

In this document, for demonstration purposes, you will create a data source to retrieve data from the Star Wars API and display the information on your website.

Develop a data source extension

To develop a data source extension and connect it to your website, follow these steps:

  1. Create a data source schema.
  2. Upload the data source schema to the Studio.
  3. Implement the data source extension.
  4. Add the data source to the page folder.
  5. Create a Frontend component.
  6. Add the Frontend component to the page version.

Create a data source schema

A data source schema specifies the information about the data source and its configuration. The Studio uses this schema to present the available configuration options to the users.

A data source schema requires the following fields:

  • customDataSourceType: is required and must comply with the format <vendor>/<identifier>. You can use your company or project name as the <vendor> and use a speaking identifier for the data source.

  • name: specifies how the data source is referenced in the Studio and should be understandable for Studio users. The category and icon are specific schema fields for visualization in the Studio.

  • category: specifies the clustering of the data source in the Studio.

  • icon: specifies the name of the icon associated with the data source in Studio.

  • schema: contains a list of configuration sections, each containing some schema fields. For further information on schema fields, see Schemas.

In this example, we create an example/star-wars-movie data source that exposes a single input field (Movie ID) where a Studio user can enter the ID of a Star Wars movie episode. The API hub passes this configuration to the data source during server-side rendering, and the data source will then fetch information about the selected movie from the Star Wars movie API.

Star Wars movie data source schemajson
{
"customDataSourceType": "example/star-wars-movie",
"name": "Star Wars movie",
"category": "Content",
"icon": "stars",
"schema": [
{
"name": "Settings",
"fields": [
{
"label": "Movie ID",
"field": "movieId",
"type": "string",
"translatable": false
}
]
}
]
}

Upload the data source schema to the Studio

To upload the data source schema to the Studio, follow these steps:

  1. From the Studio home page or from the left menu, go to Developer > Data sources.

  2. Click Create schema.

  3. Copy the data source schema you created and paste it into the schema editor.

  4. Click Validate.

    If you include the dataSourceType in your JSON, you don't need to add it to the required field input.

  5. Click Publish.

Implement the data source extension

A data source extension is defined as a function with the config and context parameters and returns a value of type DataSourceResult.

To implement the data source extension, you must register the data source extension with its customDataSourceType value under the data-sources key of the default export in the packages/<project>/backend/index.ts file. For example, we are using example/star-wars-movie as the key in the data-sources object to register our extension.

In this example, we receive the Movie ID configured by the Studio user as the config.configuration.movieId. We use this value to create a GraphQL query to filter the list of movies. Then, we perform an HTTP request to the Star Wars movie API using the Axios library and return the received response as dataSourcePayload.

Executing API calls costs time and affects the performance of your website. Therefore, you should make as few calls as possible and execute them in parallel.

You should always validate the incoming configuration values because the Studio allows users to store configurations even if the required parameters are missing.

Star Wars movie data source implementationtypescript
import {
DataSourceConfiguration,
DataSourceContext,
DataSourceResult,
} from '@frontastic/extension-types';
import axios from 'axios';
export default {
'data-sources': {
'example/star-wars-movie': async (
config: DataSourceConfiguration,
context: DataSourceContext
): Promise<DataSourceResult> => {
if (!config.configuration.movieId) {
return {
dataSourcePayload: {
ok: false,
error: 'Movie ID is missing from the configuration.',
},
} as DataSourceResult;
}
return await axios
.post<DataSourceResult>(
'https://swapi-graphql.netlify.app/.netlify/functions/index',
{
query:
'{film(id:"' +
config.configuration.movieId +
'") {title, episodeID, openingCrawl, releaseDate}}',
}
)
.then((response): DataSourceResult => {
return {
dataSourcePayload: response.data,
} as DataSourceResult;
})
.catch((reason) => {
return {
dataSourcePayload: {
ok: false,
error: reason.toString(),
},
} as DataSourceResult;
});
},
},
};

Add preview data for the Studio

To display data source previews in the Studio, you must return a previewPayload property in the data source response.

The context.isPreview property of the data source is set to true when the Studio requests for the data source preview. You can use this property to conditionally return a previewPayload property in the response.

The previewPayload property must be an array of objects, each containing two properties:

  • title: the title to display for the item fetched from the data source.
  • image: the absolute URL of the image to display for the item fetched from the data source.

In this example, we will return the title of the movie and a URL of an image from Imgur as the image. To learn more about data source preview in the Studio, see Using the data source filter editor and Component settings.

Add data source previewTypeScript
// code above
.then((response): DataSourceResult => {
const payloadResult = {
dataSourcePayload: response.data,
}
return !context.isPreview ? payloadResult : {
...payloadResult,
previewPayload: [
{
title: response.data.film.title,
image: 'https://i.imgur.com/YbxTgoD.jpeg',
},
],
};
})
// rest of the code...

Add the data source on a page folder

Now you need to add the Star Wars movie data source to the page folder where you want to render the content, then you need to configure the data source filters.

To add the data sources to the page folder and configure the data source filters, follow these steps:

  1. If necessary, create a page folder. Otherwise, from the Studio home page or from the left menu, go to Site builder.

  2. In the page folder list, hold the pointer over the page folder where you want to render the content and click the Settings icon: the Page folder settings dialog opens.

  3. In the Data source section, click + Add data source filter: the list of the available data sources opens. From the list, you can select the Star Wars movie data source. When you select a data source, the data source filter editor opens.

  4. In the Movie ID field, enter the ID of the Star Wars movie. In this example, we enter ZmlsbXM6MQ==.

  5. Click Save.

Create a Frontend component

Now you need to create a Frontend component that renders the content fetched from the data source. In this example, we create the Frontend component that renders the Star Wars opening crawl.

To create a Frontend component, follow these steps:

  1. Create the Frontend component schemas by uploading the following schemas to the Studio.

    Star Wars opening crawl Frontend component schemajson
    {
    "tasticType": "example/star-wars-opening-crawl",
    "name": "Star Wars opening crawl",
    "icon": "movie_filter",
    "category": "general",
    "schema": [
    {
    "name": "Data source",
    "fields": [
    {
    "label": "Star Wars movie",
    "field": "movieData",
    "type": "dataSource",
    "dataSourceType": "example/star-wars-movie"
    }
    ]
    }
    ]
    }
  2. In your commercetools Frontend project, add the following index.tsx file under tastics/content/example/star-wars-opening-crawl.

    index file of the Star Wars opening crawl Frontend componentTypeScript React
    import React from 'react';
    const StarWarsOpeningCrawl = ({ data }) => {
    return (
    <marquee direction="up" style={{ whiteSpace: 'pre-wrap' }}>
    {data.movieData.dataSource.data.film.openingCrawl}
    </marquee>
    );
    };
    export default StarWarsOpeningCrawl;
  3. Register the index.tsx file for the example/star-wars-opening-crawl Frontend component in the index.tsx file under frontastic/tastics.

    Register StarWarsOpeningCrawl Frontend componentTypeScript React
    export const tastics = {
    ...
    'commercetools/ui/checkout': Checkout,
    'commercetools/ui/thank-you': ThankYou,
    'commercetools/ui/cart': Cart,
    'commercetools/ui/footer': Footer,
    'commercetools/ui/header': Header,
    'commercetools/ui/content/tile': Tile,
    'commercetools/ui/content/spacer': Spacer,
    'commercetools/ui/content/showcase': Showcase,
    'example/star-wars-opening-crawl': StarWarsOpeningCrawl,
    ...
    default: NotFound,
    };

Add Frontend component to the page version

Finally, you must add the Frontend components you created to the page version where you want to render the content. Thus, the data retrieved from the data source is rendered on the page version through the Frontend component.

To add the Frontend components to the page version, follow these steps:

  1. If necessary, create a page version. Otherwise, from the Studio home page or from the left menu, go to Site builder.

  2. Use the page folder list and the status sections to navigate to the page version where you want to add the Frontend component. Then, hold the pointer over the page version and click the Edit icon: the page builder opens.

  1. Edit the layout of the page version as you wish. In this example, we add a 1/1 layout element to the MAIN layout section.
  1. Use the Components pane to find the Frontend component to add. Then, drag it to the layout element. In this example, we drag the Star Wars opening crawl Frontend component to the 1/1 layout element.

  2. Select the Frontend component. Then, in Component settings > Content select the data source to associate to the Frontend component. In this example, we select Star Wars movie.

  3. Preview and save your changes. The Star Wars opening crawl is now rendered on your commercetools Frontend website.

    A preview page with a Star Wars opening crawl

Check the data source response

To check the data source response via HTTP API, you must have completed the previous steps. You must therefore have a page folder that is associated with the data source and that contains a page version. This page version must contain a Frontend component associated with the data source.

To check the response, use an HTTP client such as, Postman, HTTPie, or cURL.

From the HTTP client, send a GET request to https://EXTENSION_RUNNER_HOSTNAME/frontastic/page. The request must contain the following headers and query parameters.

  • Headers:
    • Acceptapplication/json
    • Commercetools-Frontend-Extension-Version: your Studio developer username.
  • Query parameters:
    • path: the path to the page folder you created. For example, /your-page-folder.
    • locale: a locale of your commercetools Frontend project. For example, en_US.

For information on the Commercetools-Frontend-Extension-Version header and the extension runner hostname, see Main development concepts.

Example of cURL request to check a data source responseshell
curl -X 'GET' -H 'Accept: application/json' -H 'Commercetools-Frontend-Extension-Version: STUDIO_DEVELOPER_USERNAME' 'https://EXTENSION_RUNNER_HOSTNAME/frontastic/page?path=/your-page-folder&locale=en_US'

The response body will be a JSON payload with a data key representing the page folder data, including the dataSources.dataSourcePayload property that is passed to the Frontend component connected to the data source.

Example of a payload with a data source responsejson
{
"data": {
"_type": "Frontastic\\Catwalk\\NextJsBundle\\Domain\\PageViewData",
"dataSources": {
"ac8a8700-6a84-4c02-9160-4fc2fced3fe9": {
"dataSourcePayload": {
"data": {
"film": {
"title": "A New Hope",
"episodeID": 4,
"openingCrawl": "It is a period of civil war.\r\nRebel spaceships, striking\r\nfrom a hidden base, have won\r\ntheir first victory against\r\nthe evil Galactic Empire.\r\n\r\nDuring the battle, Rebel\r\nspies managed to steal secret\r\nplans to the Empire's\r\nultimate weapon, the DEATH\r\nSTAR, an armored space\r\nstation with enough power\r\nto destroy an entire planet.\r\n\r\nPursued by the Empire's\r\nsinister agents, Princess\r\nLeia races home aboard her\r\nstarship, custodian of the\r\nstolen plans that can save her\r\npeople and restore\r\nfreedom to the galaxy....",
"releaseDate": "1977-05-25"
}
}
}
}
}
}
...
}