2 Aprile, 2019 | Di Wellnet

Drupal 8 Decoupled con JSON:API e Vue.JS - parte 1

Drupal 8 Decoupled con JSON:API e Vue.JS - parte 1

Sempre più decoupled

Dalla versione 8.7 il modulo JSON:API integrato nel core sarà stabile. A questo punto si è arrivati perché si sta ampliando sempre di più la prospettiva di utilizzare Drupal con approccio Decoupled ovvero, in sintesi: Drupal come backend e qualsiasi tecnologia/framework frontend-oriented come frontend.

Cos’è JSON:API?

JSON API è una specifica che descrive un formato che opera su HTTP. Esso delinea come i client debbano richiedere o modificare dati dal server e come quest’ultimo debba rispondere a tale richiesta. L’obiettivo principale è quello di ottimizzare le richieste HTTP sia per quanto riguarda il numero di queste sia rispetto alle dimensioni dei pacchetti inviati/richiesti. 

La richiesta (sia lato server che client) JSON API è connotata dal Media Type application/vnd.api+json.

Vediamo come Yehuda Katz (uno dei suoi sviluppatori) descrive JSON API:

JSON API is a wire protocol for incrementally fetching and updating a graph over HTTP

Analizziamo la definizione:

  • JSON API è un wire protocol: non si occupa di implementare funzionalità per lo scambio di dati/informazioni (resources) attraverso la rete (wire) bensì di stabilire come questi dati/informazioni debbano presentarsi da un punto all’altro.
  • JSON API è incrementale: I client possono richiedere i dati di cui necessitano nella forma desiderata ed eventualmente ad un livello di complessività crescente.
  • JSON API definisce un modo per ottenere e modificare: infatti il formato con il quale si modifica (CRUD) o si richiede (GET) una risorsa è lo stesso.
  • JSON API definisce una struttura a grafi: tale struttura permette alle risorse di essere collegate le une alle altre riuscendo così a rappresentarle in una forma più attinente alla logica della risorsa stessa.

Cosa s'intende per risorsa

Più volte mi sono riferito al termine resource (risorsa) e tante più volte vi imbatterete in questo elemento se approccerete a JSON:API. Questo perchè essa rappresenta la struttura principale di una risposta restituita dal server che implementa le specifiche JSON:API. In sintesi è la risposta HTTP che il server restituisce, in conformità alle specifiche JSON:API, contenente headers, status code e contenuti. Il contenuto della resource è chiamato document. La sua struttura è descritta dettagliatamente nell'immagine subito sotto.

Per un approfondimento rimando alla documentazione su drupal.org a questo link.

Struttura di una risorsa JSON:API. https://www.drupal.org/docs/8/modules/jsonapi/glossary-of-terms
Struttura di una risorsa JSON:API. https://www.drupal.org/docs/8/modules/jsonapi/glossary-of-terms

 

La proprietà type

Dalla documentazione ufficiale su drupal.org apprendiamo che ogni risorsa JSON:API deve avere una proprietà globalmente unica chiamata type. L’implementazione Drupal di JSON:API ricava questa proprietà da:

  • Nome macchina dell’entità

  • Nome macchina del bundle

Per esempio le proprietà type per una resource articolo, una pagina ed un utente sono rispettivamente:

  • node--article
  • node--page
  • user--user 

Noterete che l'ultima entità (user) riporta una ripetizione, questo perchè essa è sprovvista di bundle. In questo caso il modulo ripiega sull'utilizzo indiscriminato del nome macchina dell'entità per entrambe le parti.

JSON:API Endpoint

La domanda che a questo punto sorge spontanea è: a quale endpoint risponde il modulo JSON:API? Semplicemente: /jsonapi

Precisamente il pattern di riferimento, per Drupal, è: /jsonapi/{entity_type_id}/{bundle_id}[/{entity_id}]

Prendendo in esamina il bundle article dell'entità node:

  • GET|POST/jsonapi/node/article
    • Nel caso del metodo GET, non avendo specificato un uuid verranno restituiti tutti i nodi di quel bundle (se presenti).
  • PATCH|DELETE: /jsonapi/node/article/{uuid}

In pratica

Vediamo, in pratica, come iniziare a richiedere/creare risorse mediante JSON:API in Drupal (nel mio caso versione 8.7.x-dev). È necessario, a tale scopo, abilitare i seguenti moduli:

  • JSON:API

  • Serialization

A questo punto siamo pronti per effettuare le nostre chiamate.

GET - Richiedere una risorsa

Come da immagine (e da documentazione) abbiamo visto che una Resource è una risposta HTTP che il server restituisce in conformità alle specifiche JSON:API contenente headers, status code e contenuti.

Vediamo ora cosa accade quindi nel momento in cui andiamo ad effettuare una GET della risorsa /jsonapi/node/article. Anticipando che dal momento che non stiamo specificando nessun ID specifico (UUID) stiamo richiedendo quella che in gergo viene definita Collection Resource: una risorsa contenente più resource object

Prima di procedere con l'esempio è necessario ricordarsi di informare il server circa il formato accettato dal client come risposta che, come dicevamo all'inizio dell'articolo, è rappresentato dall'header:

Accept: application/vnd.api+json.

Esempio 1: GET di una Collection Resource di article senza averne creato ancora uno.

// http://d8jsonapiapp.lndo.site/jsonapi/node/article
 
{
  "jsonapi": {
    "version": "1.0",
    "meta": {
      "links": {
        "self": {
          "href": "http://jsonapi.org/format/1.0/"
        }
      }
    }
  },
  "data": [
 
  ],
  "links": {
    "self": {
      "href": "http://d8jsonapiapp.lndo.site/jsonapi/node/article"
    }
  }
}

Esempio 2: GET di una Collection Resource di article dopo averne creato 1

// http://d8jsonapiapp.lndo.site/jsonapi/node/article
 
{
  "jsonapi": {
    "version": "1.0",
    "meta": { ... }
  },
  "data": [
    {
      "type": "node--article",
      "id": "6d5e9e6c-811d-4d6c-8f69-24de0b7a59cd",
      "attributes": {
        "drupal_internal__nid": 1,
        "drupal_internal__vid": 4,
        "langcode": "en",
        "revision_timestamp": "2019-04-02T13:17:12+00:00",
        "revision_log": null,
        "status": true,
        "title": "First article",
        "created": "2019-04-01T13:36:52+00:00",
        "changed": "2019-04-02T13:17:12+00:00",
        "promote": true,
        "sticky": false,
        "default_langcode": true,
        "revision_translation_affected": true,
        "path": { ... },
        "body": { ... },
        "comment": { ... }
      },
      "relationships": {
        "node_type": { ... },
        "revision_uid": { ... },
        "uid": { ... },
        "field_image": { ... },
        "field_tags": { ... }
      },
      "links": { ... }
    }
  ],
  "links": {
    "self": {
      "href": "http://d8jsonapiapp.lndo.site/jsonapi/node/article"
    }
  }
}

Struttura di una risorsa JSON:API

Nell'immagine ho evidenziato le parti componenti la risposta ottenuta da Drupal che compongono la nostra risorsa.
È evidente l'importanza del resource object che nel 90% dei casi è l'elemento d'interesse della chiamata. Questo contiene al suo interno l'attributes object che altro non è che l'oggetto contenente i campi dell'entità richiesta. Inoltre avendo creato un solo nodo di tipo article non può che esserci un solo resource object.
Probabilmente stiamo effettuando la richiesta tramite una chiamata ajax in javascript ed il risultato della chiamata (il document della resource) l'abbiamo salvata nella variabile results. Ora, volendo accedere all'attributo (campo) title del resource object dovremmo fare qualcosa del genere:

console.log(results.data[0].attributes.title);

Facile no? Ovviamente avendo a disposizione una Collection Resource bisognerebbe "loopare" l'array results.data, così da accedere in maniera incrementale a tutti gli indici da 0 a n.

Ad inizio articolo abbiamo esaminato la definizione di JSON:API data da uno dei suoi sviluppatori e abbiamo visto come questo la identificasse in una struttura a grafi. Questa caratteristica è data dalle relationships object che altro non sono che riferimenti a risorse relazionate a quella che attualmente stiamo richiedendo. Nel caso dell'articolo per esempio un relationship object è rappresentato dalla risorsa user--user (creatore del nodo), oppure alla risorsa file--file inerente al campo immagine del tipo di contenuto article.

Questa possibiltà, offerta dall'implementazione delle specifiche JSON:API, permette di ridurre il numero di chiamate da effettuare per completare l'informazione di cui si necessita costruire l'output, nel nostro caso il nodo article.

POST - Creare una risorsa

Fin'ora abbiamo visto, per grandi linee, come ottenere risorse mediante una richiesta GET.

L'inverso di tale operazione è quella di creare (o modificare tramite PATCH) una risorsa mediante il metodo POST. L'esempio che andremo a vedere riguarda la creazione di un nuovo nodo di tipo article.

C'è un problema: effettuare una richiesta POST per creare un'articolo su Drupal equivale a tentare di creare un nodo di tipo articolo tramite interfaccia Drupal senza essere loggato! Per risolvere tale problema, ovvero per eseguire una richiesta autenticata, bisogna abilitare un altro modulo: basic_auth

È inoltre necessario accertarsi che il modulo JSON:API sia configurato correttamente per accettare tutte le operazioni CRUD (create, read, update and delete). Per fare questo bisogna recarsi al path /admin/config/services/jsonapi e impostare come segue le allowed operations:

JSON:API Allowed operation screenshot

Procediamo dunque col creare la nostra risorsa, il nodo di tipo article. Ebbene sì, anche la richiesta inviata dal client deve rispettare le specifiche JSON:API e quindi inviare una resource contenente un document all'interno del quale sia presente un (o più) resource object

La richiesta che invieremo...

POST /jsonapi/node/article
Host: d8jsonapiapp.lndo.site
Content-Type: application/vnd.api+json
Authorization: Basic YWRtaW46YWRtaW4=
 
{
	"data": {
		"type": "node--article",
		"attributes": {
			"title": "Test creation",
			"body": {
				"value": "Lorem ipsum dolor silent",
				"format": "plain_text"
			}
		}
	}
}

Il valore dell'header Authorization è costruito codificando i valori d'accesso a Drupal (username e password) in base-64 come segue:

(javascript) var basicHeader = "Authorization: " "Basic " + btoa(username + ":" + password);

Ovviamente la risposta da attendersi, se tutto è andato a buon fine, è una resource completa riferentesi al nodo appena creato.

Article JSON:API

Nel prossimo articolo...

Siamo giunti al termine della prima parte di tutorial dedicata alla panoramica del modulo Drupal JSON:API. Nella seconda parte realizzeremo una semplice Web App usando Vue JS (Vue is a progressive framework for building user interfaces) la quale consumerà le API Drupal e le renderà nello stile più appropriato. 

Vai alla seconda parte

Wellnet
Wellnet

Wellnet è una nuova realtà nel panorama delle agenzie digitali italiane: 70 expertise complementari e integrate, con sedi a Milano, Torino Cuneo e Modena, frutto della fusione di tre realtà di successo preesistenti.

Potrebbe interessarti: