Creating Content Using the Drupal 8 REST API Tutorial

Drupal8 rest screen

How we'll do it

In this tutorial, we're going to be able to post content to a Drupal content type using the REST API. To do it, we're going to start from scratch with a fresh install and configure everything for the API so that you can see how to do it on your site. This tutorial shows how to set up Drupal 8 in 2 minutes using drush.

The steps:

  • Get a fresh copy of Drupal installed
  • Set up the REST API permissions using Drupal's configuration manager
  • Go through our sample drupal8-restapi-content-post.php script
  • Check out the results

Configuring the API

We need a few modules turned on to use the API the way we want to

% drush en rest serialization hal basic_auth

This is going to enable or download an enable the modules we want.

Now go to the admin and click on Configuration > Configuration Synchronization > Export > Single Item. In the first drop down, leave it at Simple Configuration. In the second, select rest.setting. When you tab out, it will load the settings you currently have. For our demo, it should look like this:

link_domain: null
bc_entity_resource_permissions: false
  default_config_hash: bwcdqlollZ-bMAg90HtLMFFBgY7UXJohIln7BICIooE
        - hal_json
        - json
        - basic_auth
        - cookie
        - hal_json
        - json
        - basic_auth
        - cookie

If yours aren't like that, make a copy of the ones above. If you have some settings there already, just add the GET and POST values to what you see and copy the whole thing. Staying in Configuration, navigate to Import > Single Item. Select Simple Configuration, type in rest.settings in the box. Now paste in the config. Save, and say yes to the changes. You can go back to "Export" to make sure it saved.

Let's get an authorization token and POST some content

You can download this script on gitgub

First set up your parameters and Guzzle

        $user = 'your admin user - maybe it is ... admin';
        $pass = 'your admin password';
        $url = ''; // or your server location. 

        $client = new GuzzleHttp\Client([
            'base_uri' => $url,
            'timeout'  => 2.0,

The API wants you to have a valid token to POST. Let's get one

        // First get a session token
        $res = $client->request('GET', '/rest/session/token');
        $csrf_token = $res->getBody();

Now we're going to set up a JSON package to POST that contains some content for an article. In a future blog, we'll go into how to get more detailed with the POST and where to find an example.

In the next part of the script, we then POST to /entity/node?_format=hal_json. In future versions of Drupal, they will move to just /node, so keep an eye out for that.

        $serialized_entity = json_encode([
            'title' => [['value' => 'Example node title ' . time()]],
            'type' => [['target_id' => 'article']],
            '_links' => ['type' => [
                'href' => $url . '/rest/type/node/article'

        $content_client = new GuzzleHttp\Client([
            'base_uri' => $url,
            'timeout'  => 2.0,

        $res = $content_client->request('POST', '/entity/node?_format=hal_json', [
            'auth' => [$user, $pass],
            'body' => $serialized_entity,
            'headers' => [
                'Content-Type' => 'application/hal+json',
                'X-CSRF-Token' => $csrf_token

And voila! Run that a few times and you'll see a bunch of new articles in your site.

% php drupal8-restapi-content-post.php 
CSRF Success: TtdKL4dzLUkPybgKL-yWWnTrEOxGFmhFjPu-3Jq-tRo
POST Success: {"_links":{"self":{"href":"http:\/\/\/node\/23?_format=hal_json"},"type":{"href":"http:\/\/\/rest\/type\/node\/article"},"http:\/\/\/rest\/relation\/node\/article\/uid":[{"href":"http:\/\/\/user\/1?_format=hal_json","lang":"en"}],"http:\/\/\/rest\/relation\/node\/article\/revision_uid":[{"href":"http:\/\/\/user\/1?_format=hal_json"}]},"nid":[{"value":"23"}],"uuid":[{"value":"b8006773-6b58-4919-8a63-1304eca01faa"}],"vid":[{"value":"23"}],"langcode":[{"value":"en","lang":"en"}],"type":[{"target_id":"article"}],"title":[{"value":"Example node title 1489339311","lang":"en"}],"_embedded":{"http:\/\/\/rest\/relation\/node\/article\/uid":[{"_links":{"self":{"href":"http:\/\/\/user\/1?_format=hal_json"},"type":{"href":"http:\/\/\/rest\/type\/user\/user"}},"uuid":[{"value":"35ff17d0-166a-4cb3-818d-73b217d72b53"}],"lang":"en"}],"http:\/\/\/rest\/relation\/node\/article\/revision_uid":[{"_links":{"self":{"href":"http:\/\/\/user\/1?_format=hal_json"},"type":{"href":"http:\/\/\/rest\/type\/user\/user"}},"uuid":[{"value":"35ff17d0-166a-4cb3-818d-73b217d72b53"}]}]},"status":[{"value":true,"lang":"en"}],"created":[{"value":1489339311,"lang":"en"}],"changed":[{"value":1489339311,"lang":"en"}],"promote":[{"value":true,"lang":"en"}],"sticky":[{"value":false,"lang":"en"}],"revision_timestamp":[{"value":1489339311}],"revision_translation_affected":[{"value":true,"lang":"en"}],"default_langcode":[{"value":true,"lang":"en"}],"comment":[{"status":2,"cid":0,"last_comment_timestamp":0,"last_comment_name":null,"last_comment_uid":0,"comment_count":0,"lang":"en"}]}

Check it out on

Drupal install freezeframe