B A C K
How to Override a REST Resource from Drupal Core

How to Override a REST Resource from Drupal Core

Knowledge

Sometimes projects require us to find innovative solutions. Recently, we needed to override a core REST resource in Drupal 8, and given the limited documentation available, we decided to share our solution.

The Premises of a Drupal 8 Override

Drupal 8 handles configuration in a unified way, with more features stored in core than in previous versions. This architectural choice means that overriding core functionality requires careful consideration to avoid system damage.

While Drupal 8 supports global `$config` overrides through `Drupal\Core\Config\ConfigFactory::get()`, REST resource overrides require a different approach. Drupal 8's core provides basic REST resources for system entities, but complex operations often require extending these base classes.

Step-by-Step Guide to Override a REST Resource

1. Create a New Class

First, create a class that extends the EntityResource class:

namespace Drupal\my_module\Plugin\rest\resource;

use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Drupal\node\Entity\Node;

/**
 * @RestResource(
 *   id = "my_custom_node_rest_resource",
 *   label = @Translation("Custom Node REST Resource"),
 *   uri_paths = {
 *     "canonical" = "/api/v1/node/{node}",
 *     "create" = "/api/v1/node"
 *   }
 * )
 */
class MyCustomNodeResource extends EntityResource {
  // ...
}

2. Implement Required Methods

Override the necessary methods from the parent class:

public function post($data) {
  // Your custom POST logic here
  $response = new ResourceResponse($result, 201);
  return $response;
}

public function patch($entity, array $data) {
  // Your custom PATCH logic here
  return new ResourceResponse($entity, 200);
}

3. Configure REST Resource Settings

Add the following to your module's configuration:

# config/install/rest.resource.my_custom_node_rest_resource.yml
langcode: en
status: true
dependencies:
  module:
    - my_module
    - serialization
id: my_custom_node_rest_resource
plugin_id: my_custom_node_rest_resource
granularity: resource
configuration:
  methods:
    - GET
    - POST
    - PATCH
  formats:
    - json
  authentication:
    - basic_auth

4. Implement Access Controls

Add proper access checking:

public function access($operation, array $args = []) {
  $entity = isset($args['entity']) ? $args['entity'] : NULL;

  switch ($operation) {
    case 'create':
      return $this->checkCreateAccess();
    case 'update':
      return $this->checkUpdateAccess($entity);
    default:
      return parent::access($operation, $args);
  }
}

5. Handle Exceptions

Implement proper error handling:

protected function handleException(\Exception $e) {
  watchdog_exception('my_module', $e);

  return new ResourceResponse([
    'error' => [
      'message' => $this->t('An error occurred while processing the request.'),
      'code'    => 500,
    ],
  ], 500);
}

Best Practices

  • Always maintain backward compatibility when possible.
  • Document your custom endpoints thoroughly.
  • Implement proper access controls.
  • Add comprehensive error handling.
  • Use dependency injection instead of static service calls.
  • Add proper request validation.
  • Include appropriate response headers.

Testing Your Custom Resource

Add PHPUnit tests to ensure your resource works as expected:

namespace Drupal\Tests\my_module\Functional;

use Drupal\Tests\rest\Functional\ResourceTestBase;

class MyCustomNodeResourceTest extends ResourceTestBase {
  // Test implementation
}

Common Pitfalls to Avoid

  • Not handling all HTTP methods properly.
  • Forgetting to update REST configuration after changes.
  • Inadequate error handling.
  • Missing access controls.
  • Not validating input data.
  • Improper response formatting.

By following these steps and best practices, you can successfully override Drupal 8 core REST resources while maintaining system stability and security.