Conception d'API RESTful. Que dois-je retourner s'il n'y a pas de lignes?

50

Je suis en train de coder une API pour un réseau social avec le Slim Framework. Ma question est la suivante: quelles sont les meilleures pratiques lorsqu'il n'y a aucune ligne à renvoyer dans la structure json?

Disons que cet appel / v1 / get / movies renvoie 2 lignes à partir des noms de film de la table:

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

Mais alors j'appelle / v1 / get / books et il n'y a aucune ligne dans cette table. Devrais-je simplement renvoyer une structure vide?

[
]

... ou serait-ce mieux un message et un code d'erreur?

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

Quelle est la meilleure pratique? (l'API sera utilisée dans les applications iOS et Android) Merci!

Andres SK
la source
3
Pour moi, cela ressemble à la question de savoir si zéro est en réalité un montant.
scarfridge
16
Votre exemple est cassé. Vous ne pouvez pas avoir d'objets JSON avec des clés dupliquées. Ce que vous cherchez, c'est un tableau[{"name": "..."}, {"name":"..."}]
Martin Wickman,
@ MartinWickman Désolé pour cela, je viens de le réparer.
Andres SK
8
@ Andufo, en fait, vous ne l'avez pas fait ...
mercredi
25
Si votre application est censée être RESTful, pourquoi le verbe / la méthode "obtenir" fait-il partie de votre URI de point final?
user50849

Réponses:

46

Habituellement, je retournerais le nombre d'enregistrements dans le résultat sous forme de métadonnées. Je ne suis pas sûr que ce soit la pratique REST normale, mais ce ne sont pas beaucoup de données supplémentaires, et elles sont très précises. Il y a généralement une pagination pour de nombreux services, il est donc impossible de renvoyer d'énormes résultats à la fois. Personnellement, je suis ennuyé quand il y a une pagination pour de petits ensembles de résultats. S'il est vide, retourne number_of_records : 0et réserve en liste / tableau vide books : [].

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

EDIT (quelques années plus tard): La réponse de Martin Wickman est bien meilleure, voici une explication "courte".

Lors de la pagination, gardez toujours à l'esprit la possibilité de changer le contenu ou l'ordre. Comme si, la première demande arrive, 24 résultats, vous revenez en premier 10. Après cela, "nouveau livre" est inséré et vous avez maintenant 25 résultats, mais avec la demande initiale, il serait commandé à la 10ème place. Lorsque le premier utilisateur demande la 2e page, il ne recevra pas le "nouveau livre". Il existe des moyens de gérer de tels problèmes, comme fournir "l'identifiant de la requête" qui devrait être envoyé avec les appels d'API suivants, puis renvoyer la page suivante de "l'ancien" jeu de résultats, qui devrait être stocké d'une manière ou d'une autre et lié à un "identifiant de la requête". Une alternative consiste à ajouter un champ du type "liste de résultats modifiée depuis la première demande".

Généralement, si vous le pouvez, essayez de faire un effort supplémentaire et évitez la pagination. La pagination est un état supplémentaire qui peut être muté et le suivi de tels changements est sujet à des erreurs, d'autant plus que le serveur et le client doivent le gérer.

Si vous avez trop de données à traiter en même temps , envisagez de renvoyer "liste d'id" avec tous les résultats et détails d'une partie de cette liste, et fournissez des appels d'API multi_get / get_by_id_list pour la ressource.

grizwako
la source
1
Euh, je me demande pourquoi celui-ci n'est pas voté aussi fortement que l'autre. J'aime plus cela, car cela donne à la fois une liste vide (supposée être une liste, non?) Que vous pouvez parcourir aveuglément sans conditions spéciales, mais les métadonnées sont également considérées comme un moyen de dire: "Non, nous n'avons pas". t glissez une erreur pour vous, il y avait en fait 0 résultats ".
Izkata
1
-1 car le booksparamètre est un objet mais 'books' implique plus d'un et plus d'un implique un tableau. Les métadonnées sont cool et à peu près tout, au final, je m'attendrais à ce qu'une collection de livres soit un tableau d'objets book; s'il n'y a pas de livres, donnez-moi le tableau vide
Charles Sprayberry
9
Le problème avec ceci est que l'ajout de "number_of_records" ne fournit plus d'informations, il ajoute simplement de la redondance et augmente la complexité. Pour signaler une erreur, renvoyez un code http approprié + quelque chose dans le corps.
Martin Wickman
1
@cspray books est une liste, comme le fait remarquer Izkata, ma faute de frappe.
Grizwako
2
@ MartinWickman Je ne voulais pas polluer la réponse originale avec des métadonnées supplémentaires, mais d'après mon expérience, de nombreux services ne renvoient pas toutes les données immédiatement, mais de manière "paginée".
Grizwako
105

Votre exemple est cassé. Vous ne devriez pas avoir d'objets JSON avec des clés en double. Ce que vous recherchez est un tableau avec des objets de film, comme ceci:

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

Cette approche répond également à votre question. Vous devriez retourner un tableau vide lorsque la requête ne correspond pas:

[]

D'autre part, si vous essayez d'obtenir une ressource de film spécifique avec un GET api/movie/34film qui n'existe pas, renvoyez 404 avec un message d'erreur approprié (codé JSON) dans le corps.

Martin Wickman
la source
1
+1 Ceci est valide JSON selon json_xs.
l0b0
15

S'il s'agit de JSON, vous devriez vraiment envisager de renvoyer un tableau d'objets. Cela présente de nombreux avantages, notamment que lorsque vous n’avez pas d’enregistrements, il s’agit d’un tableau vide.

Donc, quand vous avez des disques, vous revenez:

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

Et quand vous n'avez pas de disques, vous reviendriez:

    [

    ]
Devdatta Tengshe
la source
14

Si vous exécutez l'opération avec succès, mais qu'elle n'a rien à renvoyer, telle qu'une carte {}ou un tableau vide, []je préférerais répondre avec le code de réponse 204, voici un extrait de la définition de code d'état HTTP spec:

Le serveur a répondu à la demande mais n'a pas besoin de renvoyer un corps d'entité et peut vouloir renvoyer des métainformations mises à jour. La réponse PEUT inclure des métainformations nouvelles ou mises à jour sous la forme d'en-têtes d'entité, qui, le cas échéant, DEVRAIENT être associées à la variante demandée.

Si le client est un agent d'utilisateur, il NE DEVRAIT PAS changer sa vue de document par rapport à celle qui a provoqué l'envoi de la demande. Cette réponse est principalement destinée à permettre la saisie d'actions sans provoquer de modification de la vue de document active de l'agent d'utilisateur, bien que toute métainformation nouvelle ou mise à jour DEVRAIT être appliquée au document actuellement dans la vue active de l'agent de l'utilisateur.

La réponse 204 NE DOIT PAS inclure de corps de message et est donc toujours terminée par la première ligne vide après les champs d'en-tête.

Pour l’essentiel, je recommande d’utiliser 204 dans les applications RESTful sur HTTP quand il n’ya rien à retourner.

David Sergey
la source
4
Je suis d'accord avec le commentaire de @ avakar sur une autre réponse ici. Si le client tente d'accéder à / v1 / get / movies / 1, il devrait renvoyer 404 s'il n'y a pas de films identifiables par 1. Juste / v1 / get / movies devrait renvoyer 200 même s'il n'y a pas de film. Mais 204 ne convient pas car il est destiné aux actions d'entrée.
imel96
7
Un autre problème de cette solution est qu’elle nécessite généralement un code spécial dans le client: si la réponse est une liste vide, elle peut être analysée en tant que JSON, tout comme une réponse normale. Si la réponse est un corps vide, l'analyseur JSON se plaindra probablement (car un document vide n'est pas un JSON valide). Par conséquent, le client a besoin de code supplémentaire pour rechercher HTTP 204 et ignorer l'analyse.
Sleske
7
Je pense que ceci est une interprétation erronée de l’intention de 204. 204 ne semble pas être destiné à des opérations qui attendaient un contenu et n’en a pas trouvé, mais plutôt à des opérations qui ont abouti et n’ont pas de retour prévu . De Wikipedia: "Le serveur a traité avec succès la demande, mais ne renvoie aucun contenu. Habituellement utilisé comme réponse à une demande de suppression réussie."
XML
10

Un travail raisonnable a été accompli pour créer un format d’API JSON normalisé .

Suivre les principes de cette spécification signifie que toutes les ressources retournées doivent être effectivement des "collections" (même lorsqu'une seule ressource est incluse). Après cela, votre appel à /v1/get/moviesrevenir:

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

Votre appel à /v1/get/books(qui renvoie zéro ressource) renverrait:

{
    "books": []
}
Tim Blair
la source
5

Pour votre exemple spécifique, je recommanderais que / v1 / get / books renvoie HTTP 200 avec un tableau vide.

Si je lis votre message correctement, votre API a l'intention de collecter des livres. Métaphoriquement, vous avez une bibliothèque pour les livres, un DVD pour les films et peut-être d'autres récipients que vous n'avez pas mentionnés ici. Parce que vous avez l'intention de collecter des livres, / v1 / get / books est votre étagère. Cela signifie qu'il existe une ressource valide, une liste de livres, qui se trouve être vide dans votre exemple spécifique.

La raison pour laquelle je ne suggère pas de renvoyer HTTP 404 dans ce cas est que l'étagère est toujours là. Il n'y a pas de livres là-dessus pour le moment, mais c'est toujours une bibliothèque. S'il n'y avait pas une bibliothèque -si l'API n'a pas l' intention de livres collectons, par exemple- alors HTTP 404 serait appropriée. Mais comme il existe une ressource, vous ne devriez pas signaler qu’il n’en existe pas, contrairement à HTTP 404. Par conséquent, je soutiens que 200 avec un tableau vide (signifiant la collection) est plus approprié.

La raison pour laquelle je ne suggère pas de renvoyer HTTP 204 est que cela suggérerait que "Aucun contenu" est la situation habituelle: effectuer cette action sur cette ressource ne renverrait normalement rien. C'est pourquoi il est généralement utilisé comme réponse aux demandes DELETE, par exemple: la nature de la suppression signifie généralement qu'il ne reste rien à retourner. Le cas est similaire lorsqu'il est utilisé pour répondre à des demandes avec la famille d'en-têtes If-Modified: vous ne vouliez du contenu que si la ressource avait changé, mais ce n'est pas le cas, donc je ne vous en donnerai pas.

Mais je soutiens que HTTP 204 n'a pas de sens pour obtenir une collection vide mais valide. S'il y avait des éléments dans la collection, la représentation appropriée serait un tableau de ces données. Par conséquent, lorsqu'il n'y a pas de données (mais que la collection est valide), la représentation appropriée est un tableau vide.

Le Spooniest
la source
5

Vous ne devriez vraiment faire qu'une des deux choses

Renvoyer un 200 (OK)code d'état et un tableau vide dans le corps.

Ou Renvoyer un 204 (NO CONTENT)code d'état et NO corps de réponse.

Pour moi, l'option 2 semble plus techniquement correcte et conforme aux principes REST et HTTP.

Cependant, l'option 1 semble plus efficace pour le client - car le client n'a pas besoin de logique supplémentaire pour différencier deux codes d'état (de succès). Comme il sait qu'il recevra toujours un tableau, il lui suffira de vérifier s'il n'en a reçu aucun, un ou plusieurs éléments et de le traiter correctement.

Vihung
la source
3

J'ai vu les deux cas dans des environnements de production. Le choix que vous choisissez dépend de qui utilisera l'API. S'ils veulent savoir pourquoi la liste est vide ou pour être sûr que la liste est vraiment vide et qu'aucune erreur ne s'est produite lors de l'extraction, vous devez alors attacher un objet "erreurs". S'ils s'en moquent, retournez une liste vide. J'irais avec une deuxième approche car elle couvre plus de besoins que la première.

devnull
la source
3

La première chose à considérer, dans la mesure où vous construisez une API RESTful, est de renvoyer un code de réponse approprié. Et le code de réponse le plus approprié pour indiquer que la demande a été traitée normalement, mais la ressource demandée n'est pas disponible pour le moment est le vénérable 404.

Si vous concevez votre API de telle sorte qu'elle renvoie toujours un code de réponse sensible, vous n'aurez peut-être même pas besoin de renvoyer un corps lorsque la ressource n'a pas été trouvée. Cela dit, rendre un corps, en particulier un corps lisible par l'homme, ne peut pas nuire.

Il n'y a pas de "meilleure pratique" ici, vos deux exemples sont arbitraires, choisissez-en un et soyez cohérent . Les développeurs détestent les surprises, si les /v1/get/moviesretours reviennent {}lorsqu'il n'y a pas de films, nous nous attendons /v1/get/actorségalement à revenir {}lorsqu'il n'y a pas d'acteurs.

Yannis
la source
1
Rendre une 404 est vraiment la bonne chose à faire, mais malheureusement personne ne le fait vraiment - moi-même.
RibaldEddie
1
Si vous avez des réponses complexes et que seules certaines parties sont vides, renvoyer un 404 déroutera l'utilisateur.
devnull
5
Je ne suis pas d'accord avec le message 404. Je devrais interpréter 404 comme "la ressource n'existe pas" et me demander si quelque chose ne va pas avec mon URL ou quoi que ce soit. Si je demande une liste de films et que je reçois un 404, je penserais qu’il n’ya pas de ressource film. Un "204 Pas de contenu" peut être plus approprié.
Thorsten Müller
8
Ok, le "pas de corps" le tuerait. Mais: "La classe de code de statut 4xx est destinée aux cas dans lesquels le client semble avoir commis une erreur.". Mais il n'y avait pas d'erreur du côté client. Donc, un 404 donne une mauvaise information. Envoyez 204 sans corps ou dites que tout va bien et envoyez une liste vide.
Thorsten Müller
9
Vous demandez une liste de livres; si vous retournez 404, cela signifie que la liste n'existe pas, pas qu'elle est vide. Retourner 200 avec une liste vide me semble la seule option raisonnable.
avril
1

Je ne pense pas que la bonne réponse soit celle qui est marquée.

La réponse fournie par nirth devrait être la meilleure, dans un véritable scénario REST. Le corps de la réponse doit être vide et le code de statut http: 204; la ressource existe mais elle n'a "pas de contenu" à ce moment-là: est vide.

REST HTTP_Status_Codes

jmmtcarvalho
la source
1

Je recommande 200 + tableau vide, car cela simplifie la gestion par tous les clients de l'API. 200 + tableau signifie "j'ai renvoyé toutes les données présentes". Que ce soit pour le code fournissant les données ou pour le code traitant, le nombre d'éléments serait sans importance.

Tous les autres codes d'état doivent être correctement documentés et livrés correctement par le serveur, puis correctement traités par le client, et nous savons tous quelle est la probabilité que cela se produise.

Il a été suggéré de retourner le statut 204 + le corps vide. Cela signifie que vous forcez chaque seul client à l' état de processus 204 correctement. De plus, vous les forcez à gérer les réponses non-JSON! J'espère que tout le monde comprendra que le simple fait qu'une demande obtienne une réponse ne signifie pas que la réponse provient du serveur lorsque http est utilisé. Il suffit simplement de vérifier que la réponse est JSON pour gérer nombre de ces cas.

gnasher729
la source
0

Je voudrais "ça dépend".

Si zéro est un résultat raisonnable, retournez la liste vide. Par exemple, si vous voulez obtenir tous les employés appelés "bob", où "aucun" est un résultat tout à fait raisonnable. Si ce n'est pas un résultat attendu, renvoyer une erreur. Par exemple, obtenir une liste historique des adresses des rues d'une personne que vous employez. Elles doivent vivre quelque part , aucun résultat n'est donc probablement une erreur, pas seulement une condition normale.

Je suis sûr que vous pouvez discuter des détails de mon exemple, mais vous voyez l'idée ...

JohnB
la source
0
  • Tout d'abord, avoir getdans votre URL n'est pas RESTful, GET est impliqué par la méthode HTTP.
  • Si vous demandez une collection, GET api/moviesretournez par exemple 200 OKavec un tableau vide [].
  • Si vous demandez un film spécifique tel que GET api/movies/1(où 1est l'identifiant) et qu'il n'existe pas, renvoyez un 404 Not Found.

Pourquoi? Vous demandez des ressources . Lorsque vous demandez la collection, la ressource elle-même (la collection) existe. Par conséquent, a 404est faux. Mais si vous demandez un film spécifique et qu'il n'existe pas, la ressource demandée n'existe pas et vous devez renvoyer un 404.

Félixfbecker
la source
-2

Si vous renvoyez du JSON, il est préférable de toujours renvoyer nombre et message d'erreur et peut-être un booléen indiquant s'il y a une erreur ou non, ce sont mes trois méta-valeurs standard renvoyées avec chaque liste de lignes.

sino
la source