API RESTful rappresenta l'assenza di una cosa

18

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

In questo momento:

/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 spirito animale infelice poiché stiamo rappresentando un problema di dominio valido - 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 selezione in modo da poterli richiedere.

Qual è la risposta migliore qui:

HTTP 200 e {selectedAnimal:null}

o anche più esplicito

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

O è meglio restituire un 404? Poiché molto simile a this image has not yet been uploaded quando si visualizza un'immagine online sarebbe un 404.% dithis person has not selected a spirit animal potrebbe essere un 404

Questa domanda è stata proposta come un duplicato, ma quella domanda risolve un URL valido che viene richiesto quando l'applicazione è stata configurata per non consentire la modifica che l'URL rappresenta.

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

Quindi questa non è la "logica del business", ma piuttosto una circostanza in cui l'assenza di una cosa ha un significato (potrebbe essere che molti dei miei colleghi sostengono che 404 è ancora corretto) ma non sono sicuro di come mappare quello alla specifica.

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

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

Il consenso tra i miei colleghi è che questo è un sintomo di un cattivo design API

Probabilmente sarebbe meglio che chiedessimo semplicemente / person / {id} e che restituisca un insieme di relazioni di collegamento per la persona ... quindi se non ti viene dato il link / selectedSpiritAnimal (quando una persona non ha selezione ) ma tu lo chiami 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 client non richieda un sottoinsieme di dati

    
posta Paul D'Ambra 25.09.2017 - 18:01
fonte

5 risposte

24

I codici HTTP 4xx probabilmente non sono la scelta giusta per questo scenario. Dichiari che avere zero spiriti animali è uno stato valido, e la rotta dell'API person/{id}/selectedSpiritAnimal terrà conto del fatto che la persona id ne abbia o meno.

Le risposte HTTP 4xx sono riservate alla situazione quando un client ha fatto qualcosa di sbagliato nella richiesta (vedi archivio di w3 delle specifiche originali ). Ma il cliente sta facendo una richiesta valida, indipendentemente dal fatto che la persona id abbia o meno un animale spirituale.

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

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

    
risposta data 25.09.2017 - 18:32
fonte
24

Permettetemi di presentarvi il modello di maturità Richardson .

Il tuo problema è che stai rappresentando due risorse come una, in cui dovresti davvero avere due risorse che hanno una relazione indicata da hypermedia. Usare hypermedia per descrivere le relazioni è il glorioso livello 3 di Rest.

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 link all'animale.

Immaginiamo una persona chiamata Bob, che ha 123 id e un animale spiritico Unicorno.

GET /person/123

restituirebbe;

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

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

GET /spitiranimal/789

potrebbe restituire

{
  "type": "Unicorn"
}

Ora immaginiamo una persona chiamata Fred, che ha id 456 e nessun animale spirituale.

GET /person/456

restituirebbe;

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

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

    
risposta data 26.09.2017 - 14:59
fonte
1

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

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

Dovresti avere un separatore webmethod /person/{id}/hasSelectedSpiritAnimal che restituisce {"isSpiritAnimalSelected": false} . Dietro le quinte, può o non può effettuare le stesse chiamate di metodo, restituendo false se null, ma è compito che decida, non il codice che consuma.

È meglio evitare la combinazione per separare le query in un unico metodo web senza un motivo valido per farlo, anche se le query sono strettamente correlate.

    
risposta data 25.09.2017 - 18:31
fonte
1

Ciò che rappresenta il tuo endpoint non è solo un animale; è un animale o non ce n'è. È un valore meglio rappresentato da un Optional / Maybe / Nullable / etc.

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

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

Potrei immaginare che il metodo DELETE , quando applicato all'endpoint, possa impostare nuovamente 'selected' a false , ovvero, annullare l'impostazione dell'animale selezionato.

Ovviamente puoi rilasciare la chiave 'selected' qui, viene mostrata solo per chiarezza; string vs null è sufficiente per la distinzione.

    
risposta data 26.09.2017 - 04:01
fonte
0

Dovresti usare 404.

The 404 (Not Found) status code indicates that the origin server did not find a current representation for the target resource

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 è opzionale.

Lo preferisco perché preferisco il più possibile i protocolli standard. HTTP ha un modo per rappresentare la non esistenza, ed è quello che userei.

MODIFICA: Supponiamo che tu abbia aggiunto una funzione in cui gli utenti possono scegliere se condividere i loro animali spirituali e qualcuno non li ha condivisi. Vorresti restituire 200 OK null o 200 OK "Unauthorized ? O useresti lo standard 401 Non autorizzato / 403 Proibito? Questo sembra direttamente analogo a non sceglierne uno al primo posto.

In alternativa, se vuoi usare 200 OK + JSON, dovresti restituire 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ù wrapping solo se necessario.

    
risposta data 26.09.2017 - 00:12
fonte

Leggi altre domande sui tag