Parte nona: interfaccia RESTful
Sar-At da sempre è utilizzabile come headless CMS, ovvero separa completamente le operazioni di motore database (creazione, alterazione, popolazione delle sezioni); le operazioni di produzione delle pagine web; e la grafica HTML usata per la presentazione dei contenuti.
Per facilitare il lavoro agli sviluppatori clientside (JavaScript) e agli integratori (sviluppatori di app che caricano contenuti dalla base dati del sito e poi li manipolano sull'apparecchio mobile) le moderne versioni di Sar-At introducono una interfaccia RESTful,.
Nel resto di questo capitolo spiegheremo come il server (Sar-At) può venire consultato dal client (una app o un JavaScript).
Accesso alle risorse del database
Sar-At consente tre tipi di accesso REST alla base dati
- Lettura di un record. Se il record è pubblico, per esempio una news pubblicata sul sito o la scheda di un prodotto in vendita nel commercio elettronico, Sar-At consente l'accesso sia in http che in https. Se il record è privato, per esempio l'anagrafica di un visitatore registrato sul sito, Sar-At pretende che l'accesso si svolga in https e che la richiesta sia accompagnata dalle credenziali del visitatore (username e password). La lettura viene richiesta dal cliente al server con una chiamata GET del protocollo http o https.
- Scrittura di un record. Sar-At pretende che l'accesso si svolga in https e che la richiesta sia accompagnata dalle credenziali del visitatore (username e password). Naturalmente le credenziali debbono essere sufficienti allo scopo. Per esempio, in un commercio elettronico un cliente può aggiornare la sua anagrafica ma non può modificare una riga di un ordine già transato. La scrittura viene richiesta dal cliente al server con una chiamata POST del protocollo http o https.
- Ricerca in una sezione del sito. Se i record della sezione sono pubblici, per esempio le news, Sar-At consente l'accesso sia in http che in https. Altrimenti è richiesto lo https. La scrittura viene richiesta dal cliente al server con una chiamata POST del protocollo http o https.
In ciascun caso, Sar-At restituisce l'OK o un codice di errore usando la sintassi classica del protocollo HTTP. Per esempio, se una app chiede al server accesso ai dati della news numero 100 ma le news sul sito sono numerate da 1 a 50, allora Sar-At restituisce l'errore 404 not found.
Se il risultato è positivo, il server restituisce i dati richiesti dal client in formato JSON. Nel caso della richiesta in scrittura, cioè il caso 2 dell'elenco qui sopra, Sar-At restituisce il JSON del record così come è salvato nella base dati dopo la modifica.
Lettura di un record
Il client richiede la lettura di un record chiamando
http(s):// www.nome-del-sito.suffisso / API / nome della tabella (sezione) / id
Per esempio, per leggere la news numero 73 sul sito test.mygelsia.it
https://test.mygelsia.it/API/news/73
A prescindere da quale sezione (tabella) del database stiate leggendo, e in quale sito, i primi campi della risposta JSON sono sempre i medesimi. Si tratta delle informazioni di servizio (metainformazioni) con cui Sar-At correda ogni record del database. Sono descritti nei precedenti capitoli di questo manuale ma, in sintesi, si tratta di:
Campo |
L/S |
Contenuto |
id |
L |
Identificativo numerico univoco del record |
masterId |
L |
Nei siti multilingue, identificativo numerico univoco della risorsa. Per esempio, se i record 1 e 2 hanno identico masterId 3 allora si tratta delle due traduzioni in due diverse lingue della medesima informazione |
language |
S |
Codice della lingua in cui sono scritti i testi (1001: italiano; 1002: inglese; eccetera. Vedere il manuale Mantenere il sito) |
creation |
L |
Data ed ora della prima creazione del record |
authorId |
L |
Username del creatore del record |
lastMod |
S* |
Data ed ora della ultima modifica del record |
modifierId |
S* |
Username del modificatore del record |
visible… sarelHitCounter |
S |
Vedi precedenti capitoli di questo manuale. |
saratUrl |
S* |
URL univoca sul sito per la consultazione dell'informazione |
L: informazione accessibile sempre e solo in lettura
S: informazione modificabile attraverso l'operazione di scrittura sul record descritta qui di seguito.
S*: informazione modificabile attraverso l'operazione di scrittura sul record, ma i contenuti del campo in questo caso verrebbero autonomamente popolati da Sar-At. Per esempio, modifierId diventerebbe la username dell'utente le cui credenziali sono state usate.
Seguono tutti i campi specifici della sezione (tabella) interessata.
Nelle sezioni anagrafiche Sar-At mantiene le password in formato cifrato (vedere capitolo terzo, alla voce "sezioni a massima sicurezza"). Di conseguenza, il campo "password" apparirà sempre vuoto nel JSON che vi viene restituito.
Tenete presente che, internamente, Sar-At memorizza tutti i testi in formato HTML. Quindi nei campi di testo breve e di testo lungo che vengono restituiti dal server al client dovete aspettarvi di trovare entità SGML (come è) e tag HTML.
Nel caso di record riservato, la chiamata deve includere le credenziali. Per esempio, in un commercio elettronico businesss to business il prezzo riservato all'acquirente e il numero di scorta magazzino è probabilmente una informazione riservata ai membri registrati del gruppo "clienti". Il client deve includere, come parametri della chiamata GET:
- username
- password
- group, cioè nome gruppo di appartenenza
Per esempio, per leggere la anagrafica del cliente registrato numero 15159 sul sito test.mygelsia.it, avremo:
https://test.mygelsia.it/API/registrazione/15159?username=luca@accomazzi.net&password=
Naturalmente, il caso di una anagrafica è un caso un po' particolare. Il software client che state sviluppando probabilmente non conosce lo id univoco del cliente di cui possiede le credenziali (di solito questa informazione non traspare). Per semplificare le procedure e saltare l'inutile passaggio di una ricerca per username nella base dati, Sar-At consente in questo caso di usare "ANY" al posto dell'id numerico (in modo analogo a quanto viene fatto con la procedura showForm, vedi capitolo terzo di questo manuale).
In altre parole, la URL vista qui sopra è equivalente a:
https://test.mygelsia.it/API/registrazione/ANY?username=luca@accomazzi.net&password=
tvumdb&group=registrati
Scrittura di un record
La scrittura di un record avviene in modo perfettamente speculare a quanto appena visto, ma il client chiama il server usando un POST anziché un GET, alla medesima URL. Per esempio, per aggiornare la scheda del cliente registrato sul sito test.mygelsia.it la URL sarà sempre
https://test.mygelsia.it/API/registrazione/15159?username=luca@accomazzi.net&password=
tvumdb&group=registrati
Se la richiesta contiene il campo id, Sar-At suppone che il client voglia aggiornare il record indicato. Se la richiesta contiene il numero zero come id, Sar-At presume che voi desideriate aggiungere un record alla base dati.
Vediamo un esempio pratico, come sia possibile aggiornare l'anagrafica del cliente già visto in precedenza sul sito test.mygelsia.it. Per massima chiarezza mostriamo l'esempio nella forma di un form HTML, perché questo rende semplice l'invio in formato POST dei dati da scrivere:
<!DOCTYPE html>
<html lang='it'>
<head>
<meta charset='utf-8' />
<title>Esempio chiamata POST di tipo RESTful</title>
</head>
<body>
<!-- post, quindi richiesta di modifica-->
<form action='https://test.mygelsia.it/API/registrazione/15159' method='post'>
<!-- credenziali -->
<input name='username' type='hidden' value='luca@accomazzi.net' />
<input name='password' type='hidden' value='tvumdb' />
<input name='group' type='hidden' value='registrati' />
<!-- campi da sovrascrivere -->
<input name='bolletta' type='hidden' value='email' />
<input name='codice_fiscale' type='hidden' value='CCMLST64H08F952C' />
<input name='newsletter' type='hidden' value='on' />
<input name='confermato' type='hidden' value='1' />
<input name='in_attesa' type='hidden' value='0' />
<input name='attivato' type='hidden' value='1' />
<input name='telefono' type='hidden' value='3497680116' />
<input name='indirizzo' type='hidden' value='Via Scarlatti' />
<input name='civico' type='hidden' value='3' />
<input name='cap' type='hidden' value='20015' />
<input name='comune' type='hidden' value='Parabiago' />
<input name='provincia' type='hidden' value='Mi' />
<!-- Non posso cambiare email perché è la username -->
<input name='codice_utenza' type='hidden' value='1907479' />
<input name='codice_cliente' type='hidden' value='022028' />
<input name='codice_amministratore' type='hidden' value='' />
<!-- pulsante per consentire l'inoltro -->
<input type='submit' value='Invia richiesta di modifica' />
</form>
</body>
</html>
Come esempio perfettamente equivalente, ecco come la medesima richiesta si può fare con una chiamata a cURL, evitando l'uso di un browser e dello HTML:
curl 'https://test.mygelsia.it/API/registrazione/15159' -H 'Host: test.mygelsia.it' -H 'Content-Type: application/x-www-form-urlencoded' --data 'username=luca%40accomazzi.net&password=tvumdb&group=registrati&bolletta=email&codice_fiscale=CCMLST64H08F952C&newsletter=on&confermato=1&in_attesa=0&attivato=1&telefono=3497680116&indirizzo=Via+Scarlatti&civico=3&cap=20015&comune=Parabiago&provincia=Mi'
Come si intuisce dall'esempio, nelle sezioni anagrafiche Sar-At non vi permette di modificare la username o la password. Ovviamente, vi permette di modificare solo la anagrafica del cliente le cui credenziali avete passato e non quelle degli altri. Un po' meno ovviamente, potrebbero esistere campi dei quali non vi è concesso effettuare l'aggiornamento (per esempio il codice cliente, o la classe di sconto applicata al cliente di cui state editando l'anagrafica): se passate uno di questo campi Sar-At si limita a ignorarlo (la richiesta non va in errore).
L'amministratore del sito imposta per ciascun campo il permesso di inserirvi dei valori alla creazione o di editare i valori per i record esistenti usando la linguetta Struttura, facendo clic sul nome del campo e operando sulle caselle del gruppo "I visitatori del sito possono…"
Ricerca nel database
Il client richiede una ricerca nel database chiamando la URL
http(s):// www.nome-del-sito.suffisso / API / SarAtSearch / 0
Per esempio, sul sito test.mygelsia.ituseremmo
https://test.mygelsia.it/API/SarAtSearch/0
Come parametri, il client passa un parametro chiamato table col nome della tabella dentro la quale cercare e una (o più) coppie di nome campo, valore campo per indicare cosa cercare. Per esempio, per cercare gli pneumatici per auto di marca Bridgestone nella tabella prodotto useremmo ?table=prodotto&marca=Bridgestone&tipo=auto
Il server risponde con un vettore in formato JSON di tutte le id dei record che rispondono alla ricerca.
Vediamo un esempio concreto. La app MyGelsia, avendo caricato il profilo cliente usando il metodo GET visto all'inizio di questo capitolo, decide di caricare l'elenco delle utenze del cliente Luca Accomazzi. Deve dunque fare una ricerca nella tabella IS_UTE alla ricerca di tutti i record che fanno capo al codice cliente 192956.
Anche in questo caso per semplicità vediamo un HTML che dimostra come effettuare la chiamata:
<!DOCTYPE html>
<html lang='it'>
<head>
<meta charset='utf-8' />
<title>Ricerca utenze del cliente</title>
</head>
<body>
<!-- post https per una ricerca sicura con risultati mutevoli -->
<form action='https://test.mygelsia.it/API/SarAtSearch/0' method='post'>
<!-- credenziali -->
<input name='username' type='hidden' value='luca@accomazzi.net' />
<input name='password' type='hidden' value='tvumdb' />
<input name='group' type='hidden' value='registrati' />
<!-- dove cercare -->
<input name='table' type='hidden' value='IS_UTE' />
<!-- cosa cercare -->
<input name='AUCCLI' type='hidden' value='192956' />
<!-- solo per la demo -->
<input type='submit' value='Invia richiesta di ricerca' />
</form>
</body>
</html>
Equivalente cURL:
curl 'https://test.mygelsia.it/API/SarAtSearch/0' --data 'username=luca%40accomazzi.net&password=tvumdb&group=registrati&table=IS_UTE&AUCCLI=192956'
La app a questo punto può eseguire un ciclo sugli id così ottenuti e ricevere di conseguenza tutte le informazioni sulle utenze del cliente (per esempio, casa e ufficio). Seguirà un'altra ricerca sulla tabella IS_FOR alla ricerca di ciascuna fornitura in capo alle utenze (per esempio, gas e luce di casa).
Codici di errore
Come anticipavamo, ogni richiesta al server riceve innanzitutto un codice di esito nella forma stabilita dal protocollo HTTP: 200 in caso di successo, un codice di errore altrimenti. Ecco un esempio usando cURL:
curl -i 'https://test.mygelsia.it/API/registrazione/15159?username=luca
@accomazzi.net&password=tvumdb&group=registrati'
Ottiene come header:
HTTP/1.1 200 OK
E come corpo della risposta
{"masterId":"15159","id":"15159","lastMod":"2016-11-26 11:29:31"
(eccetera)
Per un controesempio, alla richiesta di leggere l'anagrafica di un'altra persona viene opposto un rifiuto. Notate che lo id numerico qui è diverso e corrisponde a un altro utente.
curl -i 'https://test.mygelsia.it/API/registrazione/15160?username=luca
@accomazzi.net&password=tvumdb&group=registrati'
Ottiene come header:
HTTP/1.1 401 Unauthorized
Nel corpo della risposta Sar-At riporta un messaggio esplicativo, pensato per aiutare lo sviluppatore durante il suo lavoro a capire i motivi del rifiuto. I messaggi di errore possono venire cambiati nel corso del tempo, a ogni successivo rilascio di Sar-At, e lo sviluppatore non deve fare affidamento su di essi. Il codice rilasciato in produzione per la soluzione clientside deve utilizzare esclusivamente gli indicatori numerici per desumere il risultato della richiesta.
Possibili codici di errore
La tabella seguente riporta un elenco, esaustivo al momento in cui questo manuale viene scritto, dei messaggi di errore possibili. Per massima compatibilità con le future versioni di Sar-At si raccomanda che lo sviluppatore clientside si tuteli contro la possibile apparizione di altri codici di errore
Codice |
Possibili motivi del rifiuto |
|
Manca uno dei parametri di base della chiamata |
|
Username o password sbagliata |
|
Tentativo di leggere un record che il proprietario del sito ha dichiarato non (ancora) visibile ai visitatori |
|
Tentativo di leggere (o aggiornare) un record inesistente |
|
Tentativo di registrare nel database un dato inaccettabile (per esempio un codice fiscale la cui checksum è sbagliata, un CAP inesistente, l'indirizzo email es@dominio-inesistente.it) |
|
Errore SQL interno |
|
Il server sta sostenendo un carico di lavoro inusitatamente alto e al momento non può soddisfare la richiesta |