How to Use Apostrophe as a Headless CMS

TL;DR: Discover the powerful headless APIs that Apostrophe offers to developers. Programmatically explore and publish content via RESTful endpoints.

Apostrophe as a Headless CMS

Apostrophe is an open-source content management system (CMS) and website builder built on JavaScript. In addition to the features offered by traditional CMS technologies, Apostrophe can also be configured to function as a headless CMS. A headless CMS allows developers to manage and reuse content over multiple formats and devices, without being tied to a particular output format. It separates the content layer from the presentation layer.

Thanks to its built-in RESTful API endpoints, developers can create, retrieve, update, and delete (CRUD) content through simple HTTP calls. Here, you will learn about what endpoints Apostrophe exposes, and how to use them!

Let’s dive in!

Is Apostrophe a Headless CMS?

Short answer: Yes, Apostrophe is a headless CMS! More specifically, it is also a headless CMS. 

Apostrophe is a full-stack content management system based on Node.js and Vue.js that provides a powerful platform for building websites, web apps, and digital experiences. On top of that, it comes with advanced built-in headless capabilities.

This means that editors and designers can take advantage of all of the benefits of a traditional CMS, such as WordPress. Simultaneously, developers can interact with content and media via API, such as in Contentful. Check out our Contentful vs Apostrophe article for more details.

Get the best of the two worlds with Apostrophe!

Set Up Apostrophe as a Headless CMS

In this step-by-step section, you will learn how to get started with Apostrophe and configure it as a headless CMS. If you already have an ApostropheCMS project, you can skip the first three subchapters and go straight to the last one. 

Initialize an Apostrophe Project

First, make sure you have MongoDB and the latest LTS version of Node installed on your machine. Then, launch the command below to install the Apostrophe CLI:

npm install -g @apostrophecms/cli

Now, you can create a new Apostrophe project with:

apos create apos-app

The command will take care of installing the required dependencies and walk you through the initialization process.

Refer to the Setting Up guide from the official documentation in case of need.

Define the Piece Types

In Apostrophe, a piece type represents the model of a real-world content entity. Specifically, it contains all the field attributes required to define a stand-alone piece of content in the CMS. Here, you will learn how to set up the article piece type. Keep in mind that content modeling depends on your application domain, so adapt the examples below to your needs.

To create a new piece in Apostrophe, you need to add a module that extends @apostrophecms/piece-type. You can generate the starter code for the article type using the official CLI command below:

apos add piece article

In the modules folder, you will now have an article directory containing the following index.js file:

// modules/article/index.js

module.exports = {
  extend: '@apostrophecms/piece-type',
  options: {
    label: 'Article',
    // Additionally add a `pluralLabel` option if needed.
  },
  fields: {
    add: {},
    group: {}
  }
};

If you do not want to use the Apostrophe CLI, you can initialize this JavaScript file manually. By default, a piece type with no extra configuration has the title, slug, and visibility fields.

You can define a proper model for blog articles by updating index.js as follows:

// modules/article/index.js

module.exports = {
  extend: '@apostrophecms/piece-type',
  options: {
    label: 'Article'
    // Additionally add a `pluralLabel` option if needed.
  },
  fields: {
    add: {
      image: {
        label: 'Featured image',
        type: 'area',
        options: {
          max: 1,
          widgets: {
            '@apostrophecms/image': {}
          }
        }
      },
      content: {
        label: 'Content',
        type: 'area',
        options: {
          widgets: {
            // enable the rich-text editor
            '@apostrophecms/rich-text': {},
            // allow multimedia files
            '@apostrophecms/image': {},
            '@apostrophecms/video': {}
          }
        }
      }
    },
    group: {
      basics: {
        label: 'Basics',
        fields: [ 'title', 'content', 'image' ]
      }
    }
  }
};

The fields object should involve the following two attributes:

  • add: defines the attributes of the content type
  • group: specifies how the attribute inputs are grouped in tabs in the UI

Then, register the new piece types in the modules field in app.js:

// app.js

require('apostrophe')({
  shortName: 'my-blog',
  modules: {
    article: {},
    // remaining configs ...
  }
});

Great! This is how content modeling works in ApostropheCMS! Read our guide to learn how to build a blog in Apostrophe.

Create Some Pieces

Individual records of a specific piece type are called “pieces.” You can populate them through the easy-to-use content management UI offered by Apostrophe. 

Time to create some content. In the Admin UI, click on the “Articles” button in the top menu.

article headless cms

Then, click “New Article” to open the following modal:

new article headless cms

Fill out the form and click on the “Publish” button to create a new article piece. Repeat this process to generate more content. 

Do the same for all other piece types in your project.

As you can see, managing content in Apostrophe is simple and intuitive. Anyone can do it, even non-technical users. Let’s now learn how to publicly access this content via API.

Apostrophe Headless CMS APIs in Action

Apostrophe automatically exposes several RESTful endpoints for each piece type. This means that the tool offers built-in headless CMS capabilities, and you do not need extra configuration to enable this feature. 

It is time to see the most common headless endpoints offered by Apostrophe in action. To test the sample API calls you will see in this section, an HTTP client is recommended. Postman or Insomnia will do.

Check out the docs to explore all API endpoints available!

API Authentication

Apostrophe comes with several API authentication methods, including API keys, bearer tokens, and session cookies. Here, we will focus on bearer tokens. Since they are associated with a single account, they represent the most appropriate option for browser use and headless applications.

To get a valid bearer authentication token, perform a POST request to /api/v1/@apostrophecms/login/login, with username and password in the JSON body:

{
    "username": "<YOUR_USERNAME>",
    "password": "<YOUR_PASSWORD>"
}
authentication headless CMS

If the login credentials are correct, Apostrophe will respond with a JSON object including a token property:

{
    "token": "clhj8xkji0004y0ff0jjl9zx9"
}

Store the bearer token returned by the server in a safe place. You can use it to access APIs that require login by specifying it in the HTTP Authorization header of the request as below:

Bearer <YOUR_BEARER_TOKEN>
bearer headless cms

Take a look at the documentation to explore other authentication methods available.

Make the API Endpoints Public

By default, the Apostrophe REST APIs are accessible only by authenticated users. However, you can elect to allow the HTTP GET endpoints for a specific piece to be made publicly accessible using the publicApiProjection option:

// modules/article/index.js

module.exports = {
  extend: '@apostrophecms/piece-type',
  options: {
    label: 'Article',
    publicApiProjection: {
      title: 1,
      slug: 1,
      image: 1
    },
    // other options...
  },
  fields: {
    // omitted for brevity...
  }
};

This option enables you to control the fields returned by the GET endpoints by adding or omitting them in the publicApiProjection object. Note that this applies only to unauthenticated users. Authenticated users will always receive all available data.

Alternatively, if you want to give a SPA the ability to access all the fields in a piece type through the GET endpoint without also having other CRUD privileges, you can do so through the guestApiAccess option. This gives a logged-in guest user with no editing privileges full GET access.

Keep in mind that this does mean the user must log in, typically via our bearer token API. So it is well-suited to sites requiring user signup, such as with our @apostrophecms-pro/signup module, and possibly payment to access content with the "login required" flag. But if you want the whole world to see your content, use publicApiProjection instead.

 You can enable this configuration for a specific piece as follows:

// modules/article/index.js

module.exports = {
  extend: '@apostrophecms/piece-type',
  options: {
    label: 'Article',
    guestApiAccess: true
    // other options...
  },
  fields: {
    // omitted for brevity...
  }
};

Retrieve All Pieces

You can get all records of a specific piece type in a paginated manner with the GET /api/v1/:piece-type-name endpoint.

For example, you can get all articles with a GET request to /api/v1/article.

get api headless cms

Apostrophe will produce a paginated response in the following format:

{
    "pages": 1,
    "currentPage": 1,
    "results": [
        {
            "_id": "clhj5wwoi0031bwffh65df6ga:en:published",
            "slug": "failure-key-to-success",
            "title": "Why Failure is the Key to Success: Lessons from Famous Failures",
            "image": {
                // ...
            },
            "cacheInvalidatedAt": "2023-05-11T13:25:36.568Z"
        },
        // ...
        {
            "_id": "clhj5mp8g0017bwff6bkf9t57:en:published",
            "slug": "benefits-traveling-alone",
            "title": "5 Surprising Benefits of Traveling Alone",
            "image": {
                // ...
            },
            "cacheInvalidatedAt": "2023-05-11T13:17:40.524Z"
        }
    ]
}

If you elected to use the publicApiProjection option and did not present a bearer token, the entities inside results will only include the attributes specified in the configuration object.

results contains only the first 10 elements, also known as the first page. You can access other pages by specifying the page query parameter, as in the example below:

http://localhost:3000/api/v1/article?page=2

bearer token headless cms

You will now have access also to the content field.

Retrieve a Specific Piece

You can retrieve a specific piece by _id with the GET /api/v1/:piece-type-name/:_id API.

For example, you can get the clhj5wwoi0031bwffh65df6ga:en:published article with:

http://localhost:3000/api/v1/article/clhj5wwoi0031bwffh65df6ga:en:published

retrieve page headless cms

Apostrophe will produce a flat JSON object containing all attributes associated with the specified piece. In case of some missing data, it will return a 404 Not Found error response.

Filter Some Pieces

Apostrophe allows you to filter the result of the paginated GET endpoint through some special query parameters. For example, you can get all articles containing the word “happiness” with:

http://localhost:3000/api/v1/article?search=happiness

query headless cms

Thanks to these parameters, you can also get localized and draft content. Note that authentication is required to get drafts.

Create a New Piece

You can create a new piece by passing all required fields to the JSON body of the POST /api/v1/:piece-name endpoint.

For example, you can insert a new article as in the image below:

insert new headless cms

By default, Apostrophe will publish the content and return its attributes, including the _id. To create a draft, specify the aposMode=draft query parameter in the request.

In case of some missing required fields, the server will respond with a 422 Unprocessable Content error.

Update a Piece

Similarly to above, you can update a piece with the PUT /api/v1/:piece-name/:_id API. The main difference is that you also have to specify the _id of the existing piece in the endpoint.

If you omit a field in the JSON body, this will be restored to its default value. To partially update only some attributes of a piece, use the PATCH /api/v1/:piece-name/:_id endpoint.

Delete an Existing Piece

To delete a piece, specify its _id in the DELETE /api/v1/:piece-name/:_id endpoint.

For example, you can remove the clhj5wwoi0031bwffh65df6ga:en:published article through the DELETE request below:

http://localhost:3000/api/v1/article/clhj5wwoi0031bwffh65df6ga:en:published

delete piece headless cms

Other APIs

In addition to the piece type REST API, Apostrophe also offers:

  • Page type REST API: provides endpoints for creating, reading, updating, and deleting page objects. It requires authentication and is useful for programmatically managing pages within an Apostrophe site.
  • Media API: exposes endpoints to perform CRUD operations on images, videos, and files. This allows you to upload new media files and retrieve, replace, and download existing ones.

With Apostrophe, the headless possibilities are endless!

Conclusion

In this article, we looked at Apostrophe as a headless CMS, what its content APIs offer, and how to access them. In detail, Apostrophe is a CMS and website builder that also has headless capabilities. This makes it an extremely flexible tool.

Following this step-by-step tutorial, you learned how to use Apostrophe as a headless CMS, explore its API, and retrieve or publish content. As proven here, Apostrophe allows you to create a complete headless CMS with just a few lines of code.