How to Use Apostrophe as a Headless CMS
Tags: tutorial, howto, webdev, javascript
Published: 2023-06-16 10:40:00

[Apostrophe] (https://github.com/apostrophecms/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] (https://apostrophecms.com/compare-cms-solutions/contentful) 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] (https://www.mongodb.com/docs/manual/administration/install-community/) and the [latest LTS version of Node] (https://nodejs.org/en/download) installed on your machine. Then, launch the command below to install the [Apostrophe CLI] (https://www.npmjs.com/package/@apostrophecms/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] (https://v3.docs.apostrophecms.org/guide/setting-up.html) 
 guide from the official documentation in case of need.

####Define the Piece Types
In Apostrophe, a [piece type] (https://v3.docs.apostrophecms.org/guide/pieces.html#creating-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] (https://v3.docs.apostrophecms.org/reference/module-api/module-overview.html) that extends `@apostrophecms/piece-type`. You can generate the starter code for the `article` type using the [official CLI] (https://v3.docs.apostrophecms.org/guide/setting-up.html#the-apostrophe-cli-tool) 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] (https://apostrophecms.com/blog/how-to-build-a-blog-apostrophe).

####Create Some Pieces
Individual records of a specific piece type are called “[pieces] (https://v3.docs.apostrophecms.org/guide/pieces.html#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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ilp1w9uaaik9q9fv4ugl.png)


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


![new article headless cms](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hnpqjs25tayad9o7tz4g.png)


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] (https://v3.docs.apostrophecms.org/reference/api/pieces.html#endpoints)!

####API Authentication
Apostrophe comes with several API authentication methods, including [API keys] (https://v3.docs.apostrophecms.org/reference/api/authentication.html#api-keys), [bearer tokens] (https://v3.docs.apostrophecms.org/reference/api/authentication.html#bearer-tokens), and [session cookies] (https://v3.docs.apostrophecms.org/reference/api/authentication.html#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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mn1ha8rhp0ec39nuvq88.png)


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] (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization)` header of the request as below:

```
Bearer <YOUR_BEARER_TOKEN>
```


![bearer headless cms](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ccembpz5zm5gbhu4jloh.png)


Take a look at the [documentation] (https://v3.docs.apostrophecms.org/reference/api/authentication.html) 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] (https://v3.docs.apostrophecms.org/reference/api/authentication.html#allowing-public-access)` 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] (https://v3.docs.apostrophecms.org/reference/api/authentication.html#allowing-full-get-access-for-guest-users) 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] (https://v3.docs.apostrophecms.org/reference/api/pieces.html#get-api-v1-piece-name)` endpoint.

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


![get api headless cms](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xss1g1lxek9ka2rnutip.png)


Apostrophe will produce a paginated [response] (https://v3.docs.apostrophecms.org/reference/api/pieces.html#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
```


![retrieve page headless cms](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uyeu4c21ob4y5ynsm8ue.png)


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] (https://v3.docs.apostrophecms.org/reference/api/pieces.html#get-api-v1-piece-name-id)` API.

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

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


![query headless cms](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ik905peazj57caeyoxkp.png)


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] (https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404)` error response.

####Filter Some Pieces
Apostrophe allows you to filter the result of the paginated `GET` endpoint through some [special query parameters] (https://v3.docs.apostrophecms.org/reference/api/pieces.html#query-parameters). For example, you can get all articles containing the word “happiness” with:

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


![insert new headless cms](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/edjiq2e1o1nmm5bvndz0.png)


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] (https://v3.docs.apostrophecms.org/reference/api/pieces.html#post-api-v1-piece-name)` endpoint.

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


![delete piece headless cms](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/msu2ntju3mn9gkvjwmnr.png)


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] (https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422)` error.

####Update a Piece
Similarly to above, you can update a piece with the `[PUT /api/v1/:piece-name/:_id] (https://v3.docs.apostrophecms.org/reference/api/pieces.html#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] (https://v3.docs.apostrophecms.org/reference/api/pieces.html#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] (https://v3.docs.apostrophecms.org/reference/api/pieces.html#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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/53z373qky86b9egte4ps.png)


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

* [Page type REST API] (https://v3.docs.apostrophecms.org/reference/api/pages.html): provides endpoints for creating, reading, updating, and deleting [page] (https://v3.docs.apostrophecms.org/guide/pages.html#pages-and-page-types) objects. It requires authentication and is useful for programmatically managing pages within an Apostrophe site.
* [Media API] (https://v3.docs.apostrophecms.org/reference/api/media.html): 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.