Un'API REST deve restituire un errore interno di 500 server per indicare che una query fa riferimento a un oggetto che non esiste?

37

Sto lavorando con un'API REST che risiede su un server che gestisce i dati per una moltitudine di dispositivi IoT.

Il mio compito è interrogare il server usando l'API per raccogliere informazioni specifiche sul rendimento di tali dispositivi.

In un'istanza, ottengo un elenco di dispositivi disponibili e i relativi identificatori corrispondenti, quindi richiedo più tardi al server per ulteriori dettagli utilizzando tali identificatori (GUID).

Il server restituisce una 500 Internal Server Error per una query su uno di questi ID. Nella mia applicazione, viene generata un'eccezione e non vedo i dettagli sull'errore. Se analizzo la risposta più da vicino con Postman , posso vedere che il server ha restituito JSON nel corpo che contiene:

errorMessage: "This ID does not exist".

Ignora il fatto che il server abbia fornito l'ID per iniziare - questo è un problema separato per lo sviluppatore.

Un'API REST dovrebbe restituire una 500 Internal Server Error per segnalare che una query fa riferimento a un oggetto che non esiste? A mio avviso, i codici di risposta HTTP dovrebbero fare riferimento rigorosamente allo stato della chiamata REST, piuttosto che alla meccanica interna dell'API. Mi aspetterei un 200 OK con la risposta contenente l'errore e la descrizione, che sarebbe di proprietà dell'API in questione.

Mi sembra che ci sia una potenziale differenza di aspettativa a seconda di come è strutturata la chiamata REST.

Considera questi esempi:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

Nel primo caso, l'ID del dispositivo viene passato come variabile GET. Un 404 o 500 indica che il percorso ( /restapi/deviceinfo ) non viene trovato o ha provocato un errore del server.

Nel secondo caso, l'ID del dispositivo è parte dell'URL. Sarei più comprensivo di un 404 Not Found , ma potrei comunque argomentare sulla base delle parti del percorso interpretate come variabili rispetto a endpoint.

    
posta JYelton 23.03.2018 - 17:31
fonte

11 risposte

95

Penso che una risposta 404 sia la migliore corrispondenza semantica qui, perché la risorsa che stavi cercando di trovare (rappresentata dall'URI utilizzato per la query) non è stata trovata. Restituire un carico utile di errore nel corpo è ragionevole, ma non richiesto.

Secondo RFC 2616 , la definizione del codice di stato 404 è :

10.4.5 404 Not Found
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.

    
risposta data 23.03.2018 - 17:42
fonte
34

Userò i tuoi esempi.

http://example.com/restapi/deviceinfo?id=123

Se l'endpoint restituisce un json array , la scelta migliore è 200 OK con un array vuoto se non viene trovato alcun risultato.

Se l'endpoint è progettato per restituire un singolo risultato , la mia scelta sarebbe 404 NOT FOUND , perché, per me, la sintassi corretta per questo tipo di endpoint è: http://example.com/restapi/deviceinfo/123 . Di solito utilizzo il parametro di richiesta solo per il filtraggio e quando il mio endpoint restituisce un array.

http://example.com/restapi/device/123/info

Penso che questa domanda abbia già risposto qui . POST o GET, la scelta migliore sembra 404 NOT FOUND perché la risorsa 123 non è stata trovata.

In entrambi i casi non riesco a vedere la necessità di spiegare il motivo per cui la richiesta non è stata completata. Le informazioni sulla richiesta e il codice HTTP spiegano già perché.

    
risposta data 23.03.2018 - 19:35
fonte
26

HTTP 404 è corretto, perché il server capisce quale risorsa richiede il client, ma non ha quella risorsa.

Il fatto che tu stia lavorando con una "API REST" è la chiave. L'API dovrebbe comportarsi come se stesse eseguendo un trasferimento dello stato di REpresentational, non eseguendo una funzione. (Certo, il termine "REST" ha avuto un significato più ampio, ma qui puoi ancora usare il suo significato letterale con buoni risultati.) Il cliente ha chiesto lo stato di una risorsa descritta dall'URL http://example.com/restapi/device/123/info . Una querystring ( /deviceinfo?id=123 ) non cambierebbe la situazione. Il server sa che stai chiedendo di trasferire lo stato del dispositivo 123, ma non lo riconosce come risorsa conosciuta. Quindi HTTP 404 .

Anche le altre risposte possibili qui trattate hanno significati specifici:

  • HTTP 200 - Abbiamo lo stato per te; è nel corpo della risposta.
  • HTTP 204 - Abbiamo lo stato per te; è vuoto.
  • HTTP 400 - Non possiamo dire quale risorsa stai chiedendo. Correggi il tuo URL.
  • HTTP 500 - Abbiamo funzionato male. Non è colpa tua.

Vedi RFC 2616 sec. 10 come appropriato.

    
risposta data 24.03.2018 - 00:43
fonte
11

Un errore 5xx viene in genere utilizzato per indicare che il server ha riscontrato un errore e non può completare la richiesta. Se il server accetta la richiesta, è in grado di analizzarlo correttamente e quindi fa il suo lavoro, che non dovrebbe restituire un errore 5xx.

Non sono sicuro che esista un qualche tipo di convenzione su cosa restituire se una query non produce risultati. Ho visto sia quello che descrivi (un 200 con un corpo che contiene un messaggio) sia un 404 che indica che i risultati non sono stati trovati. Il 200 probabilmente ha più senso: la richiesta è stata completata con successo e non ci sono stati problemi con la richiesta del client o durante l'elaborazione della richiesta da parte del server. Un corpo può consegnare un messaggio al cliente.

Tratterei entrambi i tuoi esempi ( http://example.com/restapi/deviceinfo?id=123 e http://example.com/restapi/device/123/info ) uguali - il 123 è un parametro. Entrambi i casi sono diversi modi di strutturare una richiesta per ottenere informazioni sul dispositivo per un dispositivo con ID 123.

In primo luogo, considererei l'autorizzazione e l'autenticazione. Se l'utente non dispone delle autorizzazioni appropriate, restituirei un 403 o un 401 come appropriato. Sebbene si chiami "non autorizzato", la mia comprensione è che il 401 riguarda più l'autenticazione e il 403 riguarda il non autorizzato o il permesso negato. Non sarei troppo schizzinoso qui, però, se volessi limitarti a 403 per tutti gli errori di autenticazione e autorizzazione.

Quindi, gestirò l'ID. In base al tuo esempio, sembra che si tratti di un ID numerico. Se è stato fornito un valore non numerico, restituirei 400. Se il parametro potrebbe essere un identificatore di dispositivo valido, quindi continuerei con l'elaborazione. Se ci fossero altri argomenti, verrebbero anche controllati qui. Mi aspetto che il corpo della risposta contenga informazioni appropriate sul motivo per cui la richiesta è stata negativa.

Se tutti i parametri fossero validi, inizierei a elaborare la richiesta. Se il sistema o qualsiasi dipendenza (un database, un servizio di terze parti, un altro servizio interno) non è disponibile, restituirei un codice 5xx - 503 sarebbe specifico, ma sarebbe accettabile anche un 500. In entrambi i casi, vorrei restituire un corpo con ulteriori dettagli. Considerare che se una dipendenza esterna riporta un Timeout di richiesta di 408, lo mangerei e restituire un 500 al mio client, consentendo a un client di ricevere un 408 solo se la richiesta al mio sistema è scaduta. Se il sistema è in grado di completare la richiesta, restituirei 200 e il corpo appropriato.

204 può essere utile in alcuni casi, ma ti impedisce di inviare un corpo di risposta. Soprattutto in un'impostazione API, l'invio di un corpo di risposta con informazioni che possono essere inserite in un meccanismo di registrazione o segnalazione sembra la decisione giusta da fare nella maggior parte dei casi.

L'unica volta che viene restituito un 404 è se il server non ha avuto un endpoint /deviceinfo o un endpoint /device/:id/info .

Non considererei un ID che non è stato trovato uguale alla risorsa non trovata. La risorsa è l'informazione del dispositivo per un particolare dispositivo (nel tuo esempio). Restituire un 404 significherebbe che la risorsa (le informazioni sul dispositivo) non esiste. Un 200 con un corpo appropriato significa che il sistema può effettivamente fornire informazioni sul dispositivo. Potrebbe esserci o meno un dispositivo con l'ID specificato.

    
risposta data 23.03.2018 - 17:39
fonte
5

Un errore HTTP della serie 500 indica un malfunzionamento del server. Oltre a 501 Not Implemented e 505 HTTP Version Not Supported , l'uso di questi codici di errore comporta l'implicazione che riprovare la richiesta in un secondo momento possa avere successo (sebbene solo 503 Service Unavailable lo specifichi esplicitamente). Idealmente, un server non dovrebbe mai produrre uno di questi codici, anche se l'impossibilità di scrivere software privo di bug e di fornire al server risorse infinite significa che ne avrai bisogno di volta in volta.

Per un risultato "oggetto inesistente", dovresti probabilmente restituire 404 Not Found (quando la richiesta è per un oggetto per nome) o 200 Success con un corpo risultato vuoto (quando cerchi un oggetto per attributi ). 204 No Content sembra allettante, ma lo userei solo per le situazioni in cui la mancanza di un corpo di risposta è il risultato previsto.

    
risposta data 24.03.2018 - 01:29
fonte
1

Come client della tua API, quando eseguo una di queste chiamate:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

Mi aspetto di ottenere una (rappresentazione di) un oggetto DeviceInfo (o qualche tipo particolare comunque, sia che si tratti di un tipo formale o semplicemente di qualcosa conforme a una convenzione documentata "tipo di anatra"). Voglio uno stato di 200 per significare che ne ho ricevuto uno, e posso andare avanti e usarlo.

Per le API REST, penso ai codici di stato 400 e 500 come ad eccezioni. Li usi per indicare quando non puoi restituire una risposta "normale" per la richiesta che hai ricevuto, quindi il cliente dovrà fare qualcosa di eccezionale piuttosto che elaborare le informazioni che si aspettava di recuperare.

Questo significa, come utente API, che posso utilizzare una sorta di funzione di chiamata di riposo controllata che recupera una risposta o genera un'eccezione. È fantastico; la mia logica normale può essere un codice di linea retta e posso organizzare la gestione degli errori nello stesso modo in cui faccio nel codice locale. 404 imprevisti si manifestano come eccezioni "nessuna risorsa trovata" senza che io debba fare nulla, non come errori di "attributo mancante" quando in seguito sto elaborando { errorMessage: "Device 123 not found" } come se fosse un oggetto DeviceInfo .

Se ritieni che l'endpoint http://example.com/restapi/deviceinfo sia trovato, ed è solo il id=123 che non lo è, e quindi restituisci 200 con un messaggio di errore nel corpo, allora sei creare esattamente lo stesso tipo di problemi di interfaccia delle funzioni C che potrebbero restituire un risultato corretto o un codice di errore, oppure metodi che indicano problemi restituendo arbitrariamente null . È molto più bello come utente della tua interfaccia avere errori segnalati attraverso un canale "separato" da rendimenti regolari. Questo vale anche qui, anche se le risposte HTTP 200, 404 e 500 sono lo stesso canale da un punto di vista di basso livello. Sono standardizzati e facili da distinguere, quindi la mia struttura client REST può facilmente passare a quegli stati per trasformarli in strutture adeguate nella mia lingua; per fare la stessa cosa con il livello JSON (dove dici sempre 200 e dammi un DeviceInfo o un messaggio di errore) Ho bisogno di incorporare una certa conoscenza degli schemi JSON che usi.

Quindi usa 200 quando puoi restituire un valore valido del tipo atteso (che è il motivo per cui http://example.com/restapi/search-devices?colour=blue può restituire 200 con un array vuoto se non ci sono dispositivi blu, un array vuoto è un array valido e un array sensibile rispondere alla richiesta "Vorrei i dettagli di tutti i dispositivi blu"). Se non è possibile, utilizzare il codice di stato non 200 più appropriato. Anche se "il dispositivo 123 non esiste" è la risposta corretta a "dammi i dettagli del dispositivo 123" e non è un errore per il server , è un'eccezione per le aspettative del cliente che Riceverò un DeviceInfo e non dovrebbe essere comunicato come una normale risposta "ecco cosa hai chiesto".

    
risposta data 26.03.2018 - 02:47
fonte
0

Potresti utilizzare l'errore 422 Entità non elaborabile per differenziare da 404 non trovato . 422 significa che il server comprende la richiesta ma non può dare una risposta adeguata. Sto usando questo codice in situazioni simili.

    
risposta data 23.03.2018 - 20:52
fonte
0

L'errore 500 normalmente indica che la richiesta ha bloccato un programma lato server; negli ambienti aziendali questi errori vengono trattati come un uovo in faccia e vengono evitati.

Errore 4xx dovrebbe segnalare al programmatore che l'endpoint API (risorsa) non esiste. Di conseguenza, una volta raggiunto l'endpoint appropriato, qualsiasi errore di gestione da quel punto in avanti è responsabilità del programmatore dell'API che deve essere gestito con garbo, cioè con un messaggio di errore di 200 risposte.

    
risposta data 23.03.2018 - 21:19
fonte
0

Sebbene w3 noti che 404 viene utilizzato quando non è applicabile nessun'altra risposta , non sarebbe questa la risposta 204 (senza contenuto)? La richiesta era valida da un punto di vista dell'elaborazione e il server ha elaborato la richiesta e ha un risultato. Questo è un successo, che tende verso le risposte 2xx. Non c'era alcun contenuto per questa particolare richiesta quindi 204 dice all'utente che non c'era niente di sbagliato nella loro query ma non c'è niente lì.

Potresti anche creare un caso debole in cui 409 (Conflitto) è una risposta appropriata. Anche se il 409 è più spesso usato per un POST, dice

The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.

probabilmente la non esistenza dell'id richiesto è il conflitto qui, e il ritorno nel messaggio che nessun id di questo tipo esiste nel sistema è abbastanza informazioni per l'utente da riconoscere e correggere il conflitto.

    
risposta data 23.03.2018 - 21:52
fonte
0

Le altre risposte lo coprono, ma volevo solo sottolineare che un errore di 500 serie significa "ho incasinato". In questo caso, "I" indica l'API, quindi un errore del server non gestito o simile. Un errore di 400 serie significa "hai incasinato" - il chiamante dell'API ha inviato qualcosa di sbagliato.

    
risposta data 25.03.2018 - 17:47
fonte
-4

Gli altri utenti hanno fornito risposte valide su cosa fare se vuoi andare sul libro.

Tuttavia ti suggerisco di leggere troppo l'RESTfulness e di essere assolutamente kosher rispetto ad esso.

REST è un protocollo capriccioso, perché se si vuole seguire il libro mentre lo si usa, costringe sia il client che il server a essere costruiti avendo una conoscenza specifica del fatto che stanno comunicando tramite REST, quindi in sostanza lo specifico il protocollo di comunicazione utilizzato non può essere sottratto.

Esiste un approccio diverso: evita completamente RESTfulness e usalo solo come protocollo di comunicazione e nient'altro. Ciò significa che le uniche risposte che devono essere restituite sono "HTTP 200 OK" e "HTTP 500 Internal Server Error" perché per quanto riguarda il protocollo di comunicazione, qualsiasi tentativo di comunicare può avere solo due risultati: o la richiesta è stata eseguita correttamente consegnato al server, oppure no.

Cosa succede dopo la consegna, non è uno degli affari del protocollo di comunicazione. Quindi, una volta che il server ha ricevuto correttamente la richiesta e inizia l'elaborazione, possono verificarsi molti errori, ma si tratta di errori specifici dell'applicazione che nessuno degli affari del protocollo di comunicazione è in grado di conoscere. Dovrebbero essere comunicati all'interno del carico utile di una risposta che sembra perfettamente riuscita per quanto riguarda il protocollo di comunicazione.

Quindi, la linea di fondo è, mi sento di raccomandare di restituire un "HTTP 200 OK" e all'interno del payload della risposta ("corpo del contenuto della risposta" in gergo HTTP) hanno un codice di errore specifico dell'applicazione che dice "ID non trovato" o qualsiasi altra cosa .

    
risposta data 25.03.2018 - 09:58
fonte

Leggi altre domande sui tag