ButterCMS: A Headless CMS on Google Cloud Platform

By Brandon Nicoll, Software Engineer, ButterCMS

This tutorial explores creating and managing content for an example online store using ButterCMS, a fully managed headless content management system (CMS). You'll learn how to deploy your store app by using Google App Engine and examine some options for scaling and monitoring the app.

Web developers are often asked to build websites where other teams manage the content that is published. On the Earth Class Mail website, for example, web developers create and maintain the homepage, but the marketing team administers most of the content.

Traditionally, you might manage such content by using CMS templates. With respect to site development, design, and maintenance, your challenge is how to integrate the CMS-managed sections into the rest of the website. Now you have two systems to maintain: the CMS and the web framework you used to develop the main website. Moreover, in such systems, you would typically maintain a separate CMS admin site and database for the content editors to login and manage content.

A headless CMS solves these issues, by allowing you to feed CMS content into your existing website, in your existing framework and leveraging existing style assets. The primary difference from a traditional CMS is how the headless CMS retrieves and consumes content and data. With a traditional CMS, you rely on templates and plugins to assemble web pages. With a headless CMS, you retrieve relevant content using simple API calls, and integrate that content with a web framework to build rich, and fully customizable web pages. This difference decouples the content from the website, allowing content editors to make updates without needing to change templates and redeploy the site.

ButterCMS

ButterCMS, or simply "Butter," is a Software as a Service (SaaS) for headless CMS. Butter minimizes or eliminates the setup, configuration, and hosting of the CMS backend. Butter offers client libraries for most of the popular programming languages and frameworks used for web development. Using these client libraries, you can easily integrate managed content into your app. And if Butter doesn't support your preferred language or framework, it offers an easy-to-use REST API. In addition, Butter also provides a clean and simple UI for content editors.

App Engine

In this tutorial, you'll use App Engine to deploy your store app. App Engine is a fully-managed developer experience that makes it easy to deploy apps built using Node.js and many other web frameworks. It automatically scales the service in response to load and takes care of such operational concerns as provisioning, health checking, load balancing, and healing. App Engine lets you focus on writing code to create business value rather than on managing infrastructure.

Objectives

  • Use Node.js and ButterCMS to develop a simple backend service, or content service, that powers the website for an example store.
  • Develop a simple frontend for the website using Node.js and the content service.
  • Use App Engine to deploy the content service and the website.
  • Use App Engine to set up scaling for the website.
  • Use Stackdriver Monitoring to check the health of your content service and website.

Costs

This tutorial uses App Engine, which is a billable service. You can use the pricing calculator to estimate the costs for your projected usage. New Cloud Platform users might be eligible for a free trial.

Before you begin

  1. Select or create a Cloud Platform project.

    Go to the Projects page

  2. Enable billing for your project.

    Enable billing

  3. Install and initialize the latest version of the Google Cloud SDK:

    Download Google Cloud SDK
  4. Create a ButterCMS account.
  5. Prepare your environment for Node.js development.

    Go to the Setup Guide

Architecture overview

You use Butter to define and manage the content for the store website, and you use the Butter API to retrieve that content. A content service encapsulates the implementation details for communicating with the CMS to retrieve the content. The content service converts the content into a format that the website's presentation logic can consume. This logic communicates only with the content service and not with Butter. This decoupling allows you to keep the system extensible and maintainable. For example, you could combine content from different sources or swap Butter with another headless CMS simply by changing the content service and keeping the rest of the system unchanged.

Butter architecture

Managing content in Butter

To manage the dynamic content for the store website, you use a feature of Butter called collections. Collections are lists of user-defined objects, where each object encapsulates information about an individual entity. In this example, an object represents a product listed on the store website. Butter handles storing all the information and provides a UI where you can manage that information.

Create a workspace

Before you can create a collection, you first need to create a workspace. A workspace provides a framework for organizing the content and might represent individual pages or groups of related content.

  1. On the navigation menu in the Butter admin, click New Workspace.

    New Workspace

Create a collection

Now that you have a workspace, you can create a collection.

  1. In the workspace you just created, click New Content Field, and then click Collection.

    Collection

  2. In the Content Label field, enter a name for the collection and click Create.

    Content Label

  3. Define the properties for each product.

    product properties

  4. Click Add to Collection, where Collection is the name you specified in step 2.

    Add to collection

  5. Fill in the form fields and click Save. On the collection overview page, you'll see your newly added product.

    Collection overview

Edit content

After you've defined a collection and populated it with some initial data, the site's content editors can follow the same steps to change existing objects, add new objects, or remove objects that are no longer needed.

content editing

Creating a content service

This section assumes that you have installed Node.js and npm on your workstation. Unless instructed otherwise, you enter the following commands in a command shell on your workstation.

  1. Create a directory for your content service project:

    mkdir contentService

    cd contentService

  2. Initialize the project for Node.js:

    npm init
    
  3. Enter any relevant information when prompted.

  4. Install the npm packages buttercms and express: express is a web application framework, and buttercms is a client library for Butter's API.

    npm install express --save

    npm install buttercms --save

Implement the service

To implement the content service, you need your Butter API key.

  1. To find your key, sign in to your account and navigate to https://buttercms.com/settings/.
  2. In your text editor of choice, create a file server.js that will contain the code for the content service.
  3. In server.js enter the following, replacing YOUR KEY with your Butter API key:

    const express = require('express');
    const app = express();
    const butter = require('buttercms')(‘YOUR KEY');
    
    app.get('/hotproducts', function (req, res) {
      butter.content.retrieve(['hotproducts']).then(function(resp) {
        var hotProducts = resp.data.data;
        res.json(hotProducts);
      });
    })
    
    const PORT = process.env.PORT || 8080;
    app.listen(PORT, () => {
      console.log(`App listening on port ${PORT}`);
      console.log('Press Ctrl+C to quit.');
    });
    
  4. Start the server:

    node server.js
    

    If you direct your browser to http://localhost:8080/hotproducts, you will see the following JSON representation of the products you added earlier:

    {
       "hotproducts":[
          {
             "url":"https://store.example.com/tshirt",
             "description":"A t-shirt with Brandon on it",
             "productname":"Brandon T-Shirt",
             "previewimage":"https://cdn.buttercms.com/image1",
             "priceinusd":14.99
          },
          {
             "url":"https://store.example.com/mug",
             "description":"A mug with Brandon on it",
             "productname":"Brandon Coffee Mug",
             "previewimage":"https://cdn.buttercms.com/image2",
             "priceinusd":6.99
          }
       ]
    }
    

    You are now ready to deploy the service to App Engine.

Deploy the service

This section assumes that you have the Cloud SDK installed and initialized and that the project directory you created earlier (contentService) is the current working directory.

  1. Create a file named app.yaml that contains the following:

    runtime: nodejs
    env: flex
    
  2. Deploy the app using the following command:

    gcloud app deploy
    

    As the code is built and deployed, you'll see progress updates in the terminal window. The output might look familiar if you have used Docker to build container images before. When the deployment is done, the content service will be live and publicly accessible.

Implementing a frontend website

At this point, the content service is ready to be consumed by a frontend. In this section, you create a frontend, a crude implementation of a website, to pull in the content data from the content service and return HTML.

Create the website

  1. Create a directory for the frontend:

    mkdir eCommerceSite

    cd eCommerceSite

  2. Initialize the project for Node.js:

    npm init
    
  3. Enter any relevant information when prompted.

  4. Install the express npm package:

    npm install express --save
    
  5. Install the npm package request, which you'll use to make the REST call to contentService:

    npm install request --save
    
  6. When you deployed contentService to App Engine, you were given a public URL. Make note of that URL, open your text editor, and create a server.jsfile that will contain the code to return the homepage HTML:

    const express = require('express');
    const app = express();
    const https = require('https');
    
    const options = {
      hostname: 'contentservice-173519.appspot.com',
      port: 443,
      path: '/hotproducts',
      method: 'GET'
    }
    
    app.get('/', function (req, res) {
      var html = '';
      const contentReq = https.request(options, (contentRes) => {
        contentRes.on('data', (d) => {
          var data = JSON.parse(d);
          for (i = 0; i < data.hotproducts.length; i++) {
          html += '<li>' + data.hotproducts[i].productname + '</li>';
        }
        res.set('Content-Type', 'text/html');
        res.end(html);
        });
      });
      contentReq.end();
    });
    
    const PORT = process.env.PORT || 8080;
    app.listen(PORT, () => {
      console.log(`App listening on port ${PORT}`);
      console.log('Press Ctrl+C to quit.');
    });
    

Deploy the website

Follow the same instructions as in the previous section to create an app.yaml file, and then run gcloud app deploy to deploy the website to App Engine.

Scaling

App Engine provides several scaling options that you can use to configure how the content service and the example website will scale in response to load. You specify these options in app.yaml.

Manual scaling

With manual scaling, you set the exact number of App Engine instances you want the app to run in. If you later change the number of instances, you must update app.yaml manually. Here's an example app.yaml entry:

manual_scaling:
  instances: 2

Basic scaling

With basic scaling, you set the maximum number of instances and the amount of time an instance can go without serving a request before being shut down. This option enables App Engine to shut down unneeded instances. Here's an example app.yaml entry:

basic_scaling:
  max_instances: 3
  idle_timeout: 3m

Automatic scaling

Automatic scaling offers a wider range of parameters that define how App Engine manages scaling for the app, for example, setting minimum and maximum instances. Here's an example app.yaml entry:

automatic_scaling:
  min_num_instances: 5
  max_num_instances: 10
  min_pending_latency: 45ms
  max_pending_latency: automatic
  max_concurrent_requests: 100

You can find more details about these scaling options for Node.js applications.

Monitoring

With your content service and website up and running, you can monitor their health by using Stackdriver Monitoring. This section describes how to create example email alerts for 95-percentile response time latency exceeding a threshold.

Activate Stackdriver Monitoring

  1. In the Cloud Platform Console, ensure that the project you have been using for this tutorial is the currently active project.
  2. In the Products and services menu, under Stackdriver, click Monitoring.

    After you sign in, you will be prompted to link the currently active project to an existing Stackdriver account, which you just created. As soon as you link your project to your account, you will be ready to add alerts.

Add an alert

  1. On the left-side navigation menu, click Alerting and on the submenu that appears, click Create a Policy.

    Create a Policy

  2. In the resulting Create new alerting policy page, under Conditions, click Add Condition, and then click Metric Threshold.

    Metric Threshold

  3. Define the desired threshold condition for the alert as shown here:

    threshold condition

  4. Click Save Condition. You will be redirected back to the Create new alerting policy page.

  5. In Notifications, enter the email address that will receive email notifications when the alert condition is met.

  6. Click Save Policy to start the monitoring. For information about any charges you might incur, see the Stackdriver pricing page.

Cleaning up

To avoid incurring charges to your Google Cloud Platform account for the resources used in this tutorial:

  1. In the Cloud Platform Console, go to the Projects page.

    Go to the Projects page

  2. In the project list, select the project you want to delete and click Delete project. After selecting the checkbox next to the project name, click
      Delete project
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

What's next

  • Try out other Google Cloud Platform features for yourself. Have a look at our tutorials.

Monitor your resources on the go

Get the Google Cloud Console app to help you manage your projects.

Send feedback about...