An Introduction to RESTful Web Services in Drupal 8

We now have a full series on Web Services in Drupal 8, which is much more detailed and accurate, and will be kept up to date with the latest versions of Drupal 8.

This article was last updated on April 14, 2016 by trainer Blake Hall and tested with Drupal 8.0.6. There will be no further updates to this article for newer versions of Durpal core.

One of the Drupal 8 initiatives that really excites me is Web Services. Drupal has never been easy to work with as a web service, but all that is about to change! In this article I am going to explore what has been going on behind the scenes with RESTful Web Services in Drupal Core and attempt to implement some working examples. After reading, you will be able to create a new node on your site via the Drupal 8 Core REST API.

What is REST?

It's best that I first make sure everyone is on the same page. Web Services make it possible for external applications to interact with our application (in this case our Drupal site). The most common interactions are reading, creating, updating, and deleting resources.

REST is one of the most popular ways of making Web Services work. There are other formats such as SOAP or XML-RPC, but we are only going to focus on REST because it is the Drupal standard. REST utilizes HTTP methods, such as GET, POST, and DELETE.

As an example, a popular usage of a REST interface is a mobile application that needs to read and write data from your site's database.

Drupal 8 Core

Web Services have been implemented in Drupal 8 Core with the following modules:

RESTful Web Services (rest)

Exposes entities and other resources via a RESTful web API. It depends on the Serialization module for the serialization of data that is sent to and from the API.

Serialization (serialization)

Provides a service for serialization of data to and from formats such as JSON and XML.

Hypertext Application Language (hal)

Extends the Serialization module to provide the HAL hypermedia format. This is what is used as the primary format in Drupal 8 Core. It only adds two reserved keywords, ‘_links’ for link relations (also used by Github's Pull Request API) and ‘_embedded’ for embedded resources. The HAL hypermedia format can be encoded in both JSON and XML. For more details see the initial HAL proposal.

HTTP Basic Authentication (basic_auth)

This module implements basic user authentication using the HTTP Basic authentication provider. It facilitates the use of an username and password for authentication when making calls to the REST API. It is required for the examples shown in this blog post, and I would advise configuring SSL if you use it in production. For anyone looking for a more secure option, check out the contributed OAuth module which already has a Drupal 8 release.

Getting started

Start by grabbing the latest release of Drupal 8 Core and installing your site. I am using 8.0.6 at the time of writing this post. See the Releases for Drupal Core to find the latest download.

Enable the following modules: REST, Serialization, HAL, and HTTP Basic Authentication.

Web services module to enable

By default, the REST module enables the node entity resource for all GET, POST, PATCH, and DELETE operations. It supports basic or cookie authentication and the HAL or JSON formats. You can see these default settings in sites/default/files/config_XXXX/active/rest.settings.yml. To enable REST on other entities (e.g. users, files, or fields), you'll need to edit this file. There is, however, a handy contributed module created by our very own Juampy named REST UI. This module provides a user interface for enabling and disabling resources, serialization formats, and authentication providers. See the screenshot below for an example of the configuration options REST UI provides.

REST UI configuration options

Let me take this opportunity to explain the available resource options, GET, POST, PATCH, and DELETE. These are all common HTTP methods. Each operation signifies a type of action to be performed on a resource. For example, your browser used GET when you requested to view this blog post. To read a resource, we GET. To create a resource, we POST. To update a resource, we PATCH. And to delete a resource, we DELETE. Read this post if you're wondering why we use PATCH and not PUT.

Now back to our setup. For all enabled resources, the REST module can set user permissions. Go to admin/people/permissions and set up your permissions, as required. Here is an example of how I set mine:


You should create also a new authenticated user for testing purposes. If you test your API with User 1 administrator account credentials, you will likely miss permission settings that you need to be set.

Using the REST API

Now we're ready to start using our REST API. I recommend the Dev HTTP Client Chrome extension for testing calls to any API. You can also write scripts in Guzzle, which is a great new tool included in Drupal 8 Core or cURL via the command line or PHP.

Start by creating a node entity. To do this, we must send a POST to /entity/node with the Content-Type header set to application/hal+json and declare the required type and title fields in the request BODY. But don't forget that because we are using Basic Auth, we need to set the headers PHP_AUTH_USER and PHP_AUTH_PW to authenticate as our user. Here is how it looks in the Dev HTTP Client:

POST error

Or, if you prefer, you can try cURL from the command line:

curl --include --request POST --user drupaljoe:mango --header 'Content-type: application/hal+json' http://localhost:8082/d8/entity/node?_format=hal+json --data-binary '{"_links":{"type":{"href":"http://localhost:8082/d8/rest/type/node/page"}}, "title":[{"value":"My first page"}]}'

You'll notice the request is returning 403 Forbidden. It's important to remember that although you have given authenticated users permission to Access POST on Content resource they still need permission to perform the underlying action which, in this case, is creating a new page node. So head back to the permissions page and make sure authenticated users have at least the Page: Create new content, Page: Edit own content and Page: Delete own content permissions.

Another recent addition is the requirement of a CSRF token that needs to be sent along with your POST request. You can get this token by making a GET request to rest/session/token. It's also worth noting that this token is user specific, so any nodes created by POST requests with this token will be authored by the user associated with this token.

Try again, adding an additional X-CSRF-Token header with your token, and you'll now get a nice green 201 Created response. Congratulations! You just created a node entirely via your new REST API!

You can now GET the node we just created. Send a GET to /node/<nid>?_format=hal+json and you should receive a 200 OK with the BODY containing a HAL representation of the entire node entity. For a simpler JSON representation, set the _format query parameter to json and compare the results.

You should now have a general understanding of REST in Drupal 8 and the basics behind manipulating single Drupal entities via the REST API. We only used POST and GET, but PATCH and DELETE work similarly. Feel free to try them in your own time!

I hope to write more posts about REST in Drupal 8 on topics such as setting custom entity field values and retrieving lists of entities using Views. I'd like to look also into setting up more secure REST API authentication using modules such as OAuth.

Update: My blog post on RESTful Views in Drupal 8 has been released.

Please leave your comments and queries below and we'll do our best to answer what we can!

Further reading

Related Topics: 


Hi Arun,

I hadn't tried using this endpoint before, but took a quick look into the problem this morning. As best as I can understand it right now, it looks like the REST server that comes with core doesn't support retrieving and displaying configuration entities (only content entities). Therefore the search_page endpoint doesn't work as expected. They're tracking the issue for improvement in 8.4 here:


Blake Hall

Thanks for the update. What i'm trying to do is use Drupal as headless Cms. I have employee content type in drupal and i have employee search page in another website (let us call it that site as X-Site). I need to perform search against drupal ( using Rest ) and show the results in X-Site..

Thanks in advance,

Hi Arun,

Since it doesn't look like configuration entities are supported yet I think you have two options. (1) Write custom code to provide the support for your endpoint. This is likely a fair bit of work, but since you're familiar with your content model you can probably roll it out with new features incrementally. Or (2) use views. You can build a view that takes search terms as arguments, and then add a data export display which will return json at a particular path. This is certainly an easier approach, but depending on your data structure you might be a bit more limited, or the URLs you need to construct might be more complicated on your front end.

Good luck!

Blake Hall

Thanks for the nice article :)
I have a question regarding translations of custom entities. I was not able to find any documentation on the web for my need. Is it possible to add translation of a content by using REST? I would appreciate any hint/help.
Thank you in advance and btw im using Drupal 8.2.6

Hi Ramy,

It looks like translation support with the REST system is still a work in progress. You can track the core development, and perhaps weigh in with your experiences in the issue queue here:


Blake Hall

Hi Sir!
Im trying to use processsmaker in my drupal 8 site but connect them is realy cofusing and I cant and our company is badly stuck.
we'll be glad if you can help us .
already thanks for reading this.

Hi Amir,

I'm completely unfamiliar with ProcessMaker. We're working hard on adding some additional tutorials about web services in Drupal 8 though, so stay tuned.



Where are the RESTful module permissions other than `Administer REST resource configuration`?
an old article need update!!!

Howdy test1234,

While we maintain a commitment to keeping our tutorials up to date with the most recent releases of Drupal we don't offer the same with blog posts.

We do however have a very thorough series on Web Services in Drupal 8 in the copy editing phase.



I have created a custom rest resource of POST. How to use "Content-Type: multipart/form-data" to upload files in drupal 8.

As far as I know this isn't currently possible. You can read about it in this issue here:

Though this thread seems to imply that it might be possible after installing some contributed modules.


Add new comment