Headless Drupal. A strange naming for a fine CMS. Well, it is nothing but a decoupling of frontend and backend architectures within a website development project. ‘Headless’ aka “Decouple CMS Architecture” is gaining popularity as it allows developers to create a great user experience, provide greater flexibility for innovation and website owners the liberty to refresh the whole website design without re-doing the whole CMS.

Headless commerce will be the mainstay of eCommerce portal development services. It has the decoupled UI approach that provides increased flexibility for intuitive user experience. Let’s understand what is headless Drupal, its usage, benefits and how to use REST services with custom resources.

What is Headless Drupal?

When your website’s presentation is separated from the commerce stack as in frontend is decoupled from the backend is called as a headless commerce architecture. They’re the modern platforms without the frontend ‘head’ and that is the reason it is called a headless architecture. Drupal being the CMS here, we will call it as Headless Drupal.

It alleviates you from the backend commerce setup for your ecommerce stores and websites. It is an architecture that allows additional flexibility, customization, enhanced shopping experiences and creative freedom for developers to build superior Drupal based web portal development.

Why Use Headless Drupal?

Decoupled or headless website development will allow frontend developers to use creativity for rich user experience. The headless model will shift the user experience module to another application to handle meaning providing greater flexibility and benefits such as:

Seamless Shopping Experience

Utilize Portable Backends

Use better Frontends

Drupal Community Support

Use JAMstack

The next question in-line is how to build customer resources with Drupal 8 REST services. Let’s look at them in detail.

What is a Web service?

A web service is a mechanism to managed code that can be remotely invoked using HTTP. Web services exchange the information over the networks like the Internet.

Why Web Services?

Web services allow to expose the functionality of existing code over the networks, so that other applications can use them to utilize the same functionality in their application. It makes the application platform and technology agnostic.

There are two type of web service protocols which are most commonly used in web applications:

SOAP
REST

Here we will only discuss about REST services:

Representational State Transfer(REST) is an architecture style for designing loosely coupled web service. Rest is mainly used to develop lightweight, fast, scalable and easy to maintain, web service that used to be HTTP.

A RESTful API more benefit of HTTP methodologies defined by RFC 2616 protocol. Which is used some methods [GET, POST, PUT,DELETE]. GET to fetch a resource. PUT to update the resource, POST to create the resource and DELETE to remove it.

Restful service popularity increased:

  • REST itself is not protocol and it is accessed using HTTP protocol only.
  • Unlike SOAP, we can use REST services for different type of response such as JSON, XML.
  • While using REST services, we can even implement different caching mechanism to improve performance.
  • We do not require tools or technology for using REST services.
  • REST works on HTTP protocol and does not require any other software so coupling between application servers and REST are minimal.

Using Restful services In Drupal:

One of the major feature with Drupal 8 release is, it’s support for Restful services. Till Drupal 7, for creating any services in Drupal, one has to rely on contributed modules. Contributed modules in Drupal 7 provides limited exposure of drupal features.

Since the evolution in the frontend technologies, Drupal community has also feel it essentials to provide it’s customer a framework which can easily decouple it’s frontend. So Drupal has been built in a way where any frontend technologies can be integrated with drupal with ease. Drupal 8 out of the box provides number of REST APIs for all of it’s core component, thus making it possible to create a Headless Drupal 8 application with maximum utilization of the out of the box APIs.

REST API in Drupal 8 uses JSON as the response format. JSON format is globally used and expected format for creating Web application, Mobile Apps or integrating Drupal 8 with any other third party applications.

Drupal 8 uses 4 core modules for exposing REST APIs as mentioned in following screenshot.

required-modules

Core REST:

The core REST modules allow all content entities (nodes, users, taxonomy terms, comments) to be exposed as JSON+HAL or as JSON, representing Drupal’s internal storage. Views natively support “REST export” as a new display type.

Serialization:

Serialization concept is new in Drupal 8 it is based on Symfony Serializer Component. It performs serialization of data which changes arrays into data formats such as JSON or XML.

RESTful Web Services:

Allows HTTP methods to be performed on existing resources including but not limited to content entities and views (the later facilitated through the “REST export” display in Views) and custom resources added through REST plugins.

HAL:

Hypertext Application Language(HAL) module serializes drupal entities. HAL is a generic media type that provides for web API exposed series of links.

REST UI module:

REST UI is a contributed module. It provides GUI for API listing and configuration options instead of updating through YML files.

After the Enabling required modules. Rest UI modules gives you available resources list.

Rest-UI-modules

So let’s create an example module for Creating a node with Rest API. To create a custom rest service resource in Drupal 8, below files are required.

Mention files Structure :

  1. example_node_rest.info.yml
  2. ExampleNodeRestResource.php
example-node-rest

Step 1: Create an example_node_rest.info.yml file defined the metadata of module.

Code Snippet:

name: 'example_node_rest'
type: module
description: 'Example module for Node create with Rest service.'
core: 8.x
package: 'Example'

Step 1: Create an example_node_rest.info.yml file defined the metadata of module.

Code Snippet:

Your module will start showing up in the list of available modules. But as we have not defined any service, it will not give us any functionality.

Step 2: Now we will create resource file to define our restful methods. We will take an example of creating and updating a node using restful service

Let’s create rest resource with GET & POST method.

Create a ExampleNodeRestResource.php file in which defined our resource Name, ID and Methods.

Path: src\Plugin\rest\resource\ExampleNodeRestResource.php

For Example :

/**
* Provides a resource to get view modes by entity and bundle.
*
* @RestResource(
* id = "example_node_rest_resource",
* label = @Translation("Example node rest resource"),
* serialization_class = "Drupal\node\Entity\Node",
* uri_paths = {
* "canonical" = "/example-node-rest",
* "https://www.drupal.org/link-relations/create" = "/example-node-rest"
* }
* )
*/
Code Snippet:

currentUser = $current_user;
      }
 
      /**
       * {@inheritdoc}
       */
      public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
        return new static(
          $configuration,
          $plugin_id,
          $plugin_definition,
          $container->getParameter('serializer.formats'),
          $container->get('logger.factory')->get('example_node_rest'),
          $container->get('current_user')
        );
      }
 
      /**
       * Responds to POST requests.
       *
       * @param \Drupal\Core\Entity\EntityInterface $entity
       *   The entity object.
       *
       * @return \Drupal\rest\ModifiedResourceResponse
       *   The HTTP response object.
       *
       * @throws \Symfony\Component\HttpKernel\Exception\HttpException
       *   Throws exception expected.
       */
      public function post($node_data) {
        // You must to implement the logic of your REST Resource here.
        // Use current user after pass authentication to validate access.
        if (!$this->currentUser->hasPermission('access content')) {
          throw new AccessDeniedHttpException();
        }
        if($node_data->nid->value == ''){
            $node = Node::create(
              array(
                'type' => $node_data->type->target_id,
                'title' => $node_data->title->value,
                'body' => [
                  'summary' => '',
                  'value' => $node_data->body->value,
                  'format' => 'full_html',
                ],
              )
            );      
            $node->save();           
        }elseif($node_data->nid->value != '' && is_int($node_data->nid->value)){
            $values = \Drupal::entityQuery('node')->condition('nid', $node_data->nid->value)->execute();
            $node_exists = !empty($values);
                if($node_exists){
                    $node = Node::load($node_data->nid->value);
                    //Title field set 
                    $node->setTitle($node_data->title->value);
                    //Body can now be an array with a value and a format.
                    //If body field exists.
                    $body = [
                    'value' => $node_data->body->value,
                    'format' => 'basic_html',
                    ];
                    $node->set('body', $body);
                    $node->save();
                    //return new ResourceResponse($node);
                }else{
                    \Drupal::logger('example_node_rest_api')->error('Node nid '.$node_data->nid->value.' not exists' );
                    return new ResourceResponse(array('Error'=>'Node nid not exists'));
                }       
        }else{  
            return new ResourceResponse(array('Error'=>'Data not corrected'));
        }
        return new ResourceResponse($node);     
      }
       
         
     /**
       * Responds to GET requests.
       *
       * Returns a list of bundles for specified entity.
       *
       * @throws \Symfony\Component\HttpKernel\Exception\HttpException
       *   Throws exception expected.
       */
      public function get() {
        // You must to implement the logic of your REST Resource here.
        // Use current user after pass authentication to validate access.
        if (!$this->currentUser->hasPermission('access content')) {
          throw new AccessDeniedHttpException();
        }
        $entities = \Drupal::entityTypeManager()
          ->getStorage('node')
          ->loadMultiple();
        foreach ($entities as $entity) {
          $result[$entity->id()] = $entity->title->value;
        }
        $response = new ResourceResponse($result);
        $response->addCacheableDependency($result);
        return $response;
      }
 
    }
?>

Step 3: To configure our custom Rest Resource, we will go to Rest UI and do configuration as shown in below screen shot. We have used cookie based authentication for this example.

Rest-UI-and-do-configuration

Step 4: To configure our custom Rest Resource, we will go to Rest UI and do configuration as shown in below screen shot. We have used cookie based authentication for this example.

GET Result:

Result

To create node with POST Method, we will require X-CSRF-Token.

X-CSRF-Token provides by rest session token url e.g rest/session/token

For example:

X-CSRF-Token = L1R6f5y5tmgzQnRB-30HR6-zoh0aY_bZX01DQCxIKHk

POST Result:

Post-Result
If you need to perform update the particular node id, you have to pass node id in body nid json field.

For Example:

{
"type": [{
"target_id": "article"
}],
 
"title": [{
"value": "Article created by REST API "
}],
 
"body": [{"value": "Rest api node create demo"}],
"nid": [{"value": "10"}]
}

Go to drupal admin content listing page. Node is created.
content-listing-page

Blog Written By Chintan Mehta

Hadoop to Snowflake New Web
capptixAI-case-study
lendingAI-logo_opt
CustomerAI_Logo_700x300 copy
sales-ai-logo-500x200