By: Anmol
December 16 2018

Creating a Custom REST Resource for GET Method in Drupal 8

As the world gets more connected, web technologies too, need to get connected. RESTful web services can be used as an application program interface to connect various service.

This can be made possible by using HTTP requests to GET, PUT, POST and DELETE data. It is based on representational state transfer (REST) technology, an architectural style, and approach to communications often used in web services development. 

With decoupled development getting the ground, it has become important for the developers to understand teh REST technology better. Drupal provides its developers an in-house build method to use this REST technology. RESTful Web Services module, which is now a part of Drupal core, provides REST services to its developers. 

It allows users to read or update data on the site. 

Different verbs or request methods that are used for the approach are:

GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT and PATCH

The GET method allows the user to access various entities like Node, User, Taxonomy, Comments and even watchdog database log entries. GET method is a SAFE method as there is no database manipulation operation, it is a read-only request.

Unlike GET, in the POST method, database manipulation takes place. The user can update the database and create a node if need be. 

Creating REST Resource Plugins

REST resource plugins are important to expose additional resources over REST. In the steps below we will create a basic example for understanding the fundamental functionality of developing REST resource endpoint which takes a content type as argument and returns title and node ids of all nodes of that particular content-type.

  • Create the staging code for REST resource with the following Drupal console command:
drupal generate:plugin:rest:resource

You can also generate the staging code manually by creating a plugin file under src in the custom module > Plugin > Rest > Resource > {ResourceClassName}.php

Next, define the namespace, dependencies, and the plugin class as given in the example below.

  • Next, you need to create the @RestResource annotation. It helps you indicate the dependencies, and status of the class. Another important point to consider is that the URL mapping is case-sensitive.

    We must also be careful with the  @RestResource  annotation's urli_paths  which take link relation types as keys, and partial URIs as values. 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 rest_example, you'll end up with/rest_example/{id}  for GET|PATCH|DELETE and /rest_example for POST . But, often, you'll want to specify your own paths: a canonical URI path (for example /todo/{todo_id}). For example:

* uri_paths = {
 *     "canonical" = "/rest_example/{id}",
 *   }

Here’s how to get the complete REST resource GET request

<?php

namespace Drupal\rest_example\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_example",
 *   label = @Translation("Rest example"),
 *   uri_paths = {
 *     "canonical" = "/rest/api/get/node/{type}"
 *   }
 * )
 */
class RestExample 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.
    // Use current user after pass authentication to validate access.
    if (!(\Drupal::currentUser)->hasPermission('access content')) {
       throw new AccessDeniedHttpException();
     }
    if($type) {
      $nids = \Drupal::entityQuery('node')->condition('type',$type)->execute();
      if($nids){
        $nodes =  \Drupal\node\Entity\Node::loadMultiple($nids);
        foreach ($nodes as $key => $value) {
          $data[] = ['id' => $value->id(),'title' => $value->getTitle()];
        }
      }
    }
    $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;
  }

}

Output 

[
  {
    "id": "67",
    "title": "Consectetuer Sits"
  },
  {
    "id": "69",
    "title": "Eum Paulatim"
  },
  {
    "id": "70",
    "title": "Tation"
  }
]


Configuring the REST Resources

In the config file, we define which HTTP method, serialization format, and an authentication mechanism is supported by the plugin. 

This config file is necessary to use the REST resource plugin. There are two ways to configure the REST resource @RestResource plugin:

  1. REST UI Module
     
    • The REST UI module is not part of the core. So you have to download it and install it like any other module in your Drupal site.admin interface of rest UI

       

    • Once installed, go to  /admin/config/services/rest and enable your REST Resource.enabling the rest module

       

    • Select your desired settings. To have hal_json format, you can enable Drupal Core’s HAL module.admin interface to restrict HTTP
  2. Manually
    • Go to the config directory and create a config file with name as rest.resource.{resource id}.yml.
    • Add the following content.
langcode: en
status: true
dependencies:
  module:
    - rest_example
    - serialization
    - user
id: rest_example
plugin_id: rest_example
granularity: resource
configuration:
  methods:
    - GET
  formats:
    - json
  authentication:
    - cookie
  • Save this file as rest.resource.plugin_id.yml (rest.resource.rest_example.yml in this case) in your config directory and run config sync.

Defining your resource config:

Status: true/false ( enable or disable)
Id: unique id
Plugin_id: unique id
configuration=>methods: Name all request method you want to use in this plugin
configuration=>formats: Define all supported serialized format
configuration=>authentication: Name all supported authentication method.
By default, the REST module supports json and xml

Key Point: Each REST resource must be annotated with  @RestResource  annotation so they can be discovered by RESTful Web Services module.

Custom REST API is useful in sending data to third-party applications and for headless architecture. As of today, there is hardly any project or application that doesn't have a REST API. Connect with us at [email protected] to help you create