# 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 in the Studio](/frontend-development/developing-a-data-source-extension.md#create-a-data-source-schema). 2. [Implement the data source extension](/frontend-development/developing-a-data-source-extension.md#implement-the-data-source-extension). 3. [Add the data source to the page folder](/frontend-development/developing-a-data-source-extension.md#add-the-data-source-on-a-page-folder). 4. [Create a Frontend component](/frontend-development/developing-a-data-source-extension.md#create-a-frontend-component). 5. [Add the Frontend component to the page version](/frontend-development/developing-a-data-source-extension.md#add-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: We recommend that you use our visual editor in the schema builder because it provides all the fields and options you need to input. - `customDataSourceType`: is required and must comply with the format `/`. You can use your company or project name as the `` 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](/frontend-development/schemas.md). 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. If you are not using the visual editor in the schema builder, then you can upload a schema in JSON format as shown here: ```json title="Star Wars movie data source schema" { "customDataSourceType": "example/star-wars-movie", "name": "Star Wars movie", "category": "Content", "icon": "stars", "schema": [ { "name": "Settings", "fields": [ { "label": "Movie ID", "field": "movieId", "type": "string", } ] } ] } ``` Copy and paste the schema in JSON format into the code editor, and then click **Publish**. If you include `dataSourceType` in your JSON, then you don't need to add it to the required field input. ### 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//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](https://swapi-graphql.netlify.app/) using the [Axios](https://github.com/axios/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. ```typescript title="Star Wars movie data source implementation" 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 => { if (!config.configuration.movieId) { return { dataSourcePayload: { ok: false, error: 'Movie ID is missing from the configuration.', }, } as DataSourceResult; } return await axios .post( '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](/frontend-studio/frontend-component-settings.md#data-source-filters), 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](https://imgur.com/) as the `image`. To learn more about data source preview in the Studio, see [Using the data source filter editor](/frontend-studio/using-the-data-source-filter-editor.md) and [Component settings](/frontend-studio/frontend-component-settings.md#data-source-filters). ```ts title="Add data source preview" // 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](/frontend-studio/page-folders.md) 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](/frontend-studio/page-folders.md#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](/frontend-studio/using-the-data-source-filter-editor.md) 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](/frontend-development/creating-a-frontend-component.md#create-a-frontend-component-schema). ```json title="Star Wars opening crawl Frontend component schema" { "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`. ```tsx title="index file of the Star Wars opening crawl Frontend component" import React from 'react'; const StarWarsOpeningCrawl = ({ data }) => { return ( {data.movieData.dataSource.data.film.openingCrawl} ); }; 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`. ```tsx title="Register StarWarsOpeningCrawl Frontend component" highlightLines="11" 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](/frontend-development/developing-a-data-source-extension.md#create-a-frontend-component) to the [page version](/frontend-studio/page-versions.md) 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](/frontend-studio/page-versions.md#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](/frontend-studio/using-the-page-builder.md) opens. 3. 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](/frontend-studio/using-the-page-builder.md#layout-section). 4. Use the [**Components** pane](/frontend-studio/using-the-page-builder.md#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. 5. 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**. 6. [Preview and save](/frontend-studio/using-the-page-builder.md#menu-bar) your changes. The Star Wars opening crawl is now rendered on your commercetools Frontend website. ![A preview page with a Star Wars opening crawl](https://docs.commercetools.com/frontend-development/images/migrated/2eeebf6-opening-crawl.png) ## 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](https://www.postman.com/), [HTTPie](https://httpie.io/), or [cURL](https://curl.se/). 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: - `Accept`: `application/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](/frontend-development/extensions.md#extension-runner). ```shell title="Example of cURL request to check a data source response" 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. ```json title="Example of a payload with a data source response" { "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" } } } } } } ... } ``` ## Related pages - [Area overview page with navigation](/frontend-development.md) - [Previous page: Overview](/frontend-development/extensions.md) - [Next page: Developing an action extension](/frontend-development/developing-an-action-extension.md)