rest Tutorial
Iniziare con il riposo
Ricerca…
Osservazioni
Questa sezione fornisce una panoramica di cosa è il riposo e perché uno sviluppatore potrebbe volerlo usare.
Dovrebbe anche menzionare eventuali soggetti di grandi dimensioni all'interno del resto e collegarsi agli argomenti correlati. Poiché la Documentazione per il riposo è nuova, potrebbe essere necessario creare versioni iniziali di tali argomenti correlati.
Panoramica REST
REST è l'acronimo di RE presentational S tate T ransfer ed è stato coniato da Roy Fielding nella sua tesi di dottorato Architectural Styles e Design of Network-based Software Architectures . In esso identifica specifici principi architettonici come:
Risorse indirizzabili: l'astrazione chiave di informazioni e dati in REST è una risorsa e ogni risorsa deve essere indirizzabile tramite un URI.
Un'interfaccia uniforme e vincolata: uso di un piccolo insieme di metodi ben definiti per manipolare le nostre risorse.
Orientamento alla rappresentazione: una risorsa referenziata da un URI può avere formati diversi e piattaforme diverse richiedono formati diversi, ad esempio i browser hanno bisogno di HTML, JavaScript necessita di JSON e le applicazioni Java potrebbero aver bisogno di XML, JSON, CSV, testo, ecc. Quindi interagiamo con i servizi usando la rappresentazione di quel servizio.
Comunicare statelessly: le applicazioni stateless sono più facili da scalare.
Hypermedia As The Engine Of Application State: i nostri formati di dati guidano le transizioni di stato nelle nostre applicazioni.
L'insieme di questi principi architettonici si chiama REST. I concetti di REST sono ispirati a quello di HTTP. Roy Fielding che ci ha dato REST è anche uno degli autori delle specifiche HTTP.
I servizi Web e i servizi Web RESTful sono servizi che sono esposti a Internet per l'accesso programmatico. Sono le API online che possiamo chiamare dal nostro codice. Esistono due tipi di servizi Web "Big" SOAP e servizi web REST.
Servizi Web RESTful : i servizi Web che vengono scritti applicando i concetti architetturali REST sono chiamati RESTful Web Services, che si concentrano sulle risorse di sistema e su come lo stato di una risorsa può essere trasferito tramite protocollo HTTP a diversi client.
Questo documento è incentrato esclusivamente sui servizi web RESTful quindi non entreremo nei dettagli di SOAP WS.
Non ci sono regole rigide durante la progettazione di servizi web RESTful come
- Nessun protocollo standard
- Nessun canale di comunicazione standard
- Nessun standard di definizione del servizio
Ma SOAP ha regole severe per tutti questi. Tutti i servizi Web SOAP seguono le specifiche SOAP che stabiliscono quali dovrebbero essere i servizi Web SOAP. Questa specifica è sviluppata e gestita da un comitato e se SO SO non segue nemmeno una singola regola, per definizione non è SOAP.
Concetti di servizi Web RESTful
Ci sono poche linee guida che devono essere considerate durante la progettazione / sviluppo di API RESTful:
- Ubicazioni / URI basati su risorse
- Uso corretto dei metodi HTTP
- HATEOAS (Hypermedia As The Engine Of Application State)
L'approccio principale durante lo sviluppo delle API RESTful dovrebbe essere quello di rendere l'API "il più possibile RESTful".
REST su HTTP
REST è un'architettura indipendente dal protocollo proposta da Roy Fielding nella sua dissertazione (il capitolo 5 è la presentazione di REST), che generalizza il comprovato concetto di browser Web come client al fine di separare i client in un sistema distribuito dai server.
Affinché un servizio o un'API siano RESTful, deve rispettare i vincoli dati come:
- Client-server
- apolide
- cacheable
- Sistema a strati
- Interfaccia uniforme
- Identificazione delle risorse
- Rappresentazione delle risorse
- Messaggi auto-descrittivi
- Hypermedia
Oltre ai limiti menzionati nella tesi di Fielding, nel suo blog le API REST devono essere basate su ipertesto , Fielding ha chiarito che il solo richiamo di un servizio tramite HTTP non lo rende RESTful . Un servizio dovrebbe quindi anche rispettare ulteriori regole che sono riassunte come segue:
L'API deve aderire e non violare il protocollo sottostante. Sebbene REST sia usato via HTTP il più delle volte, non è limitato a questo protocollo.
Forte attenzione alle risorse e alla loro presentazione tramite media-tipi.
I clienti non dovrebbero avere conoscenze iniziali o ipotesi sulle risorse disponibili o sul loro stato restituito ( risorsa "tipizzata" ) in un'API, ma impararle al volo tramite richieste emesse e risposte analizzate. Ciò offre al server l'opportunità di spostarsi o rinominare le risorse facilmente senza interrompere un'implementazione del client.
Richardson Maturity Model
Richardson Maturity Model è un modo per applicare i vincoli REST su HTTP al fine di ottenere servizi Web RESTful.
Leonard Richardson ha diviso le applicazioni in questi 4 livelli:
- Livello 0: uso di HTTP per il trasporto
- Livello 1: utilizzo dell'URL per identificare le risorse
- Livello 2: uso di verbi HTTP e stati per le interazioni
- Livello 3: uso di HATEOAS
Poiché l'attenzione si concentra sulla rappresentazione dello stato di una risorsa, viene incoraggiata la rappresentazione di più rappresentazioni per la stessa risorsa. Una rappresentazione potrebbe quindi presentare una panoramica dello stato della risorsa mentre un'altra restituisce i dettagli completi della stessa risorsa.
Si noti inoltre che, dati i vincoli Fielding, un'API è effettivamente RESTful solo una volta implementato il 3 ° livello di RMM .
Richieste e risposte HTTP
Una richiesta HTTP è:
- Un verbo (aka metodo), la maggior parte delle volte uno di GET , POST , PUT , DELETE o PATCH
- Un URL
- Intestazioni (coppie chiave-valore)
- Facoltativamente un corpo (anche carico utile, dati)
Una risposta HTTP è:
- Uno stato, il più delle volte uno dei 2xx (riuscito) , 4xx (errore del client) o 5xx (errore del server)
- Intestazioni (coppie chiave-valore)
- Un corpo (noto anche come payload, dati)
Caratteristiche dei verbi HTTP:
- Verbi che hanno un corpo:
POST
,PUT
,PATCH
- Verbi che devono essere sicuri (cioè che non devono modificare le risorse):
GET
- Verbi che devono essere idempotenti (ovvero che non devono influenzare nuovamente le risorse quando vengono eseguiti più volte):
GET
(nullipotent),PUT
,DELETE
body safe idempotent
GET ✗ ✔ ✔
POST ✔ ✗ ✗
PUT ✔ ✗ ✔
DELETE ✗ ✗ ✔
PATCH ✔ ✗ ✗
Di conseguenza , i verbi HTTP possono essere confrontati con le funzioni CRUD :
Si noti che una richiesta PUT
richiede ai client di inviare l'intera risorsa con i valori aggiornati. Per aggiornare parzialmente una risorsa, è possibile utilizzare un verbo PATCH
(vedere Come aggiornare parzialmente una risorsa? ).
Usuali stati di risposta HTTP
Successo
- 201 (CREATO) : la risorsa è stata creata
- 202 (ACCETTATO) : richiesta accettata, ma ancora in elaborazione
- 204 (NESSUN CONTENUTO) : richiesta soddisfatta e nessun contenuto aggiuntivo
- Altrimenti: 200 (OK)
reindirizzamento
- 304 (NON MODIFICATO) : il client può utilizzare la versione memorizzata nella cache della risorsa richiesta
Errori del cliente
- 401 (NON AUTORIZZATO) : una richiesta anonima accede a un'API protetta
- 403 (PROIBITO) : una richiesta autenticata non ha diritti sufficienti per accedere a un'API protetta
- 404 (NON TROVATO) : risorsa non trovata
- 409 (CONFLICT) : stato della risorsa in conflitto (ad es. Un utente che sta tentando di creare un account con un'e-mail già registrata)
- 410 (GONE) : uguale a 404, ma la risorsa esisteva
- 412 (PRECONDITION FAILED) : la richiesta prova a modificare una risorsa che si trova in uno stato imprevisto
- 422 (ENTITÀ INCROCESSABILE) : il carico utile della richiesta è sintatticamente valido, ma semanticamente errato (ad esempio un campo obbligatorio che non è stato valutato)
- 423 (LOCKED) : la risorsa è bloccata
- 424 (DIPENDENZA NON RIUSCITA) : l'azione richiesta dipendeva da un'altra azione fallita
- 429 (TROPPE RICHIESTE) : l'utente ha inviato troppe richieste in un dato periodo di tempo
- Altrimenti: 400 (RICHIESTA MALE)
Errori del server
- 501 (NON IMPLEMENTATO) : il server non supporta la funzionalità richiesta per soddisfare la richiesta
- 503 (SERVIZIO NON DISPONIBILE) : il server non è attualmente in grado di gestire la richiesta a causa di un sovraccarico temporaneo o di una manutenzione programmata
- 507 (STORAGE INSUFFICIENTE) : il server non è in grado di memorizzare la rappresentazione necessaria per completare correttamente la richiesta
- Altrimenti: 500 (ERRORE SERVER INTERNO)
Gli appunti
Niente ti impedisce di aggiungere un corpo a risposte errate, per rendere il rifiuto più chiaro per i clienti. Ad esempio, il 422 (ENTITÀ INCROCESSABILE) è un po 'vago: il corpo della risposta dovrebbe fornire il motivo per cui l'entità non può essere elaborata.
hateoas
Ogni risorsa deve fornire ipermedia alle risorse a cui è collegata. Un collegamento è composto almeno da:
- A
rel
(per rel zione, alias nome): descrive la relazione tra la risorsa principale e quella legata (s) - A
href
: l'URL che indirizza le risorse collegate
Ulteriori attributi possono essere utilizzati anche per aiutare con la deprecazione, la negoziazione del contenuto, ecc.
Cormac Mulhall spiega che il cliente deve decidere quale verbo HTTP utilizzare in base a ciò che sta tentando di fare . In caso di dubbi, la documentazione dell'API dovrebbe comunque aiutare a comprendere le interazioni disponibili con tutti gli hypermedia.
Tipi di media
I tipi di media aiutano ad avere messaggi auto-descrittivi. Svolgono la parte del contratto tra client e server, in modo che possano scambiarsi risorse e ipermedie.
Sebbene application/json
e application/xml
siano tipi di media abbastanza popolari, non contengono molta semantica. Descrivono solo la sintassi generale utilizzata nel documento. I tipi di supporto più specializzati che supportano i requisiti HATEOAS devono essere utilizzati (o estesi tramite i tipi di media del fornitore ), come ad esempio:
Un client comunica a un server quali tipi di media comprende, aggiungendo l'intestazione Accept
alla sua richiesta, ad esempio:
Accept: application/hal+json
Se il server non è in grado di produrre una risorsa richiesta in tale rappresentazione, restituisce un 406 (NON ACCETTABILE) . In caso contrario, aggiunge il tipo di supporto nell'intestazione Content-Type
della risposta che contiene la risorsa rappresentata, ad esempio:
Content-Type: application/hal+json
Stateless> stateful
Perché?
Un server stateful implica che le sessioni dei client siano archiviate in un'archiviazione locale dell'istanza del server (quasi sempre nelle sessioni del server Web). Questo inizia a essere un problema quando si tenta di scalare orizzontalmente : se si nascondono diverse istanze del server dietro un servizio di bilanciamento del carico, se un client viene prima inviato all'istanza # 1 al momento dell'accesso, ma successivamente all'istanza # 2 quando si preleva una risorsa protetta ad esempio , quindi la seconda istanza gestirà la richiesta come anonima, poiché la sessione client è stata archiviata localmente nell'istanza # 1 .
Le soluzioni sono state trovate per affrontare questo problema (ad esempio, configurando la replica di sessione e / o la sessione appiccicosa ), ma l'architettura REST propone un altro approccio: semplicemente non rendi server statico, rendilo stateless . Secondo Fielding :
Ogni richiesta dal client al server deve contenere tutte le informazioni necessarie per comprendere la richiesta e non può sfruttare alcun contesto memorizzato sul server. Lo stato della sessione viene quindi mantenuto interamente sul client.
In altre parole, una richiesta deve essere gestita esattamente allo stesso modo, indipendentemente dal fatto che sia inviata all'istanza # 1 o all'istanza # 2 . Questo è il motivo per cui le applicazioni stateless sono considerate più facili da scalare .
Come?
Un approccio comune è un'autenticazione basata su token , in particolare con i token Web JSON di tendenza. Nota che JWT ha ancora alcuni problemi, in particolare per quanto riguarda l' invalidazione e il prolungamento automatico della scadenza (ad esempio, la funzione remember me ).
Note a margine
L'utilizzo di cookie o intestazioni (o qualsiasi altra cosa) non ha nulla a che fare con il server con stato o senza stato: questi sono solo i media che vengono qui usati per trasportare i token (identificatore di sessione per server stateful, JWT, ecc.), Niente di più.
Quando un'API RESTful viene utilizzata solo dai browser, i cookie ( HttpOnly e secure ) possono essere abbastanza comodi in quanto i browser li collegano automaticamente alle richieste in uscita. Vale la pena ricordare che se si opta per i cookie, sii a conoscenza di CSRF (un buon modo per evitare che i client generino e inviino lo stesso valore segreto univoco in un cookie e un'intestazione HTTP personalizzata ).
API memorizzabile in cache con richieste condizionali
Con l'intestazione Last-Modified
Il server può fornire un'intestazione di data Last-Modified
alle risposte che contengono le risorse che possono essere memorizzate nella cache. I clienti dovrebbero quindi memorizzare questa data insieme alla risorsa.
Ora, ogni volta che i client richiedono all'API di leggere la risorsa, possono aggiungere alle loro richieste un'intestazione If-Modified-Since
contenente la data dell'ultima Last-Modified
hanno ricevuto e memorizzato. Il server deve quindi confrontare l'intestazione della richiesta e l' ultima data effettiva modificata della risorsa. Se sono uguali, il server restituisce 304 (NON MODIFICATO) con un corpo vuoto: il client richiedente deve utilizzare la risorsa attualmente memorizzata nella cache.
Inoltre, quando i client richiedono all'API di aggiornare la risorsa (cioè con un verbo non sicuro), possono aggiungere un'intestazione If-Unmodified-Since
. Questo aiuta a gestire le condizioni di gara: se l'intestazione e l'effettiva data dell'ultima modifica sono diverse, il server restituisce un 412 (PRECONDIZIONE NON RIUSCITA) . Il client dovrebbe quindi leggere il nuovo stato della risorsa prima di riprovare per modificare la risorsa.
Con l'intestazione ETag
Un ETag (tag di entità) è un identificatore per uno stato specifico di una risorsa. Può essere un hash MD5 della risorsa per una validazione forte o un identificatore specifico del dominio per una convalida debole .
In sostanza, il processo è lo stesso dell'intestazione Last-Modified
: il server fornisce un'intestazione ETag
alle risposte che contengono le risorse memorizzabili nella cache e i client devono quindi archiviare questo identificatore insieme alla risorsa.
Quindi, i client forniscono un'intestazione If-None-Match
quando vogliono leggere la risorsa, contenente l'ultimo ETag ricevuto e archiviato. Il server può ora restituire un 304 (NON MODIFICATO) se l'intestazione corrisponde all'ETag effettivo della risorsa.
Anche in questo caso, i clienti possono fornire un'intestazione If-Match
quando desiderano modificare la risorsa e il server deve restituire un 412 (PRECONDITION FAILED) se l' ETag fornito non corrisponde a quello effettivo.
Note aggiuntive
ETag> data
Se i clienti forniscono sia la data che ETag nelle loro richieste, la data deve essere ignorata. Da RFC 7232 ( qui e qui ):
Un destinatario DEVE ignorare
If-Modified-Since
/If-Unmodified-Since
se la richiesta contiene un campo di intestazioneIf-None-Match
/If-Match
; la condizione inIf-None-Match
/If-Match
è considerata una sostituzione più accurata della condizione inIf-Modified-Since
/If-Unmodified-Since
, e i due sono combinati solo nell'interesse di interagire con gli intermediari più vecchi che potrebbe non implementareIf-None-Match
/If-Match
.
ETag poco profondi
Inoltre, mentre è abbastanza ovvio che le ultime date modificate vengono mantenute insieme alle risorse sul lato server, con ETag sono disponibili diversi approcci .
Un approccio usuale consiste nell'implementare gli ETB poco profondi: il server elabora la richiesta come se non fosse stato fornito alcun header condizionale, ma solo alla fine genera l'ETag della risposta che sta per restituire (ad esempio eseguendo l'hashing) e confronta con quello fornito. Questo è relativamente facile da implementare in quanto è necessario solo un intercettore HTTP (e molte implementazioni esistono già a seconda del server). Detto questo, vale la pena ricordare che questo approccio salverà la larghezza di banda ma non le prestazioni del server :
Un'attuazione più approfondita del meccanismo ETag potrebbe potenzialmente fornire benefici molto più grandi - come servire alcune richieste dalla cache e non dover eseguire affatto il calcolo - ma l'implementazione non sarebbe sicuramente tanto semplice, né tanto meno collegabile come l'approccio superficiale. descritto qui.
Insidie comuni
Perché non dovrei mettere i verbi in un URL?
HTTP non è RPC : ciò che rende l'HTTP significativamente diverso da RPC è che le richieste sono dirette alle risorse . Dopotutto, URL sta per Uniform Resource Locator, e un URL è un URI : un Uniform Resource Idenfitier. L'URL punta alla risorsa che vuoi gestire , il metodo HTTP indica cosa vuoi fare con esso . I metodi HTTP sono anche conosciuti come verbi : i verbi negli URL non hanno senso. Nota che le relazioni HATEOAS non dovrebbero contenere verbi, dato che anche i link sono indirizzati alle risorse.
Come aggiornare parzialmente una risorsa?
Poiché le richieste PUT
richiedono ai client di inviare l'intera risorsa con i valori aggiornati, PUT /users/123
non può essere utilizzato per aggiornare semplicemente l'e-mail di un utente, ad esempio. Come spiegato da William Durand in Please. Non patch come un idiota. sono disponibili diverse soluzioni conformi a REST:
- Esporre le proprietà della risorsa e utilizzare il metodo
PUT
per inviare un valore aggiornato, in quanto la specificaPUT
afferma che è possibile eseguire aggiornamenti di contenuto parziale indirizzando una risorsa identificata separatamente con uno stato che si sovrappone a una parte della risorsa più grande :
PUT https://example.com/api/v1.2/users/123/email
body:
new.email@example.com
- Utilizzare una richiesta
PATCH
contenente una serie di istruzioni che descrivano come la risorsa deve essere modificata (ad esempio, dopo la patch JSON ):
PATCH https://example.com/api/v1.2/users/123
body:
[
{ "op": "replace", "path": "/email", "value": "new.email@example.com" }
]
- Utilizzare una richiesta
PATCH
contenente una rappresentazione parziale della risorsa, come proposto nel commento di Matt Chapman :
PATCH https://example.com/api/v1.2/users/123
body:
{
"email": "new.email@example.com"
}
Che dire delle azioni che non si adattano al mondo delle operazioni CRUD?
Citando Vinay Sahni come best practice per la progettazione di un'API RESTful pragmatica :
Questo è dove le cose possono diventare confuse. Esistono diversi approcci:
Ristruttura l'azione in modo che appaia come un campo di una risorsa. Funziona se l'azione non prende parametri. Ad esempio, un'azione di attivazione può essere mappata a un campo
activated
booleano e aggiornata tramite un PATCH alla risorsa.Trattalo come una sotto risorsa con i principi RESTful. Ad esempio, l'API di GitHub ti consente di creare una sintesi con
PUT /gists/:id/star
e unstar conDELETE /gists/:id/star
.A volte non hai davvero modo di mappare l'azione a una struttura RESTful ragionevole. Ad esempio, una ricerca con più risorse non ha realmente senso per essere applicata all'endpoint di una specifica risorsa. In questo caso,
/search
avrebbe più senso anche se non è una risorsa. Questo è OK - fai semplicemente ciò che è giusto dal punto di vista del consumatore dell'API e assicurati che sia documentato chiaramente per evitare confusione.
Pratiche comuni
L'API è documentata Gli strumenti sono disponibili per aiutarti a creare la tua documentazione, ad es. Swagger o Spring REST Docs .
L'API è versionata , tramite le intestazioni o tramite l'URL:
https://example.com/api/v1.2/blogs/123/articles
^^^^
- Le risorse hanno nomi plurali :
https://example.com/api/v1.2/blogs/123/articles
^^^^^ ^^^^^^^^
- Gli URL utilizzano kebab-case (le parole sono in minuscolo e separate da un trattino):
https://example.com/api/v1.2/quotation-requests
^^^^^^^^^^^^^^^^^^
- HATEOAS fornisce un collegamento "autonomo" alle risorse, mirando a se stesse:
{
...,
_links: {
...,
self: { href: "https://example.com/api/v1.2/blogs/123/articles/789" }
^^^^
}
}
- Le relazioni HATEOAS utilizzano lowerCamelCase (le parole sono in minuscolo, quindi in maiuscolo tranne il primo e gli spazi sono omessi), per consentire ai client JavaScript di utilizzare la notazione dei punti rispettando le convenzioni di denominazione JavaScript quando accedono ai collegamenti:
{
...,
_links: {
...,
firstPage: { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=1&pageSize=25" }
^^^^^^^^^
}
}
Gestione dei blog tramite un'API HTTP RESTful
I seguenti esempi usano HAL per esprimere HATEOAS e fanno uso di:
- CURIE (Compact URI): utilizzato per fornire collegamenti alla documentazione API
- Modelli URI : URI che include parametri che devono essere sostituiti prima che l'URI sia risolto
Ottieni un blog 123
Richiesta
GET https://example.com/api/v1.2/blogs/123
headers:
Accept: application/hal+json
Risposta
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"id": 123,
"title": "The blog title",
"description": "The blog description",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123" },
"doc:articles": { "href": "https://example.com/api/v1.2/blogs/123/articles{?pageIndex,pageSize}", "templated": true }
}
}
Crea un nuovo articolo nel blog 123
Richiesta
POST https://example.com/api/v1.2/blogs/123/articles
headers:
Content-Type: application/json
Accept: application/hal+json
X-Access-Token: XYZ
body:
{
"title": "The title 2",
"content": "The content 2"
}
Risposta
status: 201 (CREATED)
headers:
Content-Type: application/hal+json
body:
{
"id": 789,
"title": "The title 2",
"content": "The content 2",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}
Ottieni l'articolo 789 del blog 123
Richiesta
GET https://example.com/api/v1.2/blogs/123/articles/789
headers:
Accept: application/hal+json
Risposta
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"id": 789,
"title": "The title 2",
"content": "The content 2",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}
Ottieni la quarta pagina di 25 articoli del blog 123
Richiesta
GET https://example.com/api/v1.2/blogs/123/articles?pageIndex=4&pageSize=25
headers:
Accept: application/hal+json
Risposta
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"pageIndex": 4,
"pageSize": 25,
"totalPages": 26,
"totalArticles": 648,
"_link": {
"firstPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=1&pageSize=25" },
"previousPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=3&pageSize=25" },
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=4&pageSize=25" },
"nextPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=5&pageSize=25" },
"lastPage": { "href": "https://example.com/api/v1.2/blogs/123/articles?pageIndex=26&pageSize=25" }
},
"_embedded": [
{
...
}, {
"id": 456,
"title": "The title 1",
"content": "The content 1",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/456" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/456/comments{?pageIndex,pageSize}", "templated": true }
}
}, {
"id": 789,
"title": "The title 2",
"content": "The content 2",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}, {
...
}
]
}
Aggiornare l'articolo 789 del blog 123
Richiesta
PUT https://example.com/api/v1.2/blogs/123/articles/789
headers:
Content-Type: application/json
Accept: application/hal+json
X-Access-Token: XYZ
body:
{
"id": 789,
"title": "The title 2 updated",
"content": "The content 2 updated"
}
Risposta
status: 200 (OK)
headers:
Content-Type: application/hal+json
body:
{
"id": 789,
"title": "The title 2 updated",
"content": "The content 2 updated",
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"self": { "href": "https://example.com/api/v1.2/blogs/123/articles/789" },
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" },
"doc:comments": { "href": "https://example.com/api/v1.2/blogs/123/articles/789/comments{?pageIndex,pageSize}", "templated": true }
}
}
Gli appunti
- L'identificatore utilizzato per identificare la risorsa da aggiornare è quello nell'URL : quello nel corpo (se presente) deve essere ignorato silenziosamente.
- Poiché una richiesta
PUT
aggiorna l'intera risorsa, se nessuncontent
sarebbe stato inviato, avrebbe dovuto essere rimosso dalla risorsa persistente.
Elimina l'articolo 789 del blog 123
Richiesta
DELETE https://example.com/api/v1.2/blogs/123/articles/789
headers:
Accept: application/hal+json
X-Access-Token: XYZ
Risposta
status: 204 (NO CONTENT)
headers:
Content-Type: application/hal+json
body:
{
"_links": {
"curies": [{ "name": "doc", "href": "https://example.com/docs/{rel}", "templated": true }],
"doc:blog": { "href": "https://example.com/api/v1.2/blogs/123", "title": "The blog title" }
}
}
ROVERE violento
<stock>
<add>
<item>
<name>Milk</name>
<quantity>2</quantity>
</item>
</add>
</stock>
Mettere questo corpo a una risorsa come /stocks/123
viola l'idea alla base di REST. Mentre questo corpo è put
e contiene tutte le informazioni necessarie, arriva anche con una chiamata al metodo da add
da qualche parte quando il corpo viene elaborato. A seguito di REST, pubblicheremo l' item
su /stocks/123/items/
.