<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=278116885016877&amp;ev=PageView&amp;noscript=1">

, , ,

Jul 20, 2017 | 1 Minute Read

How to Create Custom RESTful Resources in Drupal 8

Table of Contents


The RESTful Web Services API is new in Drupal 8. Expose entities as RESTful resources either to build a decoupled Drupal site, to let a native mobile iOS/Android app talk consume/feed a Drupal site, or to integrate with some web service which is amazing! In some use cases, these default REST resources are not sufficient to fulfill the requirements. In this situation, we have to write a custom REST resource. Let’s examine how we can develop this.

Before proceeding further, first let’s see a use case where the user has to write a custom REST resource. If a user wants to submit a file along with some metadata using a single webservice call currently it is not possible with the default REST resources.

Now, let’s build our own REST resource for the above use case.

Test Resource module (test_resource.module) contains the following files:

  • test_resource.info.yml - Module .info file
  • test_resource.module - Empty module file
  • test_resource.routing.yml - Routing file with all the API paths


path: test/ws


  _controller: 'Drupal\test_resource\Controller\TestResourceController::create'

methods:  [POST]


  _auth: [ 'basic_auth' ]


    _user_is_logged_in: 'TRUE'

    _custom_access: '\Drupal\test_resource\Controller\TestResourceController::access'

  • test_resource.permissions.yml - Permission file to define custom permission


title: 'Access webservice'

description: 'Gives permission to the user to access the webservice.'

  • test_resource.services.yml - Routing event subscriber.



  class: 'Drupal\test_resource\Routing\RouteSubscriber'


    - { name: event_subscriber }

  • src/Routing/RouteSubscriber.php

It is good practice to use a CSRF token with REST request. Here, at the event subscriber class for routing, we are setting CSRF token as a requirement.


namespace Drupal\test_resource\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;

use Symfony\Component\Routing\RouteCollection;


* Route subscriber class.


class RouteSubscriber extends RouteSubscriberBase {


 * {@inheritdoc}


 * Add a CSRF-Token  as requirement.


public function alterRoutes(RouteCollection $collection) {

  if ($route = $collection->get('tal_webservice.ingredient')) {

    $route->setRequirement('_access_rest_csrf', 'TRUE');




  • src/Controller/TestResoutceController.php


namespace Drupal\test_resource\Controller;

use Drupal\Core\Session\AccountInterface;

use Symfony\Component\HttpFoundation\Request;

use Symfony\Component\HttpFoundation\JsonResponse;

use Drupal\Core\Access\AccessResult;


* Process Resource REST request.


class TestResourceController {


 * Allow access for logged-in, authenticated users.


 * @param \Drupal\Core\Session\AccountInterface $account

 *   Run access checks for this account.


 * @return bool

 *   Return true or false on the basis of criteria specified.


public function access(AccountInterface $account) {

  return AccessResult::allowedIf($account->hasPermission('access_webservice'));



 * Process REST request.


public function create(Request $request) {

  if (strpos($request->headers->get('Content-Type'), 'multipart/form-data;') !== 0) {

    $res = new JsonResponse();

    $res->setStatusCode(400, 'must submit multipart/form-data');

    return $res;


  // Validate the request data.

  $error = $this->validate($request);

  if ($error !== TRUE) {

    return new JsonResponse($error, 400);


// Here your business logic goes.

  try {

      $data = file_get_contents($_FILES['files']['tmp_name']);

      $destination = 'public://' . $request->request->get('file_name');

      $file = file_save_data($data, $destination, FILE_EXISTS_REPLACE);


  catch (\Exception $error) {

    return new JsonResponse($error->getMessage(), 400);


  return new JsonResponse(‘Request processed successfully’, 200);




 * Validate the POST data.


private function validate(Request $request) {

  $error = '';

  // Material Id is mandatory.

  if ($request->request->get(metadata) == '') {

    $error = t('Invalid post data, metadata was missing.');

    return $error;


     return TRUE;



That's it! We hope you found this post helpful.

If you have any questions, do share them with us in the comments below. 

About the Author
Abhishek Dhariwal, Senior DXP Consultant
About the Author

Abhishek Dhariwal, Senior DXP Consultant

Abhishek is a true explorer—whether it’s different cuisines, places, or subjects, he enjoys it all. He reads at least two newspapers daily, values attention to detail, and prioritizes thoughtful solutions over quick fixes. Away from work, you can find this technophile enjoying TV Series.

Back to Top