web-dev-qa-db-fra.com

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

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

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

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

Mais, alors j'appelle / v1/get/books et il n'y a pas de lignes dans cette table. Dois-je simplement retourner 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 iOS et Android) Merci!

52
Andres SK

Habituellement, je renvoie le nombre d'enregistrements en tant que métadonnées. Je ne sais pas si c'est normal REST pratique, mais ce ne sont pas beaucoup de données supplémentaires, et c'est très précis. Habituellement, il y a une pagination pour beaucoup de services, il n'est pas pratique de renvoyer un énorme jeu de résultats Personnellement, je suis ennuyé quand il y a une pagination pour les petits jeux de résultats .. S'il est vide, retournez number_of_records : 0 et les livres en tant que 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 "court" d'explication pourquoi.

Lors de la pagination, gardez toujours à l'esprit la possibilité de modifier le contenu ou la commande. Comme, la première demande vient, 24 résultats, vous retournez les 10 premiers. Après cela, "nouveau livre" est inséré et maintenant vous avez 25 résultats, mais avec la demande d'origine, il serait commandé à la 10ème place. Lorsque le premier utilisateur demande la 2e page, il ne reçoit pas de "nouveau livre". Il existe des moyens de gérer de tels problèmes, comme fournir un "ID de demande" 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é à "ID de demande". Une alternative consiste à ajouter un champ comme "la liste des résultats a changé 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 ces modifications est sujet aux erreurs, d'autant plus que le serveur et le client doivent le gérer.

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

47
grizwako

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

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

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

[]

D'un autre côté, si vous essayez d'obtenir une ressource de film spécifique avec GET api/movie/34 et ce film n'existe pas, puis retournez 404 avec un message d'erreur approprié (codé json) dans le corps

105
Martin Wickman

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

Donc, lorsque vous avez des enregistrements, vous renvoyez:

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

Et quand vous n'avez aucun dossier, vous retourneriez:

    [

    ]
15
Devdatta Tengshe

Si vous exécutez l'opération avec succès, mais qu'elle n'a rien à retourner, comme une carte vide {} ou tableau vide [] Je préférerais répondre avec 204 code de réponse, voici un extrait de Définitions du code d'état HTTP spec:

Le serveur a satisfait 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 une métainformation nouvelle ou mise à jour sous la forme d'en-têtes d'entité qui, s'ils sont présents, DEVRAIENT être associés à la variante demandée.

Si le client est un agent utilisateur, il NE DEVRAIT PAS changer sa vue de document de celle qui a provoqué l'envoi de la demande. Cette réponse est principalement destinée à permettre la saisie des actions sans effectuer de modification de la vue active du document de l'agent utilisateur, bien que toute métainformation nouvelle ou mise à jour DEVRAIT être appliquée au document actuellement dans la vue active de l'agent 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.

Essentiellement, je recommande d'utiliser 204 dans les applications RESTful sur HTTP lorsqu'il n'y a rien à retourner.

14
David Sergey

Il y a eu une quantité raisonnable de travail sur la création d'un format API JSON normalisé .

Le fait de suivre les principes de cette spécification signifie que toutes les ressources renvoyées doivent effectivement être des "collections" (même lorsqu'une seule ressource est incluse). Suivre cela signifierait que votre appel à /v1/get/movies retournerais:

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

Votre appel à /v1/get/books (qui ne renvoie aucune ressource) retournerait:

{
    "books": []
}
10
Tim Blair

Vous ne devriez vraiment faire qu'une ou deux choses

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

Ou Renvoyez un code d'état 204 (NO CONTENT) et AUCUN 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 réussite). Comme il sait qu'il recevra toujours un tableau, il doit simplement vérifier s'il n'a reçu aucun, un ou plusieurs éléments et le traiter de manière appropriée

5
Vihung

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

Si je lis bien votre message, votre API a l'intention de collecter des livres. Métaphoriquement parlant, vous avez une étagère pour les livres, un rack de DVD pour les films et peut-être d'autres conteneurs 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 retourner HTTP 404 dans ce cas est que la bibliothèque est toujours là. Il n'y a pas de livres pour le moment, mais c'est toujours une étagère. S'il ne s'agissait pas d'une bibliothèque - si l'API n'avait pas l'intention de collecter des livres, par exemple - alors HTTP 404 serait approprié. Mais parce qu'il y a une ressource là-bas, vous ne devriez pas signaler qu'il n'y en a pas, ce que fait 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 retourner HTTP 204 est que cela suggérerait que "Aucun contenu" est l'état des choses ordinaire: effectuer cette action sur cette ressource normalement ne retournerait 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 n'y a plus rien à retourner. Le cas est similaire lorsqu'il est utilisé pour répondre aux 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 donnerai aucun contenu.

Mais je soutiens que pour obtenir une collection vide mais valide, HTTP 204 n'a pas de sens. S'il y avait des éléments dans la collection, alors 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.

5
The Spooniest

La première chose à considérer, puisque vous créez une API RESTful, est de renvoyer un code de réponse approprié. Et le code de réponse le plus approprié pour communiquer que la demande s'est déroulé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 manière à ce 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 humainement lisible, ne peut pas faire de mal.

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 /v1/get/movies Retour {} quand il n'y a pas de films, nous nous attendons à ce que /v1/get/actors pour retourner également {} quand il n'y a pas d'acteurs.

3
yannis

J'ai vu les deux cas dans des environnements de production. Celui 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 sa récupération, vous devez alors attacher un objet "erreurs". S'ils s'en moquent, retournez une liste vide. J'irais avec la deuxième approche car elle couvre plus de besoins que la première.

3
devnull
  • Tout d'abord, avoir get dans votre URL n'est pas RESTful, GET est impliqué par la méthode HTTP.
  • Si vous demandez une collection comme GETapi/movies retourne un 200 OK avec un tableau vide [].
  • Si vous demandez un film spécifique comme GETapi/movies/1 (où 1 est l'identifiant) et il n'existe pas, renvoyez un 404 Not Found.

Pourquoi? Vous demandez ressources. Lorsque vous demandez la collection, la ressource elle-même (la collection) existe. À cet effet, un 404 est 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.

1
felixfbecker

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 qui s'y trouvent". Tant pour le code qui fournit les données que pour le code qui les traite, le nombre d'articles ne serait pas pertinent.

Tout autre code d'état doit être correctement documenté et correctement délivré par le serveur et correctement traité par le client, et nous savons tous à quel point cela est probable.

Il a été suggéré de retourner le statut 204 + corps vide. Cela signifie que vous forcez everysingle client à traiter correctement l'état 204. De plus, vous les forcez à gérer les réponses non JSON! J'espère que tout le monde se rend compte que juste parce qu'une demande a obtenu une réponse, cela ne signifie pas que la réponse est venue du serveur lorsque http est utilisé, et juste une vérification que la réponse est JSON gère bon nombre de ces cas.

1
gnasher729

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

La réponse fournie par nirth doit être la meilleure, dans un vrai REST. La réponse du corps doit être vide et le code d'état http: 204; la ressource existe mais elle n'a "aucun contenu" à ce moment: est vide.

REST HTTP_Status_Codes

1
jmmtcarvalho

Je dirais "Ça dépend".

Si zéro est un résultat raisonnable, renvoyez la liste vide. Par exemple, si vous souhaitez 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, retournez une erreur. Par exemple, obtenir une liste historique des adresses d'une personne que vous employez. Ils doivent vivre quelque part donc aucun résultat n'est probablement une erreur, pas seulement une condition normale.

Je suis sûr que vous pouvez contester les spécificités de mon exemple, mais vous avez l'idée ...

0
JohnB