L'API RESTful rappresenta l'assenza di qualcosa


18

Immagina un'API per identificare se una persona ha selezionato il suo animale spirituale. Possono avere solo zero o un animale spirito.

Attualmente:

/person/{id}/selectedSpiritAnimal

quando hanno selezionato un animale restituisce http 200 e {selectedAnimal:mole}

ma quando non hanno alcuna selezione, restituisce http 404.

Questo rende il mio animale spirituale infelice poiché rappresentiamo una preoccupazione di dominio valida - non avendo ancora selezionato un animale spirituale - come un errore HTTP.

Inoltre, come azienda - erm Sprit-Animal-Hampers-R-us - vogliamo sapere quando qualcuno non ha alcuna selezione in modo da poterlo sollecitare.

Qual è una risposta migliore qui:

HTTP 200 e {selectedAnimal:null}

o ancora più esplicito

HTTP 200 e {selectedAnimal:null, spiritAnimalSelected: false}

O è meglio restituire un 404? Dal momento che molto simile this image has not yet been uploadedalla visualizzazione di un'immagine online sarebbe un 404. this person has not selected a spirit animalpotrebbe essere un 404


Questa domanda è stata proposta come duplicata, ma quella domanda affronta un URL altrimenti valido richiesto quando l'applicazione è stata configurata per non consentire la modifica rappresentata dall'URL.

Mentre qui sto osservando come si rappresenta una risorsa in cui l'assenza della risorsa è significativa. Vale a dire che è valido per il client richiedere l'URL e la risposta è che hai richiesto correttamente la risorsa che rappresenta un'assenza di una cosa.

Quindi questa non è una "logica di business", ma piuttosto una circostanza in cui l'assenza di qualcosa ha un significato (potrebbe essere come molti dei miei colleghi sostengono che 404 sia ancora corretto) ma non sono sicuro di come mapparlo al spec.


Molto difficile scegliere una risposta. Ho cambiato idea più volte durante la conversazione qui e quella in corso al lavoro.

La cosa che lo risolve per me qui è che la specifica dice che un 4xx è quando il client ha sbagliato . In questo caso al cliente è stato detto di aspettarsi una risposta dall'URL selezionatoSpiritAnimal, quindi non ha commesso errori.

Il consenso tra i miei colleghi è che questo è un sintomo di una cattiva progettazione delle API

Probabilmente sarebbe meglio che semplicemente richiedessimo / person / {id} e che restituisca un insieme di relazioni di link per la persona ... quindi se non ti viene dato il link / selectedSpiritAnimal (quando una persona non ha selezione) ma tu chiamalo comunque allora un 404 ha un senso. Oppure implementare risposte parziali e lasciare che / person / {id} restituisca un documento più completo a meno che il cliente non richieda un sottoinsieme dei dati


5
Non hai spiegato perché ritieni che sia un problema restituire un 404. Dal punto di vista del dominio, non sai se hai ricevuto un 404 o un 200, sottratto dal livello client.
Vincent Savard,

14
o forse è meglio restituire 204 senza contenuto?
Paul D'Ambra,

6
Suppongo che la mia preoccupazione con 404 sia inequivocabile un cambiamento di configurazione che introduce un modello di URL non valido da una persona senza animale spirituale
Paul D'Ambra,

2
@ PaulD'Ambra Per quello che vale, non vorrei usare un contenuto. Non ho visto i codici HTTP gestiti sul front-end in quel modo in Javascript dai giorni XmlHttpRequest. Ma è certamente valido.
Brandon Arnold,

Risposte:


24

I codici HTTP 4xx non sono probabilmente la scelta giusta per questo scenario. Dichiarate che avere zero animali spirituali è uno stato valido e la rotta API spiegherà person/{id}/selectedSpiritAnimalse la persona ne idha o meno uno.

Le risposte HTTP 4xx sono riservate alla situazione in cui un client ha fatto qualcosa di errato nella richiesta (consultare l'archivio di w3 delle specifiche originali ). Ma il cliente sta facendo una richiesta valida, indipendentemente dal fatto che una persona idabbia o meno un animale spirituale.

Quindi mi appoggio alle seconde soluzioni usando un corpo JSON correttamente formattato nella risposta e un codice HTTP 2xx.

Ora se ricevi una tale richiesta e risulta che la persona idnon esiste, un codice 4xx ha più senso.


17
"Le risposte HTTP 4xx sono riservate alla situazione in cui un client ha fatto qualcosa di errato nella richiesta". Quando fai dichiarazioni autorevoli sulla specifica, fai riferimento alla specifica HTTP effettiva e non (a) un framework costruito sopra di essa, o (b) un post di blog casuale.
Eric Stein,

5
@EricStein Mi sono sentito un po 'pigro al riguardo; grazie per la critica. Aggiornato.
Brandon Arnold,

1
Sento che il link RFC qui è in conflitto. Da un lato la parte 4xx dice cases in which the client seems to have erred, ma dall'altro il 404 dice direttamente The server has not found anything matching the Request-URI. Potresti considerare di richiedere qualcosa che non esiste un errore client. Capisco la persona che non esiste contro un oggetto secondario non esistente, ma che potrebbe essere indicato come messaggio di risposta. Anche 204 sembra rilevante, poiché l'entità esiste, ma non ha contenuto per una proprietà secondaria.
shortstuffsushi,

1
Il cliente ha fatto qualcosa di sbagliato; ha richiesto l'animale spirit selezionato per un utente quando non esiste. Questo è esattamente ciò che significa 404 ... hai chiesto qualcosa che non c'è.
Andy,

5
Quando il mio browser inoltra una richiesta a softwareengineering.stackexchange.com/questions/unicorn è una richiesta valida eppure ricevo ancora un 404 (sembra che non ci siano dubbi sull'ID "unicorno").
user253751

24

Lascia che ti presenti il modello di maturità Richardson .

Il tuo problema è che stai rappresentando due risorse come una, dove dovresti davvero avere due risorse che hanno una relazione indicata da hypermedia. Usare l'ipermedia per descrivere le relazioni è il glorioso livello 3 di Riposo.

La tua persona dovrebbe vivere sotto l'URI /person/{id}e l'animale dovrebbe vivere sotto /spiritanimal/{id}. La persona dovrebbe indicare che ha un animale spirituale usando un collegamento all'animale.

Immaginiamo una persona di nome Bob, che ha l'ID 123 e un animale spirito unicorno.

GET /person/123

ritornerebbe;

{
  "name": "Bob",
  "links": [
    {
      "rel": "spiritanimal",
      "uri": "/spiritanimals/789"
    }
  ]
}

Ora chiunque legga la persona 123 saprà di avere un animale spirituale e ha l'URI dove può ottenere maggiori informazioni su di esso.

GET /spitiranimal/789

potrebbe tornare

{
  "type": "Unicorn"
}

Ora immaginiamo una persona di nome Fred, che ha l'id 456 e nessun animale spirituale.

GET /person/456

ritornerebbe;

{
  "name": "Fred",
  "links": [
  ]
}

Ora chiunque leggerà la persona 456 saprà di non avere un animale spirituale, poiché non esiste alcun collegamento. Non è necessario utilizzare alcun codice di stato HTTP per rappresentare la mancanza di una relazione.


1
Stavo solo aggiungendo alla domanda che, data la possibilità di cambiare l'API, un certo livello di HATEOAS sarebbe probabilmente la soluzione giusta. Questo è un ottimo esempio di ciò
Paul D'Ambra il

1

Questo è l'URL appropriato per ottenere animali spirituali; pertanto, un errore 404 non è appropriato. 404 è per rappresentare un problema tecnico, non un problema logico.

La soluzione appropriata è restituire http 200 e {"selectedAnimal": null}

Dovresti avere un metodo web separato/person/{id}/hasSelectedSpiritAnimal che ritorna {"isSpiritAnimalSelected": false}. Dietro le quinte, può o meno effettuare le stesse chiamate del metodo, restituendo false se nulle, ma sta a lui decidere, non il codice consumante.

È meglio evitare di combinare query separate in un metodo Web senza un motivo convincente per farlo, anche se le query sono strettamente correlate.


1
Potresti spiegare perché ritieni che questa sia la soluzione appropriata? Non ho alcun senso di restituire i dati quando non ci sono dati da restituire. Sono d'accordo con te sul fatto che un 404 non ha senso poiché l'URL va bene, quindi un 204 sembra avere il senso per me.
Vincent Savard,

2
I codici di stato di @VincentSavard sono più difficili da gestire rispetto alle risposte json e sono più appropriati per problemi tecnici piuttosto che comunicare informazioni sul dominio.
TheCatWhisperer,

2
204: Nessun contenuto con un corpo vuoto. È tutto chiaro e autoesplicativo. Non c'è bisogno di discutere ulteriormente. Tutto sommato, quando non esiste un modello di progettazione chiaro, un SE dovrebbe sceglierne uno, piegarlo alle sue necessità e fornire documentazione. Restituire un corpo con una risposta 204 non è conseguente.
Formixian,

2
@formixian ... Se dovessi creare un bjson / tcp api anziché un json / http, cosa restituiresti per questo caso? Affidarmi ai codici http mi sembra inutilmente vincolare i risultati dell'API alla sua implementazione http.
TheCatWhisperer,

2
@VincentSavard When you said "the spirit animal is not currently on file", it seemed quite similar to me to "there is no content"Nessun contenuto significa nessun contenuto . vale a dire: restituisce "". Questi due non sono affatto simili. "l'animale spirituale non è attualmente in archivio" è molto diverso da "".
Shane,

1

Ciò che rappresenta il tuo endpoint non è solo un animale; è un animale o mancanza di esso. È un valore rappresentato al meglio da un Optional/ Maybe/ Nullable/ ecc.

Quindi i valori legittimi (come in 200 OK) possono essere:

  • {'animal': <some animal>, 'selected': true}
  • {'animal': null, 'selected': false}

Potevo immaginare che DELETEil metodo, quando applicato al punto finale, può impostare 'selected'a falsevolta, che è, disinserire l'animale selezionato.

Puoi, ovviamente, rilasciare la 'selected'chiave qui, è mostrata solo per chiarezza; stringa vs nullè sufficiente per la distinzione.


0

Dovresti usare 404.

Il codice di stato 404 (non trovato) indica che il server di origine non ha trovato una rappresentazione corrente per la risorsa di destinazione

RFC7231

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

"mole"

HTTP/1.1 404 Not Found
Content-Type: text/plain
Date: Mon, 25 Sep 2017 00:00:00 GMT

this person has not selected a spirit animal

Dato che stai creando un'interfaccia di programmazione, non un'interfaccia umana, il testo 404 è facoltativo.

Preferisco questo perché preferisco i protocolli standard il più possibile. HTTP ha un modo per rappresentare la non-esistenza, ed è quello che vorrei usare.

MODIFICA: Supponi di aver aggiunto una funzione in cui gli utenti possono scegliere se condividere i loro animali spirituali e qualcuno non lo condivide. Restituiresti 200 OK nullo 200 OK "Unauthorized? O useresti lo standard 401 non autorizzato / 403 proibito? Questo sembra direttamente analogo al non sceglierne uno in primo luogo.


In alternativa, se si desidera utilizzare 200 OK + JSON, è necessario tornare null.

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

"mole"

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

null

Mantieni le cose pulite. Crea più avvolgimenti solo se necessario.


2
I dati sono stati trovati, però. Accade solo che i dati siano null(non hanno valore). Questo è diverso dal client che richiede qualcosa per cui non esiste uno slot per contenere il valore. Non suggeriresti di lanciare un AttributeErrorin Python quando il valore sembra essere None; ciò renderebbe l'interfaccia poco pratica e inutilmente difficile da lavorare. Più pragmaticamente, molte API client HTTP potrebbero convertire il 404 nel meccanismo di gestione degli errori standard della lingua (codice errore, eccezione, tipo di errore), il che significa che dovresti eliminare un errore estraneo.
jpmc26,

@Paul Draper Scorri un po 'verso l'alto nelle specifiche, vedrai che fa un'istruzione coperta su HTTP 4xx: "La classe 4xx del codice di stato è destinata ai casi in cui il client sembra aver sbagliato." L'op ha affermato chiaramente che non avere un animale spirituale è uno stato valido per il quale l'API dovrebbe tenere conto. tools.ietf.org/html/rfc7231#section-6.5
Brandon Arnold

Come si fa quindi a distinguere tra l'indicazione della non esistenza della risorsa richiesta (cioè nessun animale selezionato) e il cliente che richiede un percorso non valido (cioè /person/{id}/selectedSpritAnimalosservare l'errore di battitura Sprit).
sampathsris,

1
Indipendentemente dall'intenzione, un 404 significa strettamente che la risorsa non è stata trovata. Se selectedSpiritAnimal è una risorsa e nessuna esiste, allora non c'è nulla da OTTENERE e un 404 è appropriato. Tuttavia, se il client desidera sapere se è stato selezionato un animale spirituale, il server dovrebbe esporre un'altra risorsa /person/{id}/isSpiritAnimalSelectedche indicherebbe al client se è stato selezionato. Mi sembra lo stesso classico esempio di test sull'esistenza di un file prima di leggerlo. Basta leggere il file e gestire l'errore ENOENT in caso di lancio.
aaaaaa,

1
@PaulDraper Il punto non è se la risorsa esiste o meno. Il punto è che i codici HTTP 4xx sono destinati a quando il chiamante utilizza l'API in modo errato. Op afferma che /person/{id}/selectedSpiritAnimaldovrebbe essere usato anche se non esiste un animale spirituale. Ciò significa che HTTP 4xx non è corretto, se utilizzato in questo caso. Op afferma inoltre correttamente che questo potrebbe essere un odore di cattiva progettazione API.
Brandon Arnold,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.