Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Realizzare un servizio GraphQL

Come realizzare un semplice servizio di esempio basato sul paradigma di GraphQL, utilizzando Javascript ed il framework Node.js.
Come realizzare un semplice servizio di esempio basato sul paradigma di GraphQL, utilizzando Javascript ed il framework Node.js.
Link copiato negli appunti

In questa lezione, mettiamo in pratica i concetti sin qui acquisiti realizzando un servizio di esempio con GraphQL. Non avremo alcun database persistente a disposizione, ma salveremo le informazioni all'interno di un oggetto Javascript che usa un array come archivio: la nostra massima attenzione sarà infatti
per la definizione delle API. GraphQL può essere implementato in molti modi ed in vari linguaggi: qui faremo uso
del linguaggio Javascript basandoci sul substrato che offre Node.js.

L'esempio: un database per proverbi

In questo esempio creiamo una classe Javascript, denominata Archivio, che contiene al suo interno
un array di proverbi sui quali operano i metodi:

  • proverbioRandom, che estrae un proverbio a caso e lo restituisce;
  • nuovo, che immagazzina un nuovo proverbio passato come argomento;
  • selezioneProverbi, che riceve come argomento un numero intero che indica quanti proverbi devono essere restituiti al chiamante. Saranno forniti come risultato i primi dell'array.

La classe restituisce anche un oggetto di classe StatoServizio che contiene il numero di accessi
eseguiti al metodo proverbioRandom ed il risultato ottenuto nella sua ultima invocazione. Questo è
il codice con cui lo realizziamo:

class StatoServizio {
  constructor(){
     this.accessi=0
  }
  proverbioEmesso(proverbio){
    this.ultimo=proverbio
    this.accessi++
  }
}
class Archivio{
  constructor(proverbi){
      this.proverbi=proverbi
      this.stato=new StatoServizio()
  }
  proverbioRandom() {
    var item = this.proverbi[Math.floor(Math.random()*this.proverbi.length)];
    this.stato.proverbioEmesso(item)
    return item
  }
  nuovo(proverbio)
  {
     this.proverbi.push(proverbio)
     return this.proverbi.length
  }
  selezioneProverbi(quanti){
    if (quanti>0){
      return this.proverbi.slice(0, quanti)
    }
  }
}

Nello script con cui eseguiamo il server immettiamo il codice necessario per creare un oggetto di classe Archivio inizializzandolo con un lotto di proverbi:

archivio = new Archivio(['Gallina vecchia fa buon brodo',
                       'Il mattino ha l\'oro in bocca',
                       'Tra moglie e marito non mettere il dito',
                       'Una mela al giorno toglie il medico di torno',
                       'Ai pazzi si dà sempre ragione',
                       'Anno nuovo vita nuova',
                       'Bacco, tabacco e Venere riducon l\'uomo in cenere',
                       'Battere il ferro finché è caldo',
                       'Buon sangue non mente'])

Realizzazione dell'esempio

Per realizzare un servizio che condivida queste funzionalità con GraphQL seguiremo questi passaggi:

  1. importazione delle librerie necessarie: per lo più il framework Express ed il linguaggio GraphQL;
  2. strutturazione dello schema che definisce tipi di dato, query e mutation;
  3. implementazione delle funzionalità in un oggetto che risponderà alla variabile root;
  4. avvio del server sulla porta TCP di nostra scelta.

I paragrafi successivi descrivono lo sviluppo nel dettaglio

Le librerie necessarie

Prepariamo l'ambiente necessario da riga di comando con npm:

> npm init
> npm install express express-graphql graphql --save

Importiamo nel progetto le librerie necessarie con le seguenti direttive:

var express = require('express');
var http = require('express-graphql');
var { buildSchema } = require('graphql');

Tramite buildSchema potremo passare a definire i tipi di dato del servizio.

Lo schema

Nello schema definiamo: il tipo Query, che raccoglie tutte le funzionalità di interrogazione al servizio ossia quelle che restituiscono informazioni senza apportare alcune modifiche a quanto archiviato nel server; il tipo Mutation, che raccoglie funzionalità di inserimento cancellazione e modifica
di dati; il tipo StatoServizio, che sarà necessario in quanto, come vedremo, restituito da uno dei metodi della Query:

var def = buildSchema(`
  type StatoServizio{
    ultimo: String
    accessi: Int
  }
  type Query {
	 proverbioRandom: String
     stato: StatoServizio
     proverbi(quanti: Int): [String]
  }
  type Mutation{
     nuovo(nuovo: String): Int
  }
`);

A scopo didattico, abbiamo fatto in modo di raccogliere in questi casi una serie di casistiche differenti:

  • proverbioRandom viene interrogato senza argomenti, restituisce un oggetto di natura String;
  • proverbi è anch'esso una funzionalità di sola lettura ma pone due aspetti interessanti: richiede un
    argomento e restituisce un array di oggetti (notare le parentesi quadre in [String]);
  • stato è ancora un metodo in lettura ma non restituisce un oggetto di tipo built-in bensì un'istanza di StatoServizio, da noi definita. Questa classe contiene due elementi e vedremo come se ne potrà specificare quali restituire grazie alla flessibilità del linguaggio GraphQL;
  • in Mutation creiamo l'unico metodo che apporta modifiche.

Si noti che la distinzione tra Query e Mutation separeranno nettamente le funzionalità in sola
lettura (corrispondenti alle GET di REST) e quelle in modifica (i vari metodi POST, PUT, DELETE del paradigma REST).

Implementazione delle funzionalità

Quanto previsto nello schema verrà implementato nell'oggetto root:

var root = {
  // Query
  proverbioRandom: () =>
  {
	   return archivio.proverbioRandom()
  },
  stato: () => {
    return archivio.stato
  },
  proverbi: ({quanti}) => {
    return archivio.selezioneProverbi(quanti)
  },
  // Mutation
  nuovo: ({nuovo}) => {
      archivio.nuovo(nuovo);
      return archivio.proverbi.length
  }
};

Vi inseriamo sia le funzioni relative alla Query sia quella che offre una Mutation. Non facciamo nulla di diverso da qualsiasi altro contesto Javascript: riceviamo eventuali argomenti, otteniamo le informazioni accedendo all'oggetto archivio e le restituiamo.

Avvio del server

Nella fase finale dello script, avviamo il server Express, che mette a disposizione il fondamento necessario
per rendere il tutto raggiungibile via Rete:

var app = express();
app.use('/proverbi', http({
  schema: def,
  rootValue: root,
  graphiql: true,
}));
app.listen(8888);
console.log('Servizio in esecuzione su localhost:8888/proverbi');

Si notino i seguenti punti:

  • abbiamo definito l'endpoint ove risponde il servizio, "/proverbi";
  • passiamo i riferimenti a schema e oggetto root che abbiamo utilizzato, rispettivamente, per contenere definizione dei tipi e implementazione delle funzionalità;
  • attiviamo graphiql, che vedremo a breve al lavoro. Si tratta di un'applicativo fruibile in browser
    per testare subito le funzionalità implementate
    in GraphQL. Si presenta con un'interfaccia
    divisa in due pannelli: in quello a sinistra si scrivono le interrogazioni GraphQL, in quella a destra
    ne leggiamo l'esito. Specifichiamo come porta TCP di attivazione la numero 8888, ma questa potrà essere personalizzata a piacimento.

Fatto ciò si potrà avviare il tutto grazie a Node.js. Se il nostro file prende il nome di server.js, il comando per l'attivazione sarà:

> node server.js

Richieste e risposte: proviamo il servizio

Anche GraphQL lavora in una modalità richiesta/risposta. La richiesta ha un formato simile a JSON, mentre la risposta è effettivamente fornita come oggetto JSON. Le potremo
provare in GraphiQL, il servizio che sarà disponibile nel browser puntando l'endpoint che abbiamo
configurato: nel nostro esempio, http://localhost:8888/proverbi. Così apparirà l'interfaccia di
GraphiQL:

Figura 1. GraphiQL (click per ingrandire)

GraphiQL

Come già accennato, non dovremo far altro che scrivere una richiesta nel pannello sinistro e, premuto il tasto con il triangolo nero in alto, vedere la risposta in quello a destra. Una richiesta verrà introdotta da una parola chiave query o mutation a seconda del tipo di funzionalità cui stiamo accedendo.

Eseguendo la query:

query{
  proverbioRandom
}

otterremo risposte di questo tipo:

{
  "data": {
    "proverbioRandom": "Tra moglie e marito non mettere il dito"
  }
}

Come si vede, il campo data contiene proprio il risultato che abbiamo richiesto. Dopo alcune interrogazioni simili a questa si potrà richiedere lo stato attuale del servizio:

query{
  stato {
    ultimo
    accessi
  }
}

ottenendo:

{
  "data": {
    "stato": {
      "ultimo": "Il mattino ha l'oro in bocca",
      "accessi": 15
    }
  }
}

Questa query dimostra la flessibilità offerta da GraphQL: senza cambiare endpoint sarà sufficiente chiedere
meno dati per ottenere risultati più precisi
. Infatti, rimuovendo il campo accessi dalla richiesta:

query{
  stato {
    ultimo
  }
}

verrà, in maniera corrispondente, ristretta la risposta:

{
  "data": {
    "stato": {
      "ultimo": "Il mattino ha l'oro in bocca"
    }
  }
}

Infine, possiamo vedere una mutation con la quale aggiungeremo un ulteriore proverbio:

mutation{
  nuovo(nuovo:"Vivi e lascia vivere")
}

e la risposta ci comunicherà il nuovo numero di proverbi presenti nel database:

{
  "data": {
    "nuovo": 10
  }
}

Il codice dell'esempio descritto in questa lezione è disponibile a questo link.

Ti consigliamo anche