Warning message

Documentation is currently being migrated into the new system. Some pages might be temporarily missing, and some guides might appear empty. Thank you for your patience while we are improving Drupal.org documentation.

3. POST for creating content entities

Last updated on
November 21, 2016 - 15:19

Follow these steps to expose resources to POST requests:

  1. Configuration
  2. Test with a POST request

Configuration

This builds upon the GET example of the previous page.

See Getting started: REST configuration & REST request fundamentals — Configuration

Sample requests below assume this configuration:

resources:
  entity:node:
    GET:
      supported_formats:
        - hal_json
      supported_auth:
        - basic_auth
        - cookie
    POST:
      supported_formats:
        - hal_json
      supported_auth:
        - basic_auth
        - cookie

Test with a POST request

In this example, we will use HAL+JSON. HAL+JSON has the concept of relations. Most of the content in Drupal has relations. Make sure the relations are properly added to the payload (they live under the _links key).

For instance if you want to POST a new comment you need a _links entry to the user and to the entity the comment is for. Best way to get this is to first GET an example and study its _links.

Never POST a UUID (or node ID/comment ID/…) as you create a new entity.

In all of the examples below, you should get a 200 response, which includes the serialized entity in the body (since Drupal 8.1.0, i.e. since #2546216: Return entity object in REST response body after successful POST — before then, you'll get a 201 response, with an empty body)

In all examples below, we POST to the URL /entity/node. Since Drupal 8.3.0, you are able to POST to /node instead, but /entity/node will continue to work until Drupal 9.

cURL (command line)

curl --include \
  --request POST \
  --user klausi:secret \
  --header 'Content-type: application/hal+json' \
  --header 'X-CSRF-Token: <obtained from http://example.com/rest/session/token>' \
  http://example.com/entity/node?_format=hal_json \
  --data-binary '{"_links":{"type":{"href":"http://example.com/rest/type/node/article"}},"title":[{"value":"Example node title"}],"type":[{"target_id":"article"}]}'

Guzzle

<?php
$serialized_entity = json_encode([
  'title' => [['value' => 'Example node title']],
  'type' => [['target_id' => 'article']],
  '_links' => ['type' => [
      'href' => 'http://example.com/rest/type/node/article'
  ]],
]);

$response = \Drupal::httpClient()
  ->post('http://example.com/entity/node?_format=hal_json', [
    'auth' => ['klausi', 'secret'],
    'body' => $serialized_entity,
    'headers' => [
      'Content-Type' => 'application/hal+json',
      'X-CSRF-Token' => <obtained from /rest/session/token>
    ],
  ]);
?>

jQuery

function getCsrfToken(callback) {
  jQuery
    .get(Drupal.url('rest/session/token'))
    .done(function (data) {
      var csrfToken = data;
      callback(csrfToken);
    });
}

function postNode(csrfToken, node) {
  jQuery.ajax({
    url: 'http://example.com/entity/node?_format=hal_json',
    method: 'POST',
    headers: {
      'Content-Type': 'application/hal+json',
      'X-CSRF-Token': csrfToken
    },
    data: JSON.stringify(node),
    success: function (node) {
      console.log(node);
    }
  });
}

var newNode = {
  _links: {
    type: {
      href: 'http://example.com/rest/type/node/article'
    }
  },
  type: {
    target_id: 'article'
  },
  title: {
    value: 'Example node title'
  }
}; 

getCsrfToken(function (csrfToken) {
  postNode(csrfToken, newNode);
});

Dev HTTP client

POST with Taxonomy Term entity reference using HAL+JSON: cURL (command line)

The following is an example of a POST request using HAL+JSON to create an article Node with a taxonomy term entity reference for a "tagging" vocabulary.

This example applies only to HAL+JSON, since the concept of _embedded is specific to HAL+JSON, it does not exist in JSON or XML.

Before you can actually POST the article node with a tag when using the HAL+JSON format, you first have to GET the tag to retrieve its UUID (because HAL+JSON requires references by UUID). If it's a new term, you must first POST it to create it. See also example 'POST term'.

curl --request POST -k -i -s --user user:password --header 'Content-type: application/hal+json' -H 'Cache-Control: no-cache' --header 'X-CSRF-Token: <obtained from http://example.com/rest/session/token>' 'http://example.com/entity/node?_format=hal_json' --data-binary '
{
  "_links": {
    "type": {
      "href": "http://example.com/rest/type/node/article"
    },
    "http://example.com/rest/relation/node/article/field_tags": {
       "href": "http://example.com/taxonomy/term/1?_format=hal_json"
    }
  },
  "type": {
      "target_id": "article"
    },
  "title": {
      "value": "My Article"
    },
  "body": {
      "value": "some body content aaa bbb ccc"
  },
    "_embedded": {
      "http://example.com/rest/relation/node/article/field_tags": [
        {
          "_links": {
            "self": {
              "href": "http://example.com/taxonomy/term/1?_format=hal_json"
            },
            "type": {
              "href": "http://example.com/rest/type/taxonomy_term/tags"
            }
          },
          "uuid": [
            {
              "value": "ff61ea71-2540-47fe-a4bb-384b12d4de47"
            }
          ],
          "lang": "en"
        }
      ]
    }
}'

POST New Taxonomy Term using HAL+JSON: cURL (command line)

Note: actual endpoint is '/entity/taxonomy_term/'

export JSON_DATA='
{
  "_links": {
    "type": {
      "href": "https://example.com/rest/type/taxonomy_term/tags"
    }
  },
  "vid": [
    {
      "target_id": "tags"
    }
  ],
  "name": [
    {
      "value": "RESTtag",
      "lang": "en"
    }
  ]
}'


curl --request POST \
  -k \
  -i \
  -s \
  --user "username:password" \
  --header 'Content-type: application/hal+json' \
  -H 'Cache-Control: no-cache' \
  --header "X-CSRF-Token: ####YourTokenHash####" \
  'https://example.com/entity/taxonomy_term/?_format=hal_json'  \
  --data-binary "$JSON_DATA"