Usando Drupal como

motor de servicios

(XML, JSON, otros...)


http://ibonelli.github.io/drupalstuff/

¿Quien soy yo?

  • Ignacio J. Bonelli (Ingeniero en Electrónica)
  • Casi toda mi carrera profesional trabajando en sistemas
  • Trabajo para Tincan (DrupalShop UK)
  • Docente de Informática1 en la UTN (programación en C)
  • Fan de Linux y el Opensource
  • Y en mis tiempos libres:

    • Padre de dos
    • Fan de todo lo referente a SciFi
    • Deporte! Correr, nadar y remar.

    Mas sobre mi y contacto: www.nachodigital.com.ar

¿Por que usar Drupal como gestor de servicios?

  • Motor de aplicación movil
  • Headless Drupal
  • Integración general


En resumen, poder exponer los datos de
Drupal de otra manera: JSON, XML, otros...

Drupal 7

Drupal 8

  • ¡Integrado en core!
  • 4 módulos ya integrados + REST UI
  • Una vez habilitado:
    Configuration -> Web services -> REST


Para Drupal7 también existe otro módulo llamado
RESTful Web Services, pero no es tan usado.

Mucho de lo que nos dan solo necesita
configuración y un poco de conocimientos generales
de Drupal y su estructura de datos.



Servers

SOAP (Simple Object Access Protocol)

  • Originalmente diseñado por Microsoft
  • Luego pasado al IETF para estandarizarlo
  • Solo trabaja con XML para pedidos y respuestas
  • Puede trabajar sobre diversos protocolos. Normalmente trabaja sobre HTTP, se usa sobre SMTP y otros...
  • Mas complicado, pero mas robusto
  • Aconsejable para aplicaciones que necesitan alta confiabilidad como un giro bancario desde mi teléfono.

REST (Representational State Transfer)

  • Nació luego de SOAP como una alternativa sencilla
  • Pensado 100% para la web
  • Con un esquema basado en HTTP: Soporta GET, POST, PUT y DELETE
  • Soporta intercambios en JSON, XML, CSV, RSS, etc...
  • Se debe describir la interface en forma externa
  • Mejor performance y escalabilidad. ¡Permite caching!
  • Mas sencillo para trabajar con JavaScript (¡no XML!)

REST vs SOAP


Resumiendo:

  • La mayoría de las APIs fueron migrando a REST
  • REST es mas sencillo de apreender y usar
  • El soportar caching lo hace muy atractivo


Articulos:

Drupal 7

(configurando)

Install D7



drush dl -y services ; drush en -y services rest_server
drush dl -y services_entity ; drush en -y services_entity
drush dl -y libraries ; drush en -y libraries
    

El REST server viene con el módulo services, pero si queremos SOAP debemos bajar el módulo SOAP Server

Creando un servicio (I)

Structure -> Services

Creando un servicio (II)

Configurando un servicio: Node (I)

admin/structure/services/list/myservice/resources

Autenticación:

(Session authentication)

"Choose which authentication schemes that should be used with your endpoint. If no authentication method is selected all requests will be done by an anonymous user."

Esto significa que el usuario que hace el pedido es annonymous para Drupal. Por lo tanto los permisos sobre nodos (en este caso) nos van a afectar.

Una alternativa será usar Basic Auth y otra hacer un login via REST service.

Permisos para anonymous:

/admin/people/permissions

Configurando un servicio: Node (II)

  • Create:
    POST /[endpoint_path]/[resource] + BodyData
  • Retrieve:
    GET /[endpoint_path]/[resource]/[resource_id]
  • Update:
    PUT /[endpoint_path]/[resource]/[resource_id] + BodyData
  • Delete:
    DELETE /[endpoint_path]/[resource]/[resource_id]
  • Index:
    GET /[endpoint_path]/[resource]


Drupal service's docs: Working with REST Server

Herramientas

(agregados a Firefox)


Poster

    POST content:

    Configurar headers:

Ver un Nodo (retrieve)

GET http://misitio.com/api/node/13.json

Creando Nodo (create)

GET http://misitio.com/api/node

JSON data: {"title":"Mi nodo via REST","type":"page",...}

IMPORTANTE: ¡Ser anónimo! (private window => no logueado)

    POST:

    Resultado:

    Resultado: "200 OK"

    JSON: {"nid":"54","uri":"http://drupal7s.local/api/node/54"}

¿Como saber la estructura del nodo?

Usamos el módulo devel

Usando Basic Auth (config)

Usamos el módulo Services Basic Authentication

Pasos:

  • Una vez instalado, configuramos el servicio para usar Basic Auth:
    http://misitio.com/admin/structure/services/list/myservice
    Hacer check en la casilla "HTTP basic authentication"
  • Agregar un usuario (en mi caso ignacio/nopass)
  • Agregar permisos para el tipo de contenido a usar (article):

Usando Basic Auth (POST)

Basic auth protocol:

  • Usamos un header especial:
    • Header: "Authorization"
    • Content: "Basic <base64 de username:password>"
  • En un shell:
    echo "ignacio:nopass" | base64
  • Resultado: "Authorization: Basic aWduYWNpbzpub3Bhc3MK"

    POST content:

    Configurar headers:

Métodos de autenticación:

  • No auth: Ok para GET, puede ser peligroso para POST.
  • Basic auth: Simple, pero nada va cifrado (por ser HTTP).
  • Drupal's auth: Un poco mas complicado,
    require exponer user/system:
    1. user/login:
      {"username":"<user>","password":"<pass>"}
      Retorna: sessid, session_name y token
    2. system/connect:
      Toma header "X-CSRF-Token" con el valor recibido <token>
    3. Operaciones logueado...
      Operaciones logueado con el header "X-CSRF-Token"
    4. user/logout:
      Toma header "X-CSRF-Token" y también "Cookie"
      (formado por <session_name>=<sessid>)

Services entities

(módulo que extiende services)

Nos permite extenter los servicios
a cualquier tipo de entidad:

Incluso extensiones como field collection

Drupal 7

(programando)

Como lo hacemos:

  • Crearemos via código un servicio a exponer
  • Va a compartir la misma estructura que vimos hasta ahora
  • Lo que hace el servicio lo podremos manejar nosotros

Implementamos hook_services_resources():


function myintegration_services_resources() {
  $items = array(
    'report' => array(
      'operations' => array(
        'create' => array(
          'help' => 'Creating Report',
          'callback' => '_create_report',
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'access arguments append' => FALSE,
          'args' => array(
            array(
              'name' => 'report_data',
              'type' => 'array',
              'description' => 'Submited Report Details',
              'source' => 'data',
              'optional' => FALSE,
            ),
          ),
        ),
      ),
    ),
   );
  return $items;
 }
    

Implementamos la funcion que maneja el servicio:


function _create_report($report_data) {
  $server_info =  services_server_info_object();
  if (!empty($server_info->debug)) {
    watchdog('MiServicio', 'Gotten data = 
@report_data
',array('@report_data' => print_r($report_data, TRUE)),WATCHDOG_DEBUG); } // Make sure we got the report data if(empty($report_data)) { watchdog('MiServicio', 'No data sent!',NULL,WATCHDOG_WARNING); return array("response"=>"Failed, missing report data."); } // Create a new node to store report information $new_node = new stdClass(); $new_node->type = "report"; // Continua...

Como debe terminar mi servicio:


  // Continuando...
  if (!empty($server_info->debug)) {
    watchdog('MiServicio', 'Updated node = 
@new_node
',array('@new_node' => print_r($new_node, TRUE)),WATCHDOG_DEBUG); } // Devolvemos el resultado del servicio if ($new_node->nid) { return array("response"=>"Ok","status"=>"200","node"=>$new_node->nid,"fc"=>$field_collection_item->item_id); } else return array("response"=>"Failed"); }

Ejemplo completo:


Instalando:

Nuestro servicio dentro de "Services":

Referencias:

Drupal 8

Install D8



drush en -y hal rest serialization basic_auth
drush dl -y restui ; drush en -y restui
    

Se puede trabajar configurando manualmente
el archivo ARCHIVO!!, pero gracias a RESTui
podemos trabajar como en D7.

Creando un servicio

Configuration -> Web services -> REST

Permisos del servicio

People -> Permissions

Usando un servicio: GET

URL: http://drupal8.local//node/3?_format=json

Resultado: drupal8_Services_node_GET_response.json

Usando un servicio: POST


Por ahora la única forma "fácil" es
crear el resource via código.


Esto no anda bien en D8, debería andar en la versión 8.1. Hay formas de usarlo hoy, pero todavía estoy juntando información del como. Cuando logre tener detalles los compartiré en mi blog: www.nachodigital.com.ar/es/articles

Como crear un REST resource

Usando Drupal Console:

drupal generate:service [options]

Para mas detalles visitar la documentación: generate:service

¿Y el siguiente paso?

Articulos:

Headless Drupal: