< Home
Stampa

API REST

Sommario

REST

REST (“Representeational State Transfer”) è una architettura che viene utilizzata per progettare API basata sul protocollo HTTP (o HTTPS), quindi su architettura SOA client-server.

Nel modello REST (Representational State Transfer) il Web Service si occupa di fornire esclusivamente dati, detti anche risorse, e non servizi. E’ compito dei middleware (sia lato client, che lato server) fornire la logica di business necessaria ai componenti delle rispettive applicazioni. Questo modello si differenzia quindi dalle architetture di tipo RPC, come Soap.

Ogni singola API REST ha il compito di consentire l’accesso ad una singola risorsa dati.

La risorsa deve avere queste caratteristiche:

  • è costuita da una lista di record individuali distinti;
  • il singolo record ha un insieme di attributi, rappresentabili in formato trasmissibile, in formato testo (ad esempio tramite formato JSON ed XML) oppure binario (immagini, video, audio);
  • ogni record è identificato da una chiave univoca, detta Unique Identifier (UID).

Questo tipo di record sono di norma entità di database o elementi di uno stream video/audio.

L’API REST consente l’accesso in lettura e scrittura a questa risorsa tramite una interfaccia standard di comandi, che resta identica qualsiasi sia il tipo di risorsa, e che si basa direttamente sui metodi del protocollo HTTP:

  • GET: consente di accedere alla tabella dati, effetturare query di ricerca, ed accedere al singolo record (tramite UID)
  • POST: consente di inviare al server un nuovo record;
  • DELETE: consente di eliminare un record a partire da suo UID;
  • PUT: modifica di una istanza esistente, identiificata dal suo UID.

Sono previsti altri metodi, come PATCH (analogo a PUT) e OPTIONS (per interrogare il Web Server e chiedere quali API sono disponibili per quella risorsa).

E’ compito del progettista comunque decidere se implementare tutti o solo alcuni dei metodi, in base ai servizi effettivamente necessari per il progetto. La sicurezza di accesso è invece gestita separatamente, come vedremo sotto.

Per capirne il funzionamento faremo un esempio concreto.

Ipotizziamo di avere una lista di Todo memorizzate sul server a cui vogliamo accedere tramite API REST. La risorsa Todo ha i seguenti attributi:

  • id: number
  • title: string
  • dueDate: date
  • completed: bool

Vediamone il funzionamento

GET

La GET viene utilizzata in tutte quelle situazioni in cui vogliamo accedere ai dati:

  1. Scaricare una lista di Todo. Accediamo alla URL:

/api/todo

In questa URL si richiedono tutte le istanze di quella risorsa. La GET sulla risorsa (senza altri elementi) restituisce l’intera lista delle todo, senza filtri. Qui un esempio di tracciato di risposta JSON:

[{ 
 "title": "Studiare REST",
 "DueDate": "1/1/2020",
 "completed": false
},
{ 
 "title": "Ripassare SOA",
 "DueDate": "5/1/2020",
 "completed": false
},
... 
]

Se invece si vuole filtrare un sottoinsieme di risorse, su usa la queryString:

/api/todo/?completed=false

Questo meccanismo si può usare anche per paginare i risultati, quando sono troppi, introducendo un parametro speciale ad esempio page=1, così come anche si può dare una dimensione di pagina (es. resultsPerPage=20). Nello streaming invece si usano parametri come offset=xx con un valore in secondi o frame.

Nella situazione in cui invece si richiede una todo specifica, questo va identificato da un id univoco.

/api/todo/26

In questo caso l’API restituisce il singolo record.

POST

La POST si usa per inserire un nuovo elemento nella lista di risorse.

/api/todo

Nel body viene quindi inserito l’elemento, ad esempio in formato JSON:

{ 
 "title": "Fare esercizi sulle POST",
 "DueDate": "7/1/2020",
 "completed": false
}

L’id non viene fornito, perché il client non ha modo di generare un identificativo univoco valido per tutti i possibili client, e quindi il server ha questa responsabilità.

PUT

La PUT ha una struttura simile alla POST, ma concettualmente serve per modificare una risorsa esistente. Di norma quindi viene messo l’identificativo nella URL, in quanto già conosciuto dal client.

/api/risorsa/26

DELETE

La DELETE ha una URL simile a quella della GET, in quanto caso il comando è di cancellazione della risorsa.

/api/risorsa/31

Cancella la risorsa con id=31.

Sicurezza con JWT

REST non ha un meccanismo di sicurezza integrato, ed è come HTTP totalmente stateless, quindi non ha memoria di una sequenza di chiamate. Per poter gestire la sicurezza lato server si deve implementare separatamente quindi un meccanismo che garantisca l’identificazione del client, tramite autenticazione dell’utente (login) e restituzione di un token di sessione che lo identifichi univocamente sul server.

Il sistema di token più diffuso è il JSON Web Token (JWT), un sistema di autenticazione che il server non ha bisogno di salvare nel proprio database, perché trasporta internamente tutte le informazioni per identificare ed autorizzare l’utente. Il JWT è una stringa criptata nel seguente formato:

xxxxx.yyyyy.zzzzz

Dove;

xxxxx: è un header che identifica il tipo di token (algoritmo di criptazione)

yyyyy: identifica l’utente e la scadenza del token ed altre eventuali informazioni

zzzzz: è la firma crittografica della sessione

Il token viene criptato dal server con una sua chiave privata segreta lato server ed inviato al client dopo il login. Il client lo deve conservare per tutta la durata di sessione e inserirlo nell’header di ogni richiesta tramite questa coppia nome valore:

"Authorization: Bearer xxxxx.yyyyy.zzzzz"

Il server decripta il token, identifica l’utente e verifica ruolo e permessi, concedendo accesso alla risorsa se autorizzato.

La forza di JWT sta nel fatto che il server non deve memorizzare a sua volta il token nel proprio database. E’ quindi possibile fare la richiesta a web server paralleli (con database paralleli) che non si devono sincronizzare tra loro i token di sessione. E’ sufficiente che condividano la stessa chiave di criptazione.

REST e CRUD

REST è stato progettato con in mente i database ed in particolare le quattro operazioni fondamentali di accesso CRUD (Create Read Update Delete).

  • POST -> CREATE
  • GET -> READ (la SELECT di Sql)
  • PUT -> UPDATE
  • DELETE -> DELETE

Conclusioni

REST quindi:

  • si basa su risorse accessibili tramite 4 funzioni standard, e non prevede altri tipi di servizi;
  • definisce una interfaccia standard comune per qualsiasi tipologia di oggetto: il progettista del client sa già quali sono le operazioni fondamentali deve svolgere;
  • non definisce la tecnologia/linguaggio con cui è sviluppato il server, si preoccupa solo dello scambio dati;
  • corrisponde dal punto di vista logico a operazioni CRUD;
  • corrisponde dal punto di vista della comunicazione ai metodi HTTP, inoltre i codici di risposta sono gli stessi dello standard HTTP;
  • le chiamate/risposte REST sono, come le chiamate http, senza stato, quindi sia i messaggi di richiesta che di risposta devono fornire tutto il contesto, senza presupporre sessioni attive.
  • la sicurezza così come le sessioni vanno implementata esternamente, lo standard de facto è JWT

Esempio di REST: TodoList

Realizzare una applicazione distribuita che gestisce una TODO list. Gli elementi della TODO list prevedono un titolo, una data di scadenza, e uno stato (completato/non completato). L’applicazione client mostrerà la lista delle TODO, permetterà di inserire una nuova TODO, permetterà di cancellare una TODO da quelle esistenti e permetterà di modificarne lo stato.

Per realizzare questo applicativo, progetteremo un Web Service con le seguenti fasi:

1) Progettazione del database.

2) Identificazione delle viste e dei servizi REST 

3) Disegno dei tracciati JSON

4) Disegno dell’architettura dell’applicazione (quindi dei principali moduli dell’app distribuita).

Vediamo la realizzazione:

1) Database

In questo progetto è prevista una sola entità, quindi una sola tabella TODO.

Nome campofunzione
id: intid univoco
title: varchartitolo 
dueDate: datedata di scadenza
completed: boolstato di completamento

Sono previste 4 query (oltre alla CREATE):

INSERT into TODO (id, title, dueDate, completed) VALUES ($id, $title, $dueDate, $completed)

SELECT id, title, dueDate, completed FROM TODO

UPDATE TODO set completed=$completed WHERE id=$id

DELETE TODO WHERE id=$id

2) Identificazione delle viste e dei servizi REST 

I dati da mostrare corrispondono a quelli presenti nella tabella TODO.

I servizi REST saranno i seguenti:

URLVerboAzione
{baseUrl}/todoGETRiceve tutte le TODO
{baseUrl}/todoPOSTAggiunge una TODO
{baseUrl}/todo/$idPUTModifica una todo con id=$id(per cambiarne lo stato)
{baseUrl}/todo/$idDELETEElimina una TODO con id=$id

In questo caso non prevediamo la GET di una singola TODO.

3) Disegno dei tracciati JSON.

La struttura dati del JSON nella response di GET/POST/PUT è questa:

{

      todos: [

      {

            id: $id,

            title: $title,

            date: $dueDate,

            completed: $completed

      }, 

      ...
      ]

}

4) Disegno dell’architettura della web application: