Si tratta di buzzword, comunque indica un'architettura in cui i singoli servizi sono accoppiati in modo lasco, oguno può essere sviluppato con tecnologie diverse e da vendor diversi. Garantiscono maggiore flessibilità rispetto ad un'implementazione concentrata su un server monolitico.
Tipicamente sono realizzati su HTTP, se non altro per il fatto che è ubiquo.
In un'architettura non SOA, un server implementa diversi servizi tutti al suo interno, vincolandoli strettamente l'uno all'altro.
Applicazioni SOA tradizionali implementano un orchestratore tra i vari servizi che a quindi possono essere sostituiti singolarmente a patto che mantengano l'interfaccia (cioè a parità di input e output).
I microservizi invece sono interamente slegati fra di loro: si possono quindi realizzare applicazioni che lato client sfruttano direttamente i singoli servizi (ad esempio one-page app via AJAX).
È un protocollo applicativo request-response, tipicamente su TCP, per lo scambio di risorse.
La versione più recente è la 2, ma ancora molti server usano la versione 1.1.
Entrambe le versioni gestiscono più connessioni HTTP all'interno di una TCP, la versione 2 supporta anche connessioni HTTP parallele all'interno di una TCP.
Il termine della connessione viene indicato dall'header "Connection: close header".
scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
scheme può essere: http, https, file, ...
Una richiesta HTTP è formata da:
- una riga che indica l'azione, la risorsa sulla quale eseguirla e il protocollo separati da spazio
- un insieme di righe di header
Chiave: valore
- un eventuale body (ad esempio in caso di POST)
- una riga vuota che indica la fine della richiesta
Una richiesta HTTP è formata da:
- una riga con protocollo, status code e relativa descrizione separati da spazio
- un insieme di righe di header
Chiave: valore
- un body (può essere vuoto, ad esempio se c'è un redirect)
Esempio di richiesta:
GET /items/42 HTTP/1.1
Host: www.example.org
Le azioni possono essere:
- GET
- POST
- PUT
- PATCH
- DELETE
- OPTIONS
- HEAD
- CONNECT
- TRACE
Gli status code sono di 4 tipi: 1xx, 2xx, 3xx, 4xx e 5xx.
- 1xx Informazioni
- 2xx Successo
- 3xx Redirezione
- 4xx Errore del client
- 5xx Errore del server
Quando si sviluppano servizi su HTTP è necessario che client e server scambino dati strutturati.
Esistono sostanzialmente due alternative: XML e JSON.
XML non è il massimo per il web; JSON invece è più adatto in quanto un dato in formato JSON è immediatamente caricabile in una struttura dati javascript e, viceversa, una struttura dati javascript è naturalmente rappresentabile da una stringa JSON. JSON è anche più leggibile da un umano, è meno verboso.
Client Server
---------------------------------------------------->
GET / HTTP/1.1
<----------------------------------------------------
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Zona privata"
---------------------------------------------------->
GET / HTTP/1.1
Authorization: Basic dXRlbnRlOnBhc3N3b3Jk
<----------------------------------------------------
HTTP/1.1 200 OK
oppure
HTTP/1.1 403 Forbidden
Il server chiede l'autenticazione (401) per il realm "Zona privata", il client riceve la risposta e prova ad autenticarsi inviando una nuova richiesta per la stessa risorsa e con l'header Authorization: con il valore Basic dXRlbnRlOnBhc3N3b3Jk.
La stringa "dXRlbnRlOnBhc3N3b3Jk" è la rappresentazione base64 di utente:password, che quindi viaggiano in chiaro, sarà compito di HTTPS quello di cifrare tutta la connessione.
Per generarlo da commandline:
printf utente:password |base64
Tutto questo lavoro il browser lo esegue automaticamente presentando la dialog di input delle credenziali all'utente.
I cookie vengono scambiati utilizzando gli header. Il server chiede al client di registrare un cookie con l'header Set-Cookie e il client passa il cookie al server con l'header Cookie.
I cookie di sessione vengono utilizzati per gestire le sessioni di un utente archiviando tutte le informazioni necessarie in un database sul server.
Il cookie è un puntatore (un semplice numero/stringa casuale) usato per recuperare la sessione sul database.
Lo svantaggio di un cookie di sessione è che tutti i microservizi dovrebbero poter accedere al database per recuperare la sessione dell'utente, violando perciò il principio di accoppiamento lasco.
La sessione non esiste più, al client/utente che si autentica correttamente viene rilasciato un token (Access Token), presentando il quale l'utente può accedere alle risorse se autorizzato.
Si tratta di autorizzazione al portatore (bearer), e si usa un header di questo tipo:
Authorization: Bearer eyJhbGciOiJIUzI1NiIXVCJ9...TJVA95OrM7E20RMHrHDcEfxjoYZgeFONFh7HgQ
Nel caso di JWT (Json Web Token) il token è in formato JSON ed è composto da un header, un payload ed una firma. L'header indica il tipo di cookie e l'algoritmo di firma, il payload trasporta le informazioni dell'utente ed i suoi privilegi, infine la firma garantisce l'integrità e l'autenticità del token.
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
Il token è quindi in chiaro, sarà compito di HTTPS garantire la segretezza.
Il servizio che riceve la richiesta dal client verifica che il JWT fornito sia valido e autorizza l'accesso alla risorsa in base al contenuto del token stesso.
I token sono stateless, non è necessario archiviarli.
Si tratta del modo più corretto di usare il web.
Un piccolo insieme di azioni su un insieme molto grande di sostantivi.
Si parla di operazioni CRUD su risorse: (Create, Read, Update, Delete). Inoltre All read per elencare tutte le risorse.
Operation | HTTP Verb | URL |
---|---|---|
All | GET | /notes |
Read | GET | /notes/:id |
Create | POST | /notes |
Update | PATCH/PUT | /notes/:id |
Delete | DELETE | /notes/:id |
I principali framework di sviluppo web rendono facile lo sviluppo di applicazioni REST a partire dalla definizione delle entità di una database. Una componente, chiamata router, mappa path dell'URL sui corrispondenti metodi che agiscono sulle risorse/entità.