home
Hero image for: How to create a Rest Resource in Drupal 8

How to create a Rest Resource in Drupal 8

By Eduardo García ● CTO | December 16th, 2014

One of the most significant changes in Drupal 8 is his integration with RESTful.

Today I want to share with you how to create Rest Resources in a custom module to publish your website information using a RESTful API.

I will create a new REST Resource with the objective to get the list of bundle types available for a specific entity.

Create a Module

I will skip the explanation about how to create a Module in Drupal 8 because could be generated using the project Drupal Console executing the following command.

$ php console.phar generate:module

Create a new REST Resource

Assuming we create a new module named entity_rest_extra is required to create a class file EntityBundlesResource.php inside the module in a folder path src/Plugin/rest/resource.

##Namespace

The namespace for this new Rest Resource will be

namespace Drupal\entityrestextra\Plugin\rest\resource;

Libraries

We must use some dependencies to create the REST Resource, below the full list.

use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Psr\Log\LoggerInterface;

Annotations

To enable the Discover for REST Resources found our new Rest Resource we must to implement the proper information in Annotation. Check the following example.

/**

  • Provides a resource to get bundles by entity.
  • *
  • @RestResource(
  • id = "entity_bundles",
  • label = @Translation("Bundles by entities"),
  • uri_paths = {
  • "canonical" = "/bundles/{entity}"
  • }
  • ) */
">
 line-numbers">">

As you can see we provide a Resource id with a label, also we define the canonical URL for our REST Resource with a parameter named entity

Using the annotation the Discover for Rest Resources will declare the routing dynamically, so we don’t need to include a routing.yml file in our module.

Implement Class

Now we have to create a class extending from ResourceBase as you can see in the following snippet

class EntityBundlesResource extends ResourceBase {
  /**
   *  A curent user instance.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;
  /**
   *  A instance of entity manager.
   *
   * @var \Drupal\Core\Entity\EntityManagerInterface
   */
  protected $entityManager;
}

Our implementation require two properties for Current User and EntityManager.

Class Setup

As you can imagine each class requires a constructor and Drupal 8 is not the exception, but Drupal also implement The Factory Pattern to prepare the values to send to the constructor.

But is better to explain to you with the following example where we need to send the services: Resource Format, Logger, Entity manager and Current User to the constructor.

/**

  • {@inheritdoc} */ public static function create(ContainerInterface $container,   array $configuration, $pluginid, $plugindefinition) { return new static( $configuration, $pluginid, $plugindefinition, $container->getParameter('serializer.formats'), $container->get('logger.factory')->get('rest'), $container->get('entity.manager'), $container->get('current_user') ); }
">
 line-numbers">">

Now we need to define the constructor where we are receiving the values from the create method, as you can see below.

/**

  • 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. */ public function construct( array $configuration, $pluginid, $plugindefinition, array $serializerformats, LoggerInterface $logger, EntityManagerInterface $entitymanager, AccountProxyInterface $current_user) { parent::construct($configuration, $pluginid, $plugindefinition,   $serializer_formats, $logger);
$this->entityManager = $entity_manager;
$this->currentUser = $current_user;

}

">
 line-numbers">">

Implement REST method

Last but not least we have to define the RESTful state we want to implement, in my example, I want to apply a GET method to response according to the parameters.

Inside the class with have to create a method matching the RESTful state name, so for GET, we have to implement a method named get as you can see in the following snippet.

  /*
   * Responds to GET requests.
   *
   * Returns a list of bundles for specified entity.
   *
   * @return \Drupal\rest\ResourceResponse
   *   The response containing a list of bundle names.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
   */
  public function get($entity = NULL) {
    if ($entity) {
      $permission = 'Administer content types';
      if(!$this->currentUser->hasPermission($permission)) {
        throw new AccessDeniedHttpException();
      }
      $bundles_entities = 
  \Drupal::entityManager()->getStorage($entity .'_type')->loadMultiple();
      $bundles = array();
      foreach ($bundles_entities as $entity) {
        $bundles[$entity->id()] = $entity->label();
      }
      if (!empty($bundles)) {
        return new ResourceResponse($bundles);
      }
      throw new 
  NotFoundHttpException(t('Bundles for entity @entity were not found', 
  array('@entity' => $entity)));
    }

    throw new HttpException(t('Entity wasn\'t provided'));
  }

Also using the Account Proxy Interface, we can determine if Current User has enough rights to get the bundle list.

The Entity Manager Interface allows us to we get the list of bundles for Entity requested.

After that we prepare an array with the results, these results will be transformed to the proper format requested by the user using the class ResourceResponse, in our case, we will request a JSON response.

If you want to implement RESTful state POST add a method post

You can see a full and functional custom REST Resources at https://github.com/enzolutions/entity_rest_extra

Using our new Resource

Utilizing the contrib module Rest UI (I recommend to use the git version until Drupal 8 get the first release), you can enable your custom Rest Resource.

This module enables a UI to set the Authentication and format for each RESTful method implemented as you can see in the following image.

restui bundle entities settings

Using this setting the access to Resource will be granted or denied.

Using the Chrome Application Postman - REST Client you can execute an authenticated request to URL http://example.com/bundles/node as you can see in the following image.

postman rest request

If all is working as expected, you will get a similar result to following JSON output.

{ "article": "Article", "page": "Basic page" }

I hope you find this blog entry useful.

Related Posts