Drupal 8 and Drupal 9 Rest API tutorial and creating custom Rest API

In modern digital age, all applications will be having  web services in order to communicate with other third party applications and devices. This is especially evident in the areas related to PHP development services. REST architecture is the mostly used technology to implement webservices. As an Enterprise content management system, Drupal 8 also provides Restful webservice module in its core modules in order to achieve third party integrations.

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.

As you already knows Rest Webservices are used to communicate to Application using HTTP methods such as POST GET etc. Here we are discussing about how we can configure Restful Webservice API module and other Rest resources and also  how we can create custom Rest resources using our custom module.

Install postman to test rest API calls. You can also use Rest client Chrome extension.

Here I am dividing this article to below sections

  • Expose view data as Rest export
  • Creation of CSRF token for Basic authentication
  • Post content and create a node using REST
  • Submitting Files to node using Rest API
  • Creating a custom Rest resource for Get method
  • Creating a custom Rest resource for POST method

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

Rest UI

Download and install restui contributed module. This module provides easy to use UI in order to enable Rest resources and configure settings.

https://www.drupal.org/project/restui

after installing Rest UI , you can see below URL where you can manage resources.

http://YOUR_PROJ_PATH/admin/config/services/rest

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.

Expose view data as Rest export

Now we just expose a view result using rest.  We explain in detail about exposing different resources for each purposes.

Enable view resource from the list

While click on enable you will see a resource setting page where you can configure various settings which include result format of data , request method and authentication as basic authentication.

In this Case we are just displaying data using a GET request.

See below settings for exposed recourse.

I will explain detail about using authentication in below in sections.

For using basic authentication we need to create user

http://localhost/digitalnadeemDrupal/admin/people/create

Here I am creating a user with username restuser and password restuser@123

We can use this user to authenticate while calling rest API url

Create a view for any content type. Here I am creating view for Basic Page.

Select Rest export option and then provide a export path and click save button.

In views page select rest export tab if multiple displays are there.

Change Format section as fields

By click on settings you can place alias for each fields

Pop up will show which lists all fields.

You can give your own alias name so that this will appear as keys in json responses.

Please see below respnose before and after changing alias of field title.

Before applying alias for title

[{"title":"\u003Ca href=\u0022\/digitalnadeemDrupal\/node\/1\u0022 hreflang=\u0022en\u0022\u003Etest\u003C\/a\u003E"}]

After applying alias for title

[{"posttitle":"\u003Ca href=\u0022\/digitalnadeemDrupal\/node\/1\u0022 hreflang=\u0022en\u0022\u003Etest\u003C\/a\u003E"}]

As of now  we didn’t include any authentication. So we can directly call API as below. Please note you have to mention format at the end of URL .

http://localhost/digitalnadeemDrupal/basicpages?_format=json

so response will be as below.

[{"posttitle":"\u003Ca href=\u0022\/digitalnadeemDrupal\/node\/1\u0022 hreflang=\u0022en\u0022\u003Etest\u003C\/a\u003E"}]

Here digitalnadeemDrupal is my project folder

Creation of CSRF token

CSRF token is needed for Basic authentication. This token will be used to call other API end points which needs basic authentication.

Post URL is provided below. You can pass your rest user credentials in your request body.

Here I am passing my admin user credenrials

http://localhost/digitalnadeemDrupal/user/login?_format=hal_json

Request body

{
"name": "admin",
"pass": "admin123"
}

Response

 "current_user": {
"uid": "1",
"roles": [
"authenticated",
"administrator"
],
"name": "admin"
},
"csrf_token": "a4y_ZT_1RsM9RGWNWSq9PtjM5bUymSJyEMWPzcxPPa4",
"logout_token": "vORhZMKNlnd7pGlhfv8dBbFSlCFLQyrEhSj6xhJd7nU"
}

You can see your CSRF token in response key csrf_token.

Save this token and use this token for all rest resource access.

Please see below screen shot of Post man.

Here you got CSRF token. Use this token at header for basic authentication

 Post content and create a node using REST

Next we are going to discuss how we are going to post a node data using Rest module

So first we are configuring resources in rest UI window.

As you can see below

before going to  post with file , we are   submitting with text fields.

In my basic page  content type I have below fields.

And now we are going to create a node of basic page using Rest API. So we are using post man to submit the data.

For creating node we need to use basic authentication. So as mentioned in previous step get your serf token.

I am using postman to post data. For posting content URL will be as below.

http://localhost/millid8/entity/node?_format=hal_json

create BasicAuth authorization  using username and password

This create an entry in headers tab named  Authorization.

Content-Type : application/hal+json

X-CSRF-Token : Y9H_flusndNfdMHb4tmXvJ1AcDGLrN3WnQyqkmQLTww

Add node data in content body select raw option.

Here I am creating a article content with title ‘Sample article’.

{
"_links": {
"type": {
"href": "http://localhost/millid8/rest/type/node/article"
}
},
"title":[
{
"value":"sample article"
}
]
}

This will provide response with details of node created.

Submitting Files to node using Rest API

There will be situation where you have to create nodes with multiple files attached to it. We cannot  create  this with  single Rest API end point. First we have to submit file and get f_id and details. Attach this f_id with body of node creation API.

For uploading files first we need to enable Files resources at Rest UI

Go to below URL

http://localhost/millid8/in/admin/config/services/rest

Also enable file upload resource plug-in.

After enable file resource confirm authentication and formats(hal_json, json) set.

Then create a content type and an image field which accepts images.

Here in my article content type I have an image which accepts multiple values.

http://localhost/digitalnadeemDrupal1/file/upload/node/article/field_image?_format=hal_json

Content-Type   application/octet-stream

X-CSRF-Token     aXn6JKu_rhwZuPS-WNndwQls-hc2rKgOQWmcfCZ5mmg

Content-Disposition    file;filename=”offers.jpg”

{
"_links": {
"self": {
"href": "http://localhost/digitalnadeemDrupal1/sites/default/files/2019-08/offers_0.jpg"
},
"type": {
"href": "http://localhost/digitalnadeemDrupal1/rest/type/file/file"
},
"http://localhost/digitalnadeemDrupal1/rest/relation/file/file/uid": [
{
"href": "http://localhost/digitalnadeemDrupal1/user/1?_format=hal_json"
}
]
},
"fid": [
{
"value": 2
}
],
"uuid": [
{
"value": "8b8f2d3c-92f7-471c-8480-87c72cd3d2be"
}
],
"langcode": [
{
"value": "en"
}
],
"_embedded": {
"http://localhost/digitalnadeemDrupal1/rest/relation/file/file/uid": [
{
"_links": {
"self": {
"href": "http://localhost/digitalnadeemDrupal1/user/1?_format=hal_json"
},
"type": {
"href": "http://localhost/digitalnadeemDrupal1/rest/type/user/user"
}
},
"uuid": [
{
"value": "7f6726cf-5d7a-481e-ba19-d2996bb582bf"
}
]
}
]
},
"filename": [
{
"value": "offers.jpg"
}
],
"uri": [
{
"value": "public://2019-08/offers_0.jpg",
"url": "/digitalnadeemDrupal1/sites/default/files/2019-08/offers_0.jpg"
}
],
"filemime": [
{
"value": "image/jpeg"
}
],
"filesize": [
{
"value": 74188
}
],
"status": [
{
"value": false
}
],
"created": [
{
"value": "2019-08-23T02:51:01+00:00",
"format": "Y-m-d\\TH:i:sP"
}
],
"changed": [
{
"value": "2019-08-23T02:51:01+00:00",
"format": "Y-m-d\\TH:i:sP"
}
]
}

After getting above attach file id, update your node create API body values as below. In below target_id value is what value received for f_id

"field_image": [
{
"target_id": 2,
"description": "The most fascinating image ever!"
}

This will create a node with files attached to image field. Here field_image is the machine name of my image field in article content type.

most of the developers will try to upload file using base64 encoded form from javascript. it is not really needed. see below example code.

see below html form which has a file upload field.

<body>
<div class="container">
 
  <h2>Registration</h2>
  <form action="" method="post" name="registration" id = "first_form">
 
    <input type="file" id="myfile" name="myfile">
 
    <button type="submit" id="#sbbutton">submit</button>
 
  </form>
</div>

using simple fetch we can submit files to Rest API. this will provide response with f_id and other details.

var myInput = document.getElementById('myfile');
 
fetch('http://digitalnadeemlocaltest.com/file/upload/node/article/field_image?_format=json', { // Your POST endpoint
    method: 'POST',
    headers: {
      'Content-Type': 'application/octet-stream',
        'Accept':'application/vnd.api+json',
        'X-CSRF-Token':'1P2L2goyirvpoqFGVqyOloDjlQ9Tc-3CWxcZyGfhEkM',
        'Content-Disposition': 'file; filename="filename.jpg"',
		//'Authorization':'Basic YWRtaW46YWRtaW4xMjM='
		
    },
    body: myInput.files[0] // This is your file object
  }).then(
    response => response.json() // if the response is a JSON object
  ).then(
    success => console.log(success) // Handle the success response object
  ).catch(
    error => console.log(error) // Handle the error response object
  );  

see the complete code of sample html file , here digitalnadeemlocaltest.com is my local project domain.

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<title>Title of the document</title>
<script>

$( document ).ready(function() {

$('#first_form').submit(function(e) {
    e.preventDefault();
 var myInput = document.getElementById('myfile');
 
 
fetch('http://digitalnadeemlocaltest.com/file/upload/node/article/field_image?_format=json', { // Your POST endpoint
    method: 'POST',
    headers: {
      'Content-Type': 'application/octet-stream',
        'Accept':'application/vnd.api+json',
        'X-CSRF-Token':'1P2L2goyirvpoqFGVqyOloDjlQ9Tc-3CWxcZyGfhEkM',
        'Content-Disposition': 'file; filename="filename.jpg"',
		
		
    },
    body: myInput.files[0] // This is your file object
  }).then(
    response => response.json() // if the response is a JSON object
  ).then(
    success => console.log(success) // Handle the success response object
  ).catch(
    error => console.log(error) // Handle the error response object
  );  
    
  });
  });
</script>
</head>
<body>
<div class="container">
 
  <h2>Registration</h2>
  <form action="" method="post" name="registration" id = "first_form">
 
    <input type="file" id="myfile" name="myfile">
 
    <button type="submit" id="#sbbutton">submit</button>
 
  </form>
</div>
 
</body>
</html>

provide your X-CSRF-Token headers

Creating a custom Rest resource for Get method

You can create a custom rest resource plug-in in below folder in your custom module.

src->Plugin->{RsourceClassName}.php

{ResourceClass Name} can be any name based on your new plugin, say here RestSample.php.

Here I am going to create RestSample.php in my custom module(digital_nadeem) you can download complete module with custom Rest resource  here .

In order to list in Rest UI resource list we have to add @RestResource annotation in RestSample.php file.

/**
* Provides a resource to get view modes by entity and bundle.
*
* @RestResource(
*   id = "rest_sample",
*   label = @Translation("Rest sample"),
*   uri_paths = {
*     "canonical" = "/rest/digitalnadeem/api/get/node/{type}"
*   }
* )
*/

This annotation should be placed just before your class name.

Another important  part is canonical URL’s. If you are not mentioning Canonical url Drupal will create canonical url based on your resource id.

I have created below URI path.

 uri_paths = {
"canonical" = "/rest/digitalnadeem/api/get/node/{type}"
}

From rest ui screen you can enable your rest resource as below

I have selected below settings for my resource.

See the full source code in RestSample.php

<?php

namespace Drupal\digital_nadeem\Plugin\rest\resource;

use Drupal\rest\ModifiedResourceResponse;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

/**
 * Provides a resource to get view modes by entity and bundle.
 *
 * @RestResource(
 *   id = "rest_sample",
 *   label = @Translation("Rest sample"),
 *   uri_paths = {
 *     "canonical" = "/rest/digitalnadeem/api/get/node/{type}"
 *   }
 * )
 */
class RestSample extends ResourceBase {

  /**
   * Responds to GET requests.
   *
   * @return \Drupal\rest\ResourceResponse
   *   The HTTP response object.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
   *   Throws exception expected.
   */
  public function get($type = NULL) {

   // You must to implement the logic of your REST Resource here.
    $data = ['message' => 'Hello, this is a rest service and parameter is: '.$type];
	    
    $response = new ResourceResponse($data);
    // In order to generate fresh result every time (without clearing 
    // the cache), you need to invalidate the cache.
    $response->addCacheableDependency($data);
    return $response;
  }

}

Please see below response using post man.

Request URL is http://localhost/digitalnadeemDrupal1/rest/digitalnadeem/api/get/node/article?_format=json

Headers are below
Content-Type : application/json
X-CSRF-Token : aXn6JKu_rhwZuPS-WNndwQls-hc2rKgOQWmcfCZ5mmg
Authorization : Basic YWRtaW46YWRtaW5AMTIz

And output is

{
"message": "Hello, this is a rest service and parameter is: article"
}

If your request is not in proper format , there will be a chance of getting client error

Creating a custom Rest resource for POST method

Next I am going to create an end point for posting data to Rest. I have created RestSamplepost.php file in plugin path

Src->Plugin->RestSamplepost.php

For  post method  you have to mention link relation in uri_paths . see below code for post.

<?php

namespace Drupal\digital_nadeem\Plugin\rest\resource;

use Drupal\rest\ModifiedResourceResponse;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

/**
 * Provides a resource to get view modes by entity and bundle.
 *
 * @RestResource(
 *   id = "rest_samplepost",
 *   label = @Translation("Rest samplepost"),
 *   uri_paths = {
 *     "https://www.drupal.org/link-relations/create" = "/rest/digitalnadeem/api/post/items"
 *   }
 * )
 */
class RestSamplepost extends ResourceBase {

  /**
   * Responds to POST requests.
   *
   * @return \Drupal\rest\ResourceResponse
   *   The HTTP response object.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
   *   Throws exception expected.
   */
  public function post($data) {

   // You must to implement the logic of your REST Resource here.
   $data = ['message' => 'Hello, this is a rest service and parameter is: '.$data->name->value];
	    
    $response = new ResourceResponse($data);
    // In order to generate fresh result every time (without clearing 
    // the cache), you need to invalidate the cache.
    $response->addCacheableDependency($data);
    return $response;
  }

}

Drupal 9 change 

in Drupal 9 use only “create ” in uri_paths as provided below.

* uri_paths = {
*
* "create" = "/rest/digitalnadeem/api/post/items"
* }

Flush cache and enable resource from Rest UI.

Apply all required settings.

If you are getting any issue with X-CSRF-Token , generate token from which tool you are using. Here I am generated token using Post man by calling a GET request using url http://localhost/digitalnadeemDrupal1/rest/session/token since I have already logged in I got new token.

Now apply you headers as below.

Here Post URL is   http://localhost/digitalnadeemDrupal1/rest/digitalnadeem/api/post/items?_format=json

Headers are given below

Content-Type: application/json

X-CSRF-Token: s4l2v7M1rdT5f5RInSDwdo_oHPtuwTviwW-gSFXGMWs

To get Authorization header select basic and provide credentials in Authorization tab

Then select body tab and select rwa option. Provide your parameters as Json text.

Here I am giving as name as key and nadeem as value.

Click Send button. You will get below output.

{
"message": "Hello, this is a rest service and parameter is: nadeem"
}

Now you successfully implemented custom post resource plugin.

You can download digital_nadeem custom module code with above  GET and POST resource plugin

From below link.

Download custom module free source code here-(Drupal 8).

Download custom module free source code here-Drupal 9 sample code.

How to set up Cors

there is a chance if your client side app whether it is Angular or react app , which will throw cross-domain origin is not allowed error in browser console. so in that case copy content from /sites/default/default.services.yml   and create a new file services.yml in the same directory.  Then enable cors and update other portions as below.

cors.config:
    enabled: true
    # Specify allowed headers, like 'x-allowed-header'.
    allowedHeaders: ['x-csrf-token','authorization','content-type','accept','origin','x-requested-with', 'access-control-allow-origin','x-allowed-header','*']
    # Specify allowed request methods, specify ['*'] to allow all possible ones.
    allowedMethods: ['*']
    # Configure requests allowed from specific origins.
    allowedOrigins: ['http://localhost/','http://localhost:3000','http://localhost:3001','http://localhost:3002','*']
    # Sets the Access-Control-Expose-Headers header.
    exposedHeaders: false
    # Sets the Access-Control-Max-Age header.
    maxAge: false
    # Sets the Access-Control-Allow-Credentials header.
    supportsCredentials: true

Read more: How to configure JSON API in Drupal

Read more: Drupal Rest API with paragraph type field




Get Free E-book
Get a free Ebook on Drupal 8 -theme tutorial
I agree to have my personal information transfered to MailChimp ( more information )
if you like this article Buy me a Coffee this will be an ispiration for me to write articles like this.

You may also like...