Drupal 8: Creando un recurso REST personalizado con un método GET

Cabecera Drupal 8: Creando un recurso REST personalizado con un método GET

Drupal 8: Creando un recurso REST personalizado con un método GET

  • Autor: fjavimartin

  • Fecha de Creación: 29/04/2019

  • Categorías:

    • Drupal,
    • Drupal 8,
    • Rest,
    • Json,
    • Custom,
    • Code snippets,
    • Php

El objetivo de esta entrada de blog será la creación de un recurso REST personalizado que implementará un método GET mediante el que obtendremos los 10 últimos nodos del tipo de contenido article que se hayan creado en nuestro sitio drupal.

1. RESTFul Web Services API

Otra de las características principales de esta versión de drupal es la integración de la API para la creación de servicios web en el core. Esta API nos permitirá exponer entidades directamente como recursos REST accediendo a su contenido con los siguientes métodos:

- GET: Acceso al contenido de las entidades.

- POST: Creación de entidades.

- PATCH: Actualización de entidades.

- DELETE: Eliminación de entidades.

Por defecto, esta API soportará tanto XML como JSON y mediante la instalación del módulo HAL podremos utilizar el formato HAL-JSON lo que nos dará gran flexibilidad a la hora de exponer los resultados de la ejecución de nuestros web services.

2. RESTFull Web Services personalizados

Aún pudiendo utilizar de una manera fácil y sencilla la API que nos ofrece drupal muchas veces nuestras necesidades son demasiado personalizas como para poder entrar en el corsé que nos ofrecen por lo que tenemos que buscar otras opciones para el desarrollo de nuestros web services.

Unos de los motivos más simples es que cuando estamos utilizando la API de drupal necesitamos incluir en la url de nuestro servicio web el formato con el que queremos que nos sean devueltos los resultados siendo necesario incluir el parámetro _format=formato obligatoriamente:

_format=json

_format=xml

En multitud de ocasiones tendremos que implementar un web service que ya existía, con una url fijada y que no podremos modificar introduciendo el parámetro anterior. En estos casos tendremos que implementar el web service desde cero y de una manera manual. No os preocupéis, no es extra complicado y será el caso que abordemos en esta entrada de blog.

Para la implementación de un endpoint vamos a necesitar añadir la ruta del mismo a nuestro fichero routing e implementar un controlador que gestione las solicitudes…...fácil, no? Pues vamos al lío.

3. Añadir ruta al routing.yml

Hace tiempo que escribí un artículo en este mismo blog (tenéis el enlace en referencias) en el que os enseñaba como crear el primer módulo en drupal 8, pues bien, la ruta que añadiremos no difiere mucho de la que utilicé en aquel artículo.

drupal_miseries.customrest:
  path: '/drupal_miseries/rest/customrest'
  defaults:
    _controller: '\Drupal\drupal_miseries\Rest\CustomRest::getLatestNodes'
  methods: [GET]
  requirements:
    _access: 'TRUE'

Paso a comentar las distintas partes de la ruta:

- path: Será el path que nos dará acceso a nuestro endpoint.

- _controller: Será el nombre de la clase controlador que se encargará de gestionar la solicitud.

- methods: Para este artículo consultaremos información de distintas entidades por lo que utilizaremos el método GET.

- _access: Para no complicar en exceso este ejemplo y no despistar dejaremos a TRUE para que todo el mundo tenga acceso a nuestro endpoint.

4. Implementación de la clase controlador

Como veréis en el código, no difiere mucho de una clase controladora normal:

namespace Drupal\drupal_miseries\Rest;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;

class CustomRest extends ControllerBase {
  protected $entityTypeManager;
  
  /**
   * Construct implementation.
   * @param EntityTypeManagerInterface $entityTypeManager
   */
  public function __construct(EntityTypeManagerInterface $entityTypeManager) {
    $this->entityTypeManager = $entityTypeManager;
  }
  
  /**
   * Create implementation.
   * @param ContainerInterface $container
   * @return \Drupal\drupal_miseries\Rest\CustomRest
   */
  public static function create(ContainerInterface $container) {
    return new static (
      $container->get('entity_type.manager')
    );
  }
  
  /**
   * Return 10 last nodes created in a Json.
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   */
  public function getLatestNodes() {
    $response_array = array();
    
    // Get node storage from entitytype.manager service.
    $node_storage = $this->entityTypeManager->getStorage('node');
    
    // Exe a query that return 10 last nodes created.
    $query = $node_storage->getQuery()
    ->condition('type', 'article')
    ->condition('status', 1)
    ->sort('changed', 'DESC')
    ->range(0, 10)
    ->execute();
    
    // Check if query not return value
    if (!empty($query)) {
      // Load all returned nodes.
      $nodes = $node_storage->loadMultiple($query);
      foreach ($nodes as $node) {
        // Get node title and add to return array.
        $response_array[] = [
          'title' => $node->get('title')->value,
        ];
      }
    } else {
      $response_array[] = [
        'message' => $this->t('No nodes stored.'),
      ];
    }
    
    // Transform array in a Json response.
    $response = new JsonResponse($response_array);
    
    return $response;
  }
}

En nuestra clase controladora heredamos de ControllerBase y añadimos el servicio entity_type.manager que nos dará acceso a las entidades node que serán las que dan forma a los article que queremos acceder.

Lo siguiente será implementar el método getLatestArticles que devolverá el json con la información de estos 10 nodes.

// Get node storage from entitytype.manager service.
    $node_storage = $this->entityTypeManager->getStorage('node');
    
    // Exe a query that return 10 last nodes created.
    $query = $node_storage->getQuery()
    ->condition('type', 'article')
    ->condition('status', 1)
    ->sort('changed', 'DESC')
    ->range(0, 10)
    ->execute();

En este código obtenemos la clase que nos dará acceso al almacenamiento de las entidades node y con una simple query pediremos todos los node de tipo article, en estado publicado, ordenados por fecha de modificación y solamente los 10 últimos.

$response_array[] = [
          'title' => $node->get('title')->value,
        ];

De cada uno de los articles devueltos solamente nos interesa el título que será lo que añadamos al array con los resultados.

// Transform array in a Json response.
    $response = new JsonResponse($response_array);

Aquí es donde sucede la magia, transformamos el array en el que hemos ido almacenando la información de los distintos article en una respuesta json que será lo que finalmente devolvemos desde el navegador y que será lo que consuma la aplicación que hace la llamada.

[{"title":"Illum Neo Quadrum"},{"title":"Causa Dolor Euismod Proprius Tamen"},{"title":"Distineo Dolor Ex Hos Ille Turpis"},{"title":"Abluo Dolore Jugis Turpis Ymo"},{"title":"Vicis"},{"title":"Vindico"},{"title":"Verto"},{"title":"Ille"},{"title":"Camur Ex Te Veniam"},{"title":"Similis"}]

Conclusiones

En este artículo he descartado la implementación del endpoint siguiendo la API que drupal 8 nos ofrece, pero aún así no es una mala idea….tarde o temprano siempre habrá algo que no nos permita hacer y tendremos que decidirnos por la implementación personalizada, de ahí que en este artículo haya empezado, quizás, por el final.

Espero que esta entrada os haya resultado útil y como siempre…..Disfrutar!!!!!!!!!

Referencias

https://www.drupal.org/docs/8/api/restful-web-services-api/restful-web-services-api-overview

https://www.drupal.org/docs/8/api/entity-api/access-on-entities-tbd

https://www.drupal.org/docs/8/core/modules/rest/1-getting-started-rest-configuration-rest-request-fundamentals

https://www.e-quipos.es/blog/drupal-8-nuestro-primer-m%C3%B3dulo

https://git.drupalcode.org/sandbox/javier.martin-2911003/blob/develop/drupal_miseries/src/Rest/CustomRest.php

https://git.drupalcode.org/sandbox/javier.martin-2911003/blob/develop/drupal_miseries/drupal_miseries.routing.yml

Todos los Derechos Reservados © 2016

Funciona con Drupal