Skip to content
Field note

How to Create Custom RESTful Resources in Drupal 8

Introduction

July 20, 2017·2 min read·Abhishek Dhariwal, Senior DXP Consultant/ Field correspondent
How to Create Custom RESTful Resources in Drupal 8

Introduction

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

test_resource.route:

path: test/ws

defaults:

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

methods: [POST]

options:

_auth: [ 'basic_auth' ]

requirements:

_user_is_logged_in: 'TRUE'

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

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

access_webservice:

title: 'Access webservice'

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

  • test_resource.services.yml - Routing event subscriber.

services:

tal_webservice.route_subscriber:

class: 'Drupal\test_resource\Routing\RouteSubscriber'

tags:

- { 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.

<?php

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

<?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.

Companion brief

Bring this dispatch into a working session - one page in, scoping memo out.

Brief Foyer
Pressure-test "Field note" with a partner

If this dispatch landed, bring it into a room with us.

The argument in "How to Create Custom RESTful Resources in Drupal 8" is ours - but every situation breaks the argument differently. Send the situation in one page and a named partner will reply inside one business day with a scoping memo: where the argument holds for you, where it bends, and what we'd actually do in the first two weeks.

One-pager · Field note

By submitting this form you acknowledge that you have read Axelerant's Privacy Policy and agree to its terms.

Replied to by a named partner within one business day.