CMSs are a crucial component in any developer’s stack. But a CMS may not include everything your project needs. Sometimes we need to mix and match data from CMSs and other data sources. With StepZen, you can easily mix data from an external CMS with your own project by incorporating StepZen’s custom directives.

Storyblok is a headless CMS that includes a visual editor and various APIs to access your content. It gives your team the ability to manage content for multiple use-cases including corporate websites, eCommerce sites, help desks, mobile apps, and screen displays. In this example we use StepZen's @graphql directive to connect to Storyblok's GraphQL API.

In addition to connecting to the Storyblok GraphQL API, we can also use StepZen's other custom directives to bring in data from any kind of REST endpoint we want. This example will include a Shopify backend to bring in products along with the blog posts from Storyblok.

You can find the code for this example on the StepZen Samples GitHub.

1. Create a Blog Post on Storyblok

Sign up for Storyblok

You can sign up for Storyblok at the following link.

Create a New Space

After signing up, you are asked whether you want to use a demo or create a new space. A space is a content repository for keeping all the content related to one project. Each space has its own components, datasources, assets, environments, domains, collaborators, and permissions.

01-choose-your-own-adventure

Choose to create a new space instead of playing with a demo so we can build up our content from scratch.

Storyblok Dashboard

After creating a new space you are taken to your Storyblok dashboard. You can manage your content here. Create a new folder and give your folder a name and slug, then create a new entry and use the Post content blueprint to create a blogpost.

02-create-your-first-entry

The post editor gives you the ability to create your blog post and include images, an intro, and an author.

03-post-editor-with-post-data

The JSON response looks like the following:

{
  "_uid": "ec395043-549c-43d5-a389-6e3334e1f35a",
  "component": "Post",
  "title": "My Super Awesome Post",
  "image": "//a.storyblok.com/f/122199/1920x1080/823e44a555/gorillas-shark-explosion-high-five-wallpaper.jpeg",
  "intro": "This is the intro to my super awesome post. It isn't a very long intro.",
  "long_text": {
    "type": "doc",
    "content": [
      {
        "type": "paragraph",
        "content": [
          {
            "type": "text",
            "text": "This is the long text of my super awesome post. It is slightly longer than the intro."
          }
        ]
      }
    ]
  },
  "author": ""
}

2. Connect to the Storyblok GraphQL API

You can find your API keys listed under the Settings tab. Use this token to access Storyblok's GraphiQL editor.

04-settings-api-keys

Storyblok GraphiQL Editor

Storyblok includes a GraphiQL editor similar to StepZen to explore your data. Include ?token=YOUR_TOKEN after the URL to access your specific content. Open the Explorer tab to see the different queries that are available. The queries include the content itself as well as information about your content and space.

05-graphiql-explorer

Send the following test query returning the title, intro, and long_text of the blog posts to make sure you are connected.

{
  PostItems {
    items {
      content {
        title
        intro
        long_text
      }
    }
  }
}

06-graphiql-query

3. Create a StepZen Project

Now that we have data in our CMS and our API key, we can create our StepZen project. Lets create schema files called storyblok.graphql and products.graphql along with the other files we need to setup our project including stepzen.config.json, config.yaml, and index.graphql.

mkdir -p stepzen-storyblok/schema
cd stepzen-storyblok
touch index.graphql schema/storyblok.graphql schema/products.graphql stepzen.config.json config.yaml

In this example there are only two files in the schema to show the base case of connecting to the CMS and an eCommerce backend. As your schema grows it is important to separate out the schema into separate files.

stepzen.config.json

stepzen.config.json gives you the ability to configure different aspects of your StepZen project such as the endpoint name or root directory. Include the following JSON object to specify that our endpoint is called api/stepzen-storyblok.

{
  "endpoint": "api/stepzen-storyblok"
}

If you do not have a stepzen.config.json file then the CLI asks for a name for your endpoint the first time you deploy your project with stepzen start.

index.graphql

index.graphql is the glue that pulls together all the other .graphql files in your schema. Our index.graphql file only includes two schema files called storyblok.graphql and products.graphql.

schema
  @sdl(
    files: [
      "schema/storyblok.graphql"
      "schema/products.graphql"
    ]
  ) {
  query: Query
}

config.yaml

config.yaml is a file written in YAML to relay information regarding your configuration and keys to StepZen. This is where we set our API token we received from Storyblok. Including storyblok_config in the @graphql query lets us authenticate our queries to the Storyblok GraphQL API.

configurationset:
  - configuration:
      name: storyblok_config
      token: <YOUR_TOKEN_HERE>
  - configuration:
      name: shopify_config
      api_key: <YOUR_API_KEY>
      api_password: <YOUR_API_PASSWORD>
      store_name: <YOUR_STORE_NAME>

Include your own token and information for your Shopify store.

storyblok.graphql

In our schema directory is a file called storyblok.graphql for our types and queries. Our types include a PostItem with a name for the post and a Content type for the title and intro of the post. The PostItems type returns an array of those PostItem objects.

type PostItems {
  items: [PostItem]
}

type PostItem {
  name: String
  content: Content
}

type Content {
  title: String
  intro: String
}

This example shows how to query for just a small subset of all the information available from the Storyblok GraphQL API. If you want to generate a complete schema without needing to code it by hand, you can introspect your endpoint with stepzen import graphql.

type Query {
  PostItems: PostItems
    @graphql(
      endpoint: "https://gapi.storyblok.com/v1/api"
      headers: [
        { name:"Token" value:"$token" }
      ]
      configuration: "storyblok_config"
    )
}

Our query includes the endpoint and sets the headers for our token. configuration includes our token from config.yaml.

Deploy your GraphQL API to StepZen

stepzen start deploys the code in your current directory to the specified endpoint on StepZen. It also watches the directory for changes and automatically deploys them to the endpoint specified.

stepzen start

Open a browser window to localhost:5000/api/stepzen-storyblok to see the StepZen Schema Explorer. This allows you to test your API by exploring the queries and types available and querying the API running on StepZen.

Test the Endpoint

Run the following test query for the intro and title of your post.

{
  PostItems {
    items {
      content {
        intro
        title
      }
    }
  }
}

This returns the information we created early in the Storyblok editor.

{
  "data": {
    "PostItems": {
      "items": [
        {
          "content": {
            "intro": "This is the intro to my super awesome post. It isn't a very long intro.",
            "title": "My Super Awesome Post"
          }
        }
      ]
    }
  }
}

4. Connect an eCommerce REST API

Now that we have connected our blog to our StepZen project, we can pull in products from an eCommerce backend by using the @rest directive. This example connects to Shopify and queries for a set of products.

products.graphql

products.graphql has a Product type and a products query that returns an array of Product objects. Our product type only has a few properties.

type Product {
  id: ID!
  handle: String
  title: String
}

Our products query connects to the Shopify REST API using StepZen's @rest directive. The @rest directive accepts the URL of the REST endpoint that we want to connect to.

type Query {
  products: [Product]
    @rest(
      resultroot: "products[]"
      endpoint: "https://$api_key:$api_password@$store_name.myshopify.com/admin/api/2020-01/products.json"
      configuration: "shopify_config"
    )
}

Query for Products and Posts

With our blog and shop connected into our main schema, we can query for both the blog posts and the products with a single query.

{
  PostItems {
    items {
      content {
        title
        intro
      }
    }
  }
  
  products {
    title
    id
    handle
  }
}

This returns the following output:

{
  "data": {
    "PostItems": {
      "items": [
        {
          "content": {
            "intro": "This is the intro to my super awesome post. It isn't a very long intro.",
            "title": "My Super Awesome Post"
          }
        }
      ]
    }
    "products": [
      {
        "handle": "this-is-a-product",
        "id": "661261903800",
        "title": "BUY ME"
      }
    ]
  }
}

Next Steps

With the two directives pulling in data from two completely separate backends, StepZen does the heavy lifting of merging the schemas together and providing the resolvers under the hood. This allows the developer to get all the data they need with just a single query.

Curious to learn more about Storyblok? You can see Facundo Giuliani and Anthony Campolo walk through creating content in Storyblok and connecting to StepZen in How to mix data from Storyblok CMS with your own project using StepZen.

You can sign up for StepZen here to give it a try. If you have more questions or just want to hang out you can also join us on our Discord.