Progettazione API RESTful. Cosa devo restituire se non ci sono righe?


50

Attualmente sto codificando un'API per un social network con Slim Framework. La mia domanda è: quali sono le migliori pratiche quando non ci sono righe da restituire nella struttura json?

Diciamo che questa chiamata / v1 / get / movies restituisce 2 righe dai nomi dei film da tavolo:

[
    {"name": "Ghostbusters"},
    {"name": "Indiana Jones"}
]

Ma poi chiamo / v1 / get / books e non ci sono righe in quella tabella. Devo semplicemente restituire una struttura vuota?

[
]

... o sarebbe meglio un messaggio e un codice di errore?

[
    "errors": {
        "message": "no matches found",
        "code": 134
    }
]

Qual è una pratica migliore? (l'API verrà utilizzata nelle app iOS e Android) Grazie!


3
Per me questa sembra la domanda se lo zero sia effettivamente un importo.
scarfridge,

16
Il tuo esempio è rotto. Non puoi avere oggetti json con chiavi duplicate. Quello che stai cercando è un array, ovvero[{"name": "..."}, {"name":"..."}]
Martin Wickman,

@MartinWickman Mi dispiace, l'ho appena risolto.
Andres SK,

8
@andufo, in realtà, non hai ...
avakar

25
Se l'applicazione deve essere RESTful, allora perché il verbo / metodo "ottiene" una parte dell'URI dell'endpoint?
user50849

Risposte:


46

Di solito restituirei il numero di record come risultato in metadati. Non sono sicuro che si tratti della normale pratica REST, ma non contiene molti dati extra ed è molto preciso. Di solito c'è impaginazione per molti servizi, non è pratico restituire enormi set di risultati contemporaneamente. Personalmente sono infastidito quando c'è impaginazione per piccoli insiemi di risultati .. Se è vuoto, torna number_of_records : 0e prenota come lista / matrice vuota books : [].

{
    meta: {
        number_of_records : 2,
        records_per_page : 10,
        page : 0
    },
    books : [
        {id:1},
        {id:27}
    ]
}

EDIT (pochi anni dopo): la risposta di Martin Wickman è molto meglio, qui è "breve" di spiegazione del perché.

Quando si affronta l'impaginazione, tenere sempre presente la possibilità di contenuti o di cambiare l'ordine. Ad esempio, arriva la prima richiesta, 24 risultati, si restituisce il primo 10. Successivamente, viene inserito "nuovo libro" e ora si ottengono 25 risultati, ma con la richiesta originale verrebbe ordinato al 10 ° posto. Quando il primo utente richiede la seconda pagina, non riceverà "nuovo libro". Esistono modi per gestire tali problemi, come fornire "ID richiesta" che deve essere inviato con le seguenti chiamate API, quindi restituire la pagina successiva dal set di risultati "vecchio", che dovrebbe essere archiviato in qualche modo e legato a "ID richiesta". In alternativa è possibile aggiungere un campo come "Elenco risultati modificato dalla prima richiesta".

In generale, se puoi, prova a fare uno sforzo extra ed evitare l'impaginazione. L'impaginazione è uno stato aggiuntivo che può essere mutato e il monitoraggio di tali modifiche è soggetto a errori, ancor più perché sia ​​il server che il client devono gestirlo.

Se hai troppi dati da elaborare contemporaneamente , prendi in considerazione la possibilità di restituire "elenco ID" con tutti i risultati e i dettagli per alcuni pezzi di tale elenco e fornire chiamate API multi_get / get_by_id_list per la risorsa.


1
Eh, mi chiedo perché questo non sia votato così tanto come l'altro. Mi piace di più in quanto fornisce sia un elenco vuoto (che doveva essere un elenco, giusto?) Che puoi ripetere ciecamente senza condizioni speciali, ma anche i metadati contano come un modo di dire: "No, non abbiamo fatto" t gloss su un errore per te, in realtà ci sono stati 0 risultati ".
Izkata,

1
-1 perché il booksparametro è un oggetto ma "libri" implica più di uno e più di uno implica un array. I metadati sono fantastici e alla fine mi aspetto che una raccolta di libri sia una serie di oggetti; se non ci sono libri, dammi la matrice vuota
Charles Sprayberry,

9
Il problema è che l'aggiunta di "number_of_records" non fornisce ulteriori informazioni, aggiunge semplicemente ridondanza e aumenta la complessità. Per segnalare un errore, restituisci un codice http adatto + qualcosa nel corpo.
Martin Wickman,

1
@cspray books è un elenco, come ha indicato Izkata, il mio errore di battitura.
grizwako,

2
@MartinWickman Non volevo inquinare la risposta originale con metadati extra, ma nella mia esperienza, molti servizi non restituiscono immediatamente tutti i dati, ma in modo "impaginato".
grizwako,

105

Il tuo esempio è rotto. Non dovresti avere oggetti json con chiavi duplicate. Quello che stai cercando è un array con oggetti film, come questo:

 [
    {"name": "movie1"}, 
    {"name": "movie2"}
 ]

Questo approccio risponde anche alla tua domanda. È necessario restituire un array vuoto quando la query non corrisponde:

[]

D'altra parte, se si tenta di ottenere una risorsa film specifica con GET api/movie/34e quel film non esiste, quindi restituire 404 con un messaggio di errore (codificato json) adatto nel corpo


1
+1 Questo è JSON valido secondo json_xs.
l0b0

15

Se questo è JSON, dovresti davvero considerare di restituire una matrice di oggetti. Questo ha molti vantaggi incluso che quando non hai record è un array vuoto.

Quindi, quando hai i record, tornerai:

    [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]

E quando non hai alcun record, torneresti:

    [

    ]

14

Se esegui l'operazione correttamente, ma non ha nulla da restituire, come una mappa vuota {}o un array vuoto [], preferirei rispondere con un codice di risposta 204, ecco un estratto della specifica delle definizioni del codice di stato HTTP :

Il server ha soddisfatto la richiesta ma non è necessario restituire un corpo-entità e potrebbe voler restituire metainformazioni aggiornate. La risposta può includere metainformazioni nuove o aggiornate sotto forma di intestazioni di entità, che se presenti DOVREBBE essere associate alla variante richiesta.

Se il client è un agente utente, NON DOVREBBE cambiare la sua vista del documento da quella che ha causato l'invio della richiesta. Questa risposta ha principalmente lo scopo di consentire l'immissione di azioni senza provocare una modifica alla vista del documento attivo dell'agente utente, sebbene qualsiasi metainformazione nuova o aggiornata DOVREBBE essere applicata al documento attualmente nella vista attiva dell'agente utente.

La risposta 204 NON DEVE includere un corpo di messaggio e quindi viene sempre terminata dalla prima riga vuota dopo i campi di intestazione.

In sostanza, consiglio di usare 204 in applicazioni RESTful su HTTP quando non c'è nulla da restituire.


4
Sono d'accordo con il commento di @ avakar su un'altra risposta qui. Se il client sta provando ad accedere a / v1 / get / movies / 1, dovrebbe restituire 404 se non ci sono film identificabili per 1. Solo / v1 / get / films dovrebbe restituire 200 anche se non c'è film. Ma 204 non è adatto perché è destinato ad azioni di input.
imel96,

7
Un altro problema con questa soluzione è che in genere avrà bisogno di un codice speciale nel client: se la risposta è un elenco vuoto, può essere analizzata come JSON proprio come una normale risposta. Se la risposta è un corpo vuoto, il parser JSON probabilmente si lamenterà (perché un documento emtpy non è JSON valido), quindi il client ha bisogno di un codice aggiuntivo per verificare la presenza di HTTP 204 e saltare l'analisi.
sleske,

7
Credo che si tratti di una lettura errata dell'intenzione di 204. 204 sembra non essere inteso per operazioni che prevedevano contenuti e non sono riusciti a trovarne, ma piuttosto per operazioni che hanno avuto successo e non hanno un ritorno previsto . Da Wikipedia: "Il server ha elaborato correttamente la richiesta, ma non sta restituendo alcun contenuto. Di solito utilizzato come risposta a una richiesta di eliminazione riuscita."
XML

10

La creazione di un formato API JSON standard è stata eseguita in modo ragionevole .

Seguire i principi di tale specifica significa che tutte le risorse restituite dovrebbero essere effettivamente "raccolte" (anche quando è inclusa una sola risorsa). In seguito ciò significherebbe che la chiamata a /v1/get/moviesrestituirà:

{
    "movies": [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]
}

La tua chiamata a /v1/get/books(che restituisce zero risorse) restituirà:

{
    "books": []
}

5

Per il tuo esempio specifico, consiglierei che / v1 / get / books restituisca HTTP 200 con un array vuoto.

Se sto leggendo bene il tuo post, la tua API intende raccogliere libri. Metaforicamente parlando, hai uno scaffale per libri, un lettore DVD per film e forse altri contenitori che non hai menzionato qui. Poiché hai intenzione di collezionare libri, / v1 / get / books è la tua libreria. Ciò significa che c'è una risorsa valida lì -un elenco di libri- che sembra essere vuoto nel tuo esempio specifico.

Il motivo per cui non suggerisco di restituire HTTP 404 in questo caso è che lo scaffale è ancora lì. Non ci sono libri al momento, ma è ancora uno scaffale. Se non fosse uno scaffale, ad esempio se l'API non intendeva raccogliere libri, allora HTTP 404 sarebbe appropriato. Ma poiché c'è una risorsa lì, non dovresti segnalare che non ce n'è una, cosa che HTTP 404 fa. Pertanto, sostengo che 200 con un array vuoto (che significa la raccolta) è più appropriato.

Il motivo per cui non suggerisco di restituire HTTP 204 è che ciò suggerirebbe che "Nessun contenuto" è la situazione ordinaria: eseguire questa azione su questa risorsa normalmente non restituirebbe nulla. Ecco perché di solito viene utilizzato come risposta alle richieste DELETE, ad esempio: la natura dell'eliminazione generalmente significa che non è rimasto nulla da restituire. Il caso è simile quando viene utilizzato per rispondere alle richieste con la famiglia di intestazioni If-Modified: volevi contenuti solo se la risorsa fosse cambiata, ma non è così, quindi non ti darò alcun contenuto.

Ma sostengo che per OTTENERE una raccolta vuota ma valida, HTTP 204 non ha senso. Se nella raccolta fossero presenti elementi, la rappresentazione corretta sarebbe una matrice di tali dati. Pertanto, quando non vi sono dati lì (ma la raccolta è valida), la rappresentazione corretta è un array vuoto.


5

Dovresti davvero fare solo una delle due cose

Restituisce un 200 (OK)codice di stato e un array vuoto nel corpo.

Oppure Restituire un 204 (NO CONTENT)codice di stato e NESSUN corpo di risposta.

Per me, l'opzione 2 sembra più tecnicamente corretta e in linea con i principi REST e HTTP.

Tuttavia, l'opzione 1 sembra più efficiente per il client, poiché il client non ha bisogno di ulteriore logica per distinguere tra due codici di stato (di successo). Poiché sa che riceverà sempre un array, deve semplicemente verificare se non ha ricevuto nessuno, uno o molti elementi ed elaborarlo in modo appropriato


3

Ho visto entrambi i casi in ambienti di produzione. Quale scegli dipende da chi utilizzerà l'API. Se vogliono sapere perché l'elenco è vuoto o essere sicuri che l'elenco sia davvero vuoto e che non si siano verificati errori durante il recupero, è necessario allegare un oggetto "errori". Se non gli interessa, procedi con la restituzione di un elenco vuoto. Andrei con il secondo approccio poiché copre più esigenze del primo.


3

La prima cosa da considerare, poiché stai creando un'API RESTful, è di restituire un codice di risposta appropriato. E il codice di risposta più appropriato per comunicare che la richiesta è passata normalmente, ma la risorsa richiesta non è disponibile al momento è il venerabile 404.

Se si progetta l'API in modo tale da restituire sempre un codice di risposta ragionevole, potrebbe non essere necessario restituire un corpo quando la risorsa non è stata trovata. Detto questo, restituire un corpo, specialmente umanamente leggibile, non può far male.

Non ci sono "buone pratiche" qui, entrambi i tuoi esempi sono arbitrari, basta sceglierne uno ed essere coerenti . Gli sviluppatori odiano le sorprese, se /v1/get/moviesritorna {}quando non ci sono film, ci aspetteremmo /v1/get/actorsdi tornare anche {}quando non ci sono attori.


1
Restituire un 404 è davvero la cosa giusta da fare, ma purtroppo nessuno lo fa davvero, me compreso.
RibaldEddie

1
se hai risposte complesse e solo alcune di esse sono vuote, restituire un 404 confonderà l'utente.
Devnull

5
Non sarei d'accordo con il messaggio 404. A 404 interpreterei come "la risorsa non esiste" e mi preoccuperei se ho sbagliato qualcosa con il mio URL o altro. Se chiedessi un elenco di film e ottengo un 404, penserei che non ci sia affatto una risorsa cinematografica. Un "204 Nessun contenuto" potrebbe essere più appropriato.
Thorsten Müller,

8
Ok, la cosa "nessun corpo" lo ucciderebbe. Ma: "La classe 4xx del codice di stato è intesa per i casi in cui il client sembra aver sbagliato.". Ma non si è verificato alcun errore sul lato client. Quindi un 404 fornisce informazioni errate. O inviare 204 senza un corpo o dire che è ok e inviare un elenco vuoto.
Thorsten Müller,

9
Stai chiedendo un elenco di libri, restituendo 404 significherebbe che l'elenco non esiste, non che è vuoto. Restituire 200 insieme a un elenco vuoto mi sembra l'unica opzione ragionevole.
avakar,

1

Non credo che la risposta esatta sia quella contrassegnata.

La risposta fornita da Nirth dovrebbe essere la migliore, in un vero scenario REST. La risposta del corpo deve essere vuota e il codice di stato http: 204; la risorsa esiste ma non ha "nessun contenuto" in quel momento: è vuota.

REST HTTP_Status_Codes


1

Raccomando 200 + array vuoto, poiché semplifica la gestione da parte di tutti i client dell'API. 200 + array significa "Ho restituito tutti i dati presenti". Sia per il codice che consegna i dati sia per il codice che li elabora, il numero di articoli sarebbe irrilevante.

Ogni altro codice di stato deve essere adeguatamente documentato e consegnato correttamente dal server ed elaborato correttamente dal client, e sappiamo tutti quanto è probabile che ciò accada.

È stato suggerito di restituire lo stato 204 + corpo vuoto. Ciò significa che costringi ogni singolo client a elaborare correttamente lo stato 204. Inoltre li costringi a gestire risposte non JSON! Spero che tutti si rendano conto che solo perché una richiesta ha ottenuto una risposta, ciò non significa che la risposta sia arrivata dal server quando si utilizza http e solo un controllo del fatto che la risposta sia JSON gestisce molti di questi casi.


0

Vorrei "Dipende".

Se zero è un risultato ragionevole, restituisce l'elenco vuoto. Ad esempio, se vuoi ottenere tutti i dipendenti chiamati "bob" dove "none" è un risultato abbastanza ragionevole. Se non è un risultato previsto, restituire un errore. Ad esempio ottenere un elenco storico di indirizzi stradali per una persona che impieghi. Devono vivere da qualche parte, quindi nessun risultato è probabilmente un errore, non solo una condizione normale.

Sono sicuro che puoi discutere con i dettagli del mio esempio, ma hai l'idea ...


0
  • Prima di tutto, avere getnel tuo URL non è RESTful, GET è implicito nel metodo HTTP.
  • Se stai richiedendo una raccolta come GET api/moviesrestituisci a 200 OKcon un array vuoto [].
  • Se stai richiedendo un film specifico come GET api/movies/1(dove si 1trova l'id) e non esiste, restituisci a 404 Not Found.

Perché? Stai richiedendo risorse . Quando si richiede la raccolta, esiste la risorsa stessa (la raccolta). Pertanto, a 404è sbagliato. Ma se richiedi un film specifico e non esiste, la risorsa richiesta non esiste e devi restituire a 404.


-2

Se stai restituendo JSON, è meglio restituire sempre il conteggio e il messaggio di errore e forse un valore booleano che indica se c'è un errore o no, ovvero i miei tre meta valori standard restituiti con ogni elenco di righe.

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.