Skip to main content

Adding Contentstack data

tip

This tutorial assumes you have completed the basic tutorial and have the artifacts from that already present in Uniform.

Let's add some content data from Contentstack into your Uniform Canvas-powered Next app. To do this we will need to add a new Contentstack-powered parameter to your component type, and then tell your Next app how to fetch and parse the Contentstack data to display it. Canvas provides a framework for enhancing data in your Canvas composition with data from other tools, like CMSes, DAMs, commerce, and search indexes. This enhancement is done on the app side, leaving full flexibility to the developer as to the best and most efficient way to get the data.

First let's connect Uniform to Contentstack by installing the integration. You'll need a Contentstack account to do this (a free one is fine).

  1. Go to Settings on your on https://uniform.app project, then click Integrations
  2. Find the Contentstack integration and add it
  3. Click Log in to Contentstack and enter your Contentstack credentials
  4. Choose the Organization, Stack, and Environment that you want to bring content from into Canvas

Now that we're connected to Contentstack, we can add a new parameter to our Canvas component type that links to a Contentstack entry.

  1. Go to your Component Library settings
  2. Open your component type (there should be only one, if you've been following along)
  3. Click (+) next to Parameters
  4. Name your parameter something like 'Contentstack Entry', choose Contentstack Entry Selector as the type, pick Contentstack content type(s) that can be linked, and as before choose a public ID to use as the name in code. (e.g. contentstackEntry)

Now that the parameter is added to the component type, we need to link the composition we have been rendering to an actual Contentstack entry:

  1. Click Compositions, then open your composition from earlier
  2. You should see a Contentstack parameter alongside the text parameter we created before
  3. Choose a Contentstack entry to link to and save your composition
  4. That's it - you've linked to a Contentstack entry in your composition

With the data schema setup complete, now let's set up Next.js. Right now we're doing nothing with the Contentstack data - the Next app will look exactly the same as it did before, except it has a new parameter we're doing nothing with. To get the Contentstack data, we need to add an enhancer to the Next app's data fetching so that Canvas knows what to do with Contentstack parameters.

  1. If you do not already have a Contentstack delivery API token, create one in Contentstack for the Stack and Environment you selected in the Contentstack Canvas integration settings.

  2. Install the @uniformdev/canvas-contentstack and contentstack packages, which contains the Canvas Contentstack enhancer and the Contentstack JS SDK respectively.

  3. Open your pages/index.js file and import the Contentstack enhancer, and add enhance to the existing canvas import:

    import {
    createContentstackEnhancer,
    CANVAS_CONTENTSTACK_PARAMETER_TYPES,
    } from '@uniformdev/canvas-contentstack';
    import { enhance, CanvasClient, EnhancerBuilder } from '@uniformdev/canvas';
    import contentstack from 'contentstack';
  4. In getStaticProps, create the enhancer and configure it to connect to Contentstack and enhance your composition data:

    // ...fetching the composition here

    // create the Contentstack client
    const client = contentstack.Stack({
    // NOTE: for production code ensure you use environment variables to
    // configure Contentstack, not hard-coded values.
    api_key: 'your-contentstack-stack-api-key',
    delivery_token: 'your-contentstack-delivery-token',
    environment: 'your-contentstack-environment',
    // contentstack.Region.US || contentstack.Region.EU
    region: 'your-region',
    });

    // create the Contentstack enhancer
    const contentstackEnhancer = createContentstackEnhancer({ client });

    // apply the enhancers to the composition data, enhancing it with external data
    // In this case, the _value_ of the Contentstack parameter you created is enhanced
    // with data from the Contentstack entry you selected in the Contentstack entry selector.
    // You can create your own enhancers easily; they are a simple function.
    await enhance({
    composition,
    enhancers: new EnhancerBuilder().parameterType(
    CANVAS_CONTENTSTACK_PARAMETER_TYPES,
    contentstackEnhancer
    ),
    context: {},
    });

    // ...returning the props

    The Next app should still be working, but we're not rendering any of the Contentstack data yet. Let's do that!

  5. In the Home component implementation, get the Contentstack parameter value and pick a field from it:

    export default function Home({ composition }) {
    return (
    <Composition data={composition}>
    {/* note: `contentstackEntry` is the "public id" value you provided for
    the Contentstack Entry Selector parameter. */}
    {({ greeting, contentstackEntry }) => (
    <article>
    <p>{greeting}</p>
    {/* we assume your entry type has a field called 'title' on it */}
    <p>{contentstackEntry.title}</p>
    </article>
    )}
    </Composition>
    );
    }
  6. That's it - now you're rendering data from Contentstack! The default structure of the enhancer result is that of a single Contentstack entry fetched from the Contentstack Entry API.

tip

Use TypeScript? So do we. Here's the same code with TypeScript.

TypeScript Code
import { enhance, CanvasClient, EnhancerBuilder, ComponentInstance } from '@uniformdev/canvas';
import { Composition } from '@uniformdev/canvas-react';
import {
ContentstackEnhancerResult,
createContentstackEnhancer,
CANVAS_CONTENTSTACK_PARAMETER_TYPES,
} from '@uniformdev/canvas-contentstack';
import contentstack from 'contentstack';
import { GetStaticProps } from 'next';

type HomeProps = {
composition: ComponentInstance;
};

type MyCanvasComponentType = {
greeting: string;
contentstackEntry: ContentstackEnhancerResult<{ title: string }>;
};

export default function Home({ composition }: HomeProps) {
return (
<Composition<MyCanvasComponentType> data={composition}>
{({ greeting, contentstackEntry }) => (
<article>
<p>{greeting}</p>
<p>{contentstackEntry.title}</p>
</article>
)}
</Composition>
);
}

export const getStaticProps: GetStaticProps<HomeProps> = async () => {
// create the Canvas client
const canvasClient = new CanvasClient({
// if this weren't a tutorial, ↙ should be in an environment variable :)
apiKey: 'your-api-key-here',
// if this weren't a tutorial, ↙ should be in an environment variable :)
projectId: 'your-project-id-here',
});

// fetch the composition from Canvas
const { composition } = await canvasClient.getCompositionBySlug({
// if you used something else as your slug, use that here instead
slug: '/',
});

const client = contentstack.Stack({
api_key: 'your-contentstack-stack-api-key',
delivery_token: 'your-contentstack-delivery-token',
environment: 'your-contentstack-environment',
// contentstack.Region.US || contentstack.Region.EU
region: 'your-region',
});

const contentstackEnhancer = createContentstackEnhancer({ client });

await enhance({
composition,
enhancers: new EnhancerBuilder().parameterType(CANVAS_CONTENTSTACK_PARAMETER_TYPES, contentstackEnhancer),
context: {},
});

return {
props: {
composition,
},
};
};