JavaScript and Drupal 8 RESTful Web Services

Last updated on
24 May 2023

This documentation needs work. See "Help improve this page" in the sidebar.

This page aims to outline how to use JavaScript to communicate with Drupal 8's RESTful services. It is broken into sections per entity type.

It outlines:

  1. which HTTP method to use (GET, POST, PATCH, or DELETE) on which URL
  2. which headers to send
  3. what data to send, if any
  4. what response can be expected from the server

For the following entity types:

Getting started

See Getting started: REST configuration & REST request fundamentals. Please read that first!

Users

Login

  1. POST http://example.com/user/login?_format=json
  2. Content-type: application/json
  3. withCredentials: true (only for cross domain authentication)
{
  "name": "admin",
  "pass": "password"
}

200 OK

Logout

  1. POST http://example.com/user/logout?_format=json&token=logout_token
  2. Content-type: application/json
  3. withCredentials: true (only for cross domain authentication)
  4. 204 - OK

Retrieve

  1. GET http://example.com/user/1?_format=json
  2. None
  3. 200 - OK

Register

POST: https://example.com/user/register?_format=json
Content-type: application/json

{
  "name": { "value": "fooBar" },
  "mail": { "value": "foo@bar.com" },
  "pass": { "value": "secretSauce" }
}

200 OK

Nodes

Create

POST: http://example.com/entity/node
Content-type: application/json

{
  "type":[{"target_id":"article"}],
  "title":[{"value":"Hello World"}],
  "body":[{"value":"How are you?"}]
}

201 - Created

For setting the value of an entity reference field referencing another entity type, all you need is its uuid:

"_embedded": {
  "https://example.com/rest/relation/node/article/my_entity_reference_field": [
    { 
      "uuid":[{"value":"yourUUID-xxx-xxxx-xxxx-xxxxxxxxx"}]
    }
  ]
}

Retrieve

GET: http://example.com/node/123?_format=json
Content-type: *
Accept: application/json
200 - OK

Update

PATCH: http://example.com/node/123
Content-type: application/json

{
  "nid":[{"value":"123"}],
  "type":[{"target_id":"article"}],
  "title":[{"value":"Goodbye World"}]
}

204 - No Content

Delete

DELETE: http://example.com/node/123
Content-type: *
{"type":[{"target_id":"article"}]}
204 - No Content

Comments

Create

POST: http://example.com/entity/comment
Content-type: application/json

{
  "entity_id":[{"target_id":123}],
  "entity_type":[{"value":"node"}],
  "comment_type":[{"target_id":"comment"}],
  "field_name":[{"value":"comment"}],
  "subject":[{"value":"Goodbye World"}],
  "comment_body":[
    {"value":"<p>See you later!</p>","format":"basic_html"}
  ]
}

201 - Created

Retrieve

GET: http://example.com/comment/456?_format=json
200 - OK

Update

#2631774: Impossible to update Comment entity with REST (HTTP PATCH): bundle field not allowed to be updated, but EntityNormalizer::denormalize() requires it

Delete

DELETE: http://example.com/comment/456
Content-type: *
{"comment_type":[{"target_id":"comment"}]}
204 - No Content

Vocabularies

In D8, vocabularies are "Configuration Entities" and are not yet supported by core's REST. For starters, some folks are working towards GET as a minimum: #2300677: JSON:API POST/PATCH support for fully validatable config entities

Taxonomy Terms

Code Examples: RESTful Drupal 8 CRUD Example using jQuery and core REST module

CREATE Item

var package = {}
package.title = [{'value':'t1'}]
package.body = [{'value':'b1'}]
package._links = {"type":{"href":"http://local.drupal8.org/rest/type/node/page"}}

$.ajax({
  url: "http://example.com/entity/node",
  method: "POST",
  data: JSON.stringify(package),
  headers: {
    "Accept": "application/json",
    "Content-Type": "application/hal+json"
  },
  success: function(data, status, xhr) {
    debugger
  }
})

GET Item

$.ajax({
  url: "http://example.com/node/3?_format=hal_json",
  method: "GET",
  headers: {
    "Content-Type": "application/hal+json"
  },
  success: function(data, status, xhr) {
    debugger
  }
})

GET an Item and then UPDATE Item

$.ajax({
  url: "http://example.com/node/3?_format=hal_json",
  method: "GET",
  headers: {
    "Content-Type": "application/hal+json"
  },
  success: function(data, status, xhr) {
    var package = {}
    package.title = data.title
    package.body = data.body
    package.title[0].value = 'yar'
    package._links = {"type":{"href":"http://example.com/rest/type/node/page"}}
    debugger

    $.ajax({
      url: "http://example.com/node/3",
      method: "PATCH",
      data: JSON.stringify(package),
      headers: {
        "X-CSRF-Token": "niCxgd5ZZG25YepbYtckCy7Q2_GL2SvMUY5PINxRAHw",
        "Accept": "application/json",
        "Content-Type": "application/hal+json"
      },
      success: function(data, status, xhr) {
        debugger
      }
    })
  }
})

Drupal protects its REST resources from CSRF attacks by requiring a X-CSRF-Token request header to be sent when using a non-safe method. So, when performing non-read-only requests, that token is required. Such a token can be retrieved at /session/token.

GET an Item and then UPDATE Item with CSRF token.

$.ajax({
  url: 'http://example.com/session/token',
  method: 'GET',
  success: function(token) {
    var csrfToken = token;

    $.ajax({
      url: "http://example.com/node/3?_format=hal_json",
      method: "GET",
      headers: {
        "Content-Type": "application/hal+json"
      },
      success: function(data, status, xhr) {
        var package = {};
        package.title = data.title;
        package.body = data.body;
        package.title[0].value = 'yar';
        package._links = {"type":{"href":"http://example.com/rest/type/node/page"}};
        debugger

        $.ajax({
          url: "http://example.com/node/3",
          method: "PATCH",
          data: JSON.stringify(package),
          headers: {
            "X-CSRF-Token": csrfToken,
            "Accept": "application/json",
            "Content-Type": "application/hal+json"
          },
          success: function(data, status, xhr) {
            debugger;
          }
        });
      }
    });
  }
});

DELETE Item

$.ajax({
  url: "http://example.com/node/3",
  method: "DELETE",
  headers: {
    "Accept": "application/json",
    "Content-Type": "application/hal+json"
  },
  success: function(data, status, xhr) {
    debugger
  }
})

Results are Automatically Cached from GET Requests

While developing, it's important to understand that when you make a GET request to D8 Rest, Drupal will cache the result so subsequent requests receive a speedy response. You can either clear all of Drupal's caches to get the new results, or append a timestamp to the URL query string:

node/123?_format=json&time=123456789

Or if you've created a custom resource, use addCacheableDependency() on the ResourceResponse:

$response = new ResourceResponse(array('hello' => 'world'));
$response->addCacheableDependency($account);
return $response;

Resources and Modules

Help improve this page

Page status: Needs work

You can: