Remember the whole "waiter taking your order" analogy for RESTful web services? Yeah, it's been done to death. REST is like ordering food, and APIs are like waiters running between the kitchen and your table ..yada yada yada. 

But let's ditch the restaurant and try something fresh.

Let’s imagine you’re using a simple to-do list app.

You add tasks, check them off, and delete them when done. Now, what if you wanted a way to interact with your to-do list from anywhere? Like your phone, laptop, or even a voice assistant. That’s where RESTful web services come in.

Each task is a resource, and REST lets you interact with it using simple web requests like GET /tasks (fetch all), POST /tasks (add), PUT /tasks/1 (update), and DELETE /tasks/1 (remove).

Now, if you're using Drupal, you’re in luck. Drupal comes with built-in support for RESTful APIs. So, if you want to expose content, update user profiles, or integrate with external apps, Drupal’s RESTful APIs make it easy to connect and share data across platforms.

Hang on tight because we’re diving into more details on RESTful APIs and how Drupal handles RESTful services.

What are RESTful web services?

RESTful APIs are interfaces that expose data and services over the web using the REST (Representational State Transfer) architectural style. It is based on a set of principles that allow systems to communicate over the web using standard HTTP methods like GET, POST, PUT, and DELETE.

In the context of web development, RESTful Web Services provide a simple and efficient way for web applications to communicate with each other. RESTful APIs return data in formats like JSON or XML and adhere to the principles of statelessness, scalability, and separation of concerns.

Why Drupal & RESTful APIs?

Drupal, a robust content management system (CMS), can serve as a powerful backend platform for building dynamic websites and applications. One of its key strengths lies in its ability to integrate with external applications through RESTful APIs. By exposing content and functionality as APIs.

Getting started with RESTful web services in Drupal

1. Understanding Drupal's RESTful Web Services Module

In Drupal, the RESTful Web Services module provides the infrastructure needed to expose content and services through APIs. This module is included in Drupal Core, meaning that it is readily available and does not require any additional installation of third-party modules. However, additional modules such as Rest UI, Serialization, and HAL are often used in conjunction to format the data correctly and provide additional flexibility.

2. Setting Up RESTful Web Services in Drupal

To get started with RESTful Web Services in Drupal, you will need to enable the required modules:

1. Install Required Modules:

  • RESTful Web Services: Drupal Core provides a framework for exposing REST resources.
  • Serialization: This module ensures that Drupal can serialize data into formats like JSON or XML.
  • HAL (Hypertext Application Language): Optional, but useful for producing machine-readable links in API responses, especially for complex data structures.
  • Rest UI: Provides a user interface to manage all your REST resources.
  • HTTP Basic Authentication: Provides an HTTP Basic authentication provider.
  • Simple OAuth:  Provides an implementation of the OAuth 2.0 Authorization Framework RFC.

2. Enable Modules via the UI or Drush:

  • Navigate to Extend in the Drupal admin interface or use Drush commands to enable these modules. Eg drush en restui

3. Configure Basic REST Endpoints:

  • Once the modules are enabled, go to the Configuration → Web Services → REST page. Here, you can configure which entities you want to expose (e.g., nodes, users, taxonomy terms) and the HTTP methods (GET, POST, PATCH, DELETE) that are allowed.

Configuring RESTful API endpoints in Drupal

Enabling RESTful Resources

Drupal exposes several resources by default, including:

  • Nodes (Content types)
  • Users
  • Taxonomy terms
  • Comments

To enable or configure these resources, simply navigate to the REST configuration page and select the entities you want to expose.

Custom REST resources in Drupal 10

1. Enable the REST Module

Before customizing REST resources, ensure that the RESTful Web Services module is enabled. Also, enable Serialization and HAL if you need them for advanced data formats.

2. Custom REST Resource Creation

You can create custom REST resources by defining them in a custom module. A REST resource is defined using the RestResource class or by creating routes and controllers that handle custom data.

Example of Custom REST Resource Class

1. Create a custom module (e.g. custom_rest_resource).

The folder structure

Create an Info.yml file.

Create a permission.yml file.

2. Define your custom REST resource:

  • In your module directory (/modules/custom/custom_rest_resource), create a src/Plugin/rest/resource folder.
  • Inside this folder, create a custom resource file, e.g., CustomRestResource.php.

3. CustomRestResource.php:

<?php
namespace Drupal\custom_rest_resource\Plugin\rest\resource;

use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Cache\CacheableResponseInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\rest\Plugin\ResourceBase;
use Symfony\Component\HttpFoundation\Response;
use Drupal\rest\ResourceResponse;
use Psr\Log\LoggerInterface;
use Drupal\node\NodeInterface;

/**
* Provides a Custom REST Resource.
*
* @RestResource(
*   id = "custom_rest_resource",
*   label = @Translation("Custom REST Resource"),
*   uri_paths = {
*     "canonical" = "/api/v1/custom/resource/{id}",
*     "create" = "/api/v1/custom/resource"
*   }
* )
*/
class CustomRestResource extends ResourceBase {


 /**
  * A current user instance.
  *
  * @var \Drupal\Core\Session\AccountProxyInterface
  */
 protected $currentUser;


 /**
  * The entity type manager service.
  *
  * @var \Drupal\Core\Entity\EntityTypeManagerInterface
  */
 protected $entityTypeManager;


 /**
  * Constructs a Drupal\rest\Plugin\ResourceBase object.
  *
  * @param array $configuration
  *   A configuration array containing information about the plugin instance.
  * @param string $plugin_id
  *   The plugin_id for the plugin instance.
  * @param mixed $plugin_definition
  *   The plugin implementation definition.
  * @param array $serializer_formats
  *   The available serialization formats.
  * @param \Psr\Log\LoggerInterface $logger
  *   A logger instance.
  * @param \Drupal\Core\Session\AccountProxyInterface $current_user
  *   A current user instance.
  * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type_manager
  *   The entity type definition.
  */
 public function __construct(
   array $configuration,
   $plugin_id,
   $plugin_definition,
   array $serializer_formats,
   LoggerInterface $logger,
   AccountProxyInterface $current_user,
   EntityTypeManagerInterface $entity_type_manager) {
   parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
   $this->currentUser = $current_user;
   $this->entityTypeManager = $entity_type_manager;
 }


 /**
  * {@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('custom_rest'),
     $container->get('current_user'),
     $container->get('entity_type.manager')
   );
 }


 /**
  * Responds to GET requests. It will return serialize json format of node
  * object.
  *
  * @param $id
  *   Node id.
  */
 public function get($id) {


   if ($id) {
     // Load node
     $node = $this->entityTypeManager->getStorage('node')->load($id);
     if ($node instanceof NodeInterface) {
       $response = new ResourceResponse($node);
       // Configure caching for results
       if ($response instanceof CacheableResponseInterface) {
         $response->addCacheableDependency($node);
       }
       return $response;
     }
     return new ResourceResponse("Article you are looking for doesn't exist", 400);
   }
   return new ResourceResponse('Article Id is required', 400);
 }


 /**
  * Responds to POST requests.
  *
  * @param array $data
  *   The data to create a new resource.
  */
 public function post(array $data) {
   // Here you can handle the incoming data and create a new resource.
 }


 // Add PATCH, DELETE methods as needed.
}

Authentication Methods

To secure your API, you can choose from several authentication methods:

  • Basic Authentication: This is Simple but insecure for production environments. Suitable for quick development and testing.
  • OAuth2: This is More secure and is commonly used for production environments where third-party apps need access to your API.
  • Cookie-based Authentication: Suitable for front-end applications (e.g., Single Page Applications) that are on the same domain as the Drupal back-end.

Working with RESTful web services in Drupal

Making GET, POST, PUT, DELETE Requests

Once your API is configured, you can start making HTTP requests to interact with your Drupal site.

  • GET: Retrieves data. For example, a GET request to /api/v1/custom/resource/1 would retrieve the content of node 1.
  • POST: Creates new data. A POST request to /api/v1/custom/resource can create a new node.
  • PATCH: Updates existing data. A PUT request to /api/v1/custom/resource/1 would update node 1.
  • DELETE: Removes data. A DELETE request to /api/v1/custom/resource/1 would delete node 1.

Managing Caching and Performance

Caching is crucial for improving the performance of your RESTful API. Drupal provides several caching strategies, including HTTP caching headers, which can be used to cache responses and reduce server load.

Versioning APIs

To maintain backward compatibility, it's essential to version your API. You can include version numbers in the API's URL, such as /api/v1/custom/resource/1, and ensure that older versions continue to work while you introduce new features.

Common use cases for Drupal RESTful web services

  • Headless CMS: Serves as a backend for frontend frameworks (like React or Vue), separating content management from presentation.
  • Mobile Applications: Allow mobile apps to access and display Drupal content seamlessly.
  • Integration with Third-Party Services: Connect Drupal with other systems, such as CRM or eCommerce platforms, for enhanced functionality.
  • Content Syndication: Distribute content to multiple sites or platforms efficiently.
  • Custom Dashboards: Create tailored interfaces that interact with Drupal data via REST APIs.

Troubleshooting & debugging Drupal REST APIs

Common Issues

  • Missing HTTP Methods: Ensure that you have correctly configured the methods allowed for each resource.
  • Permissions Issues: Check the permissions for the API user roles to ensure that they can access the required data.

Debugging Tools

  • Watchdog: Use Drupal's built-in logging system to check for errors and warnings.
  • Postman/cURL: These tools can help you test your RESTful API by simulating requests and inspecting responses.

Error Handling

Proper error handling in your API ensures a better user experience. Return appropriate HTTP status codes (e.g., 404 for "Not Found", 500 for "Server Error", 200 for “Ok”) and include clear error messages.

Resources and learning

RESTful Web Services API:

Custom REST Resources:

API Security:

Final thoughts

Drupal’s RESTful services keep getting better, faster, safer, and more flexible. With an API-first approach, decoupled architectures are on the rise. Drupal gives you powerful REST API capabilities out of the box, plus options for custom resources and authentication. If you’re looking to build smarter, more connected digital experiences with Drupal, we’re here to help. Check out our Drupal development services to know what we can offer you. Or you could fill out this quick form to have someone from the team call you.

Contact us

LET'S DISCUSS YOUR IDEAS. 
WE'D LOVE TO HEAR FROM YOU.

CONTACT US SUBMIT RFP