RESTful Web Services API overview

Last updated on
6 March 2017

The RESTful Web Services API is new in Drupal 8.  Expose entities as REST resources either to build a decoupled Drupal site, to let a native mobile iOS/Android app talk consume/feed a Drupal site, or to integrate with some web service.

For each REST resource, you can specify the supported verbs, and for each verb, you can specify the serialization formats & authentication mechanisms.

Serialization Formats

By default, the REST module supports json and xml. If you install core's HAL module, you can also enable the hal_json format. By installing additional modules, you can get access to more formats — see Serialization API for details. 

When performing REST requests, you must inform Drupal about the serialization format you are using (even if only one is supported for a given REST resource). So:

  1. Always specify the ?_format query argument, e.g. http://example.com/node/1?_format=json.
  2. When sending a request body containing data in that format, specify the Content-Typerequest header. This is the case for POST and PATCH.

Note: Accept-header based content negotiation was removed from Drupal 8 because browsers and proxies had poor support for it.

Authentication

The REST module supports two methods of authentication: 

  • basic  - The quickest way to get started is to use basic HTTP Authentication. Enable the Basic Auth module found in core, then send your drupal username and password using HTTP Authorization Headers
  • cookie - Use the cookie granted to an authenticated user.

You can also use OAuth 2.0 Bearer Token (or some other authentication mechanism). After installing that module, you can enable it for the resources/verbs you want. 

Safe vs. unsafe methods

REST uses HTTP, and uses the HTTP verbs. The HTTP verbs (also called request methods) are: GETHEADPOSTPUTDELETETRACEOPTIONSCONNECT and PATCH.
Some of these methods are safe: they are read-only. Hence they can never cause harm to the stored data, because they can't manipulate them. The safe methods are HEADGETOPTIONSand TRACE.
All other methods are unsafe, because they perform writes, and can hence manipulate stored data.

Note: PUT is not supported for good reasons.

Unsafe methods & CSRF protection: X-CSRF-Token request header

Drupal 8 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.

REST Resource Configuration 

Important: The configuration between Drupal <=8.1 varies from Drupal >=8.2. Before proceeding, please check the version of your drupal installation to ensure you are following the proper instructions. 

Drupal 8.0 & 8.1: 

In Drupal 8, there is a single central location to configure all REST resources that a site exposes: rest.settings.yml. For each resource, you can configure per verb (i.e. GET, POST…) which serialization formats & authentication mechanisms it supports.After modifying this YAML file, import it to update the actual configuration of your Drupal 8 site at /admin/config/development/configuration/single/import.

Alternatively, you can use REST UI contributed module if you don't want to modify YAML by hand. 

Example rest.settings.yml 

resources:
  entity:node:
    GET:
      supported_formats:
        - hal_json
        - json
        - xml
      supported_auth:
        - basic_auth
        - cookie

Permissions

Finally, you will need to set the corresponding permission to your configured resource. In case of a decoupled site, you typically need to grant the authenticated user role permission to GET content. In case of a web service, you typically need to grant the anonymous users permission to GET/POST content. Grant them at /admin/people/permissions#module-rest, or using Drush: drush role-add-perm anonymous 'restful <METHOD> <RESOURCE>', for example: drush role-add-perm anonymous 'restful get entity:node'

Drupal 8.2 & Later: 

Each REST resource has a \Drupal\rest\RestResourceConfigInterface config entity that corresponds to a @RestResource plugin. Without such a config entity, the REST resource plugin will not be available for use.

There are two methods for configuring resources: 

  • granularity: method: Set serialization formats and authentication  per HTTP method.  
  • granularity: resource: Set serialization formats and authentication  per resource. 

Alternatively, you can use the development release (8.x-1.x-devREST UI contributed module if you don't want to modify YAML by hand.  

Example rest.resource.entity.node.yml using method granularity:

id: entity.node
plugin_id: 'entity:node'
granularity: method
configuration:
  GET:
    supported_formats:
      - json
    supported_auth:
      - basic_auth
      - cookie
  ... 

Example rest.resource.entity.node.yml using resource granularity:

id: entity.node
plugin_id: 'entity:node'
granularity: resource
configuration:
  methods:
    - GET
    ...
  formats:
    - json
    ...
  authentication:
    - basic_auth
    ...

Permissions

The existing entity access system, by default, moderates access to entities. For instance, users must have the view permission to the entity in order to query the entity with the GET method - the semantics of GET imply a read-only operation. Other operations, such as POST, require another permission such as the appropriate "edit" permission (edit own content, for instance).

REST API Services Change Log for Drupal 8.2

  • Added support for reading (GET) configuration entities as REST resources.
  • Added dedicated resources for user login, logout and registration.
  • Added support for selecting an authentication provider as part of the configuration of a REST Export Views Display.
  • Added a cors.config service parameter for enabling and configuring cross-origin resource sharing (CORS).
  • Simplified REST configuration with per-resource configuration and less verbose configuration structure. (The previous, configuration structure is also still supported.)
  • Improved the response messages and status codes for requests with missing or incorrect headers.
  • Improved responses to PATCH requests to entity resources to contain the updated entity in the response body.

Custom Rest Resources

[Note: A complete guide to creating custom REST resources is coming soon! ] 

Scaffolding code for custom modules can be automatically generated with a Drupal Console command via drupal generate:plugin:rest:resource.

Resource plugins
\Drupal\rest\Plugin\ResourceInterface: resource plugins, to expose additional resources over REST.
The above allows Drupal to automatically expose that resource using REST, using any authentication mechanism (see Authentication API for details), and any serialization format (both encoding & normalization — see Serialization API for details). So as a developer, you only need to implement the logic to work with the object in question that you're exposing as a resource.
Creating REST resource plugins
Look at \Drupal\dblog\Plugin\rest\resource\DBLogResource for a trivial example, \Drupal\rest\Plugin\rest\resource\EntityResource for a very complex example.

What is very important is the @RestResource annotation's uri_paths definition. If you don't specify any, Drupal will automatically generate URI paths (and hence URLs) based on the plugin ID. If your plugin ID is fancy_todo, you'll end up with GET|PATCH|DELETE /fancy_todo/{id} and POST /fancy_todo. But, often, you'll want to specify your own paths: a canonical URI path (for example /todo/{todo_id}), but also a https://www.drupal.org/link-relations/create URI path (for example /todo). If you only specify one of them, then the other will use the default URI path, which will then likely not match the URI path that you did specify.
So, either omit uri_paths, or specify both:

 *   uri_paths = {
 *     "canonical" = "/todo/{id}",
 *     "https://www.drupal.org/link-relations/create" = "/todo"
 *   }

This also allows you to version your API, and create different implementations for each version:

 *   uri_paths = {
 *     "canonical" = "/api/v1//todo/{id}",
 *     "https://www.drupal.org/link-relations/create" = "/api/v1/todo"
 *   }

See also