Quel est le code de réponse REST approprié pour une demande valide mais des données vides?

332

Par exemple, vous exécutez une demande GET users/9mais il n'y a aucun utilisateur avec l'ID # 9. Quel est le meilleur code de réponse?

  • 200 OK
  • 202 Accepté
  • 204 Aucun contenu
  • 400 Mauvaise demande
  • 404 introuvable
IMB
la source
19
Astuce: Avez-vous trouvé l'utilisateur 9?
Chris Pfohl
42
Astuce 2: l'utilisateur 9 n'a donc pas été trouvé ?
Tomasz Nurkiewicz
18
@IMB qui dit 204? "Pas de contenu" indique que l'entité que vous recherchez existe, mais n'a aucune représentation. Par exemple, si le blog avec l'ID 15 n'a aucun commentaire et que vous ne voulez pas renvoyer une liste vide pour les commentaires du blog numéro 15: "/ blog / 15 / comments" renverrait NoContent. D'un autre côté, si le blog 15 existe, «404 Not Found» est plus approprié.
Chris Pfohl
12
@Crisfole ne voulait pas dire ". D'un autre côté, si le blog 15 n'existe pas ," 404 Not Found "est plus approprié"
gdoron soutient Monica
15
J'ai très certainement fait @gdoron! :) Merci. Malheureusement, je suis environ trois ans trop tard pour modifier cela et corriger.
Chris Pfohl

Réponses:

249

TL; DR: Utiliser 404

Voir ce blog . Cela l'explique très bien.

Résumé des commentaires du blog sur 204:

  1. 204 No Content n'est pas terriblement utile comme code de réponse pour un navigateur (bien que selon la spécification HTTP, les navigateurs doivent le comprendre comme un code de réponse «ne changez pas la vue»).
  2. 204 No Content est cependant très utile pour les services Web ajax qui peuvent vouloir indiquer le succès sans avoir à retourner quelque chose. (Surtout dans les cas comme DELETEou ceux POSTqui ne nécessitent pas de commentaires).

La réponse à votre question est donc à utiliser 404dans votre cas. 204est un code de réponse spécialisé que vous ne devriez pas souvent retourner à un navigateur en réponse à un GET.

Les autres codes de réponse encore moins appropriés que 204et 404:

  1. 200devrait être retourné avec le corps de tout ce que vous avez récupéré avec succès. Ne convient pas lorsque l'entité que vous récupérez n'existe pas.
  2. 202est utilisé lorsque le serveur a commencé à travailler sur un objet mais que l'objet n'est pas encore complètement prêt. Certainement pas le cas ici. Vous n'avez pas commencé ni ne commencerez la construction de l'utilisateur 9 en réponse à une GETdemande. Cela enfreint toutes sortes de règles.
  3. 400est utilisé en réponse à une requête HTTP mal formatée (par exemple en-têtes HTTP mal formés, segments mal ordonnés, etc.). Cela sera presque certainement géré par le cadre que vous utilisez. Vous ne devriez pas avoir à gérer cela à moins que vous n'écriviez votre propre serveur à partir de zéro. Modifier : les RFC plus récents permettent désormais d'utiliser 400 pour les demandes sémantiquement invalides.

La description de Wikipedia des codes d'état HTTP est particulièrement utile. Vous pouvez également voir les définitions dans le document HTTP / 1.1 RFC2616 sur www.w3.org

Chris Pfohl
la source
8
Remarque: les codes de réponse dans les années 200 indiquent le succès. Les codes de réponse dans les 400 indiquent un échec. Le résumé, les points un et deux, concerne le 204code de réponse (sans contenu).
Chris Pfohl
227
-1 car je m'oppose trop fermement au 404 en réponse à un appel réussi qui n'a aucun enregistrement à renvoyer. En tant que développeur traitant d'une API pour une application non Web, j'ai perdu des heures à contacter les développeurs de l'API pour découvrir pourquoi le point de terminaison d'API que j'appelais n'existait pas, alors qu'en fait, il n'avait tout simplement pas données à déclarer. En ce qui concerne un 204 qui n'est pas particulièrement utile à un navigateur, c'est un peu comme la queue qui remue le chien, car la plupart des utilisations des points de terminaison API dans notre univers d'appareils intelligents ne sont pas basées sur un navigateur et celles qui utilisent probablement AJAX. Désolé de retirer des points.
Matt Cashatt
38
@MatthewPatrickCashatt vous êtes libre de voter comme bon vous semble. Je comprends enfin pourquoi les gens me déprécient, mais la justification est toujours erronée. Lorsque vous recevez un 404, cela ne signifie pas que l'itinéraire n'a pas de sens, cela signifie qu'il n'y a aucune ressource à cet endroit. Arrêt complet. Cela est vrai si vous demandez /badurlou /user/9lorsqu'un tel utilisateur n'existe pas. Un développeur peut vous aider en ajoutant une meilleure raison que «Introuvable», mais ce n'est pas obligatoire.
Chris Pfohl
19
@Crisfole Je suis enclin à être en désaccord (mais pas à voter, continuez à lire), basé sur la définition W3 de 404 , en particulier The server has not found anything matching the Request-URI. Le serveur Web / d'application a en fait trouvé une ACTION correspondant à l'URI de demande, mais pas le serveur DB. Cependant, il dit également This status code is commonly used when [...] no other response is applicable, donc je pense que cela valide un peu son utilisation (même si je ne suis pas d'accord avec / comme ça).
Daevin
8
Je ne pense pas que vous abordiez le point que je soulève: un 404 est dangereusement déroutant. Compter un appelant pour vérifier une phrase de raison ou le corps de la réponse signifie que vous ne faites pas confiance au code d'état, auquel cas il n'est pas utile.
Adrian Baker
364

Je m'oppose fermement à 404 en faveur de 204 ou 200 avec des données vides. Ou au moins on devrait utiliser une entité de réponse avec le 404.

La demande a été reçue et correctement traitée - elle a déclenché le code d'application sur le serveur, donc on ne peut pas vraiment dire que c'était une erreur client et donc toute la classe des codes d'erreur client (4xx) ne convient pas.

Plus important encore, 404 peut se produire pour un certain nombre de raisons techniques. Par exemple, l'application étant temporairement désactivée ou désinstallée sur le serveur, des problèmes de connexion proxy et ainsi de suite. Par conséquent, le client ne peut pas faire la distinction entre un 404 qui signifie «jeu de résultats vide» et un 404 qui signifie «le service est introuvable, réessayez plus tard».

Cela peut être fatal: imaginez un service de comptabilité dans votre entreprise qui répertorie tous les employés qui sont dus à une prime annuelle. Malheureusement, la seule fois où il est appelé, il renvoie un 404. Cela signifie-t-il que personne n'est dû pour un bonus, ou que l'application est actuellement en panne pour un nouveau déploiement?

-> Pour les applications qui se soucient de la qualité de leurs données, 404 sans entité de réponse est donc à peu près un no-go.

De plus, de nombreux frameworks clients répondent à un 404 en lançant une exception sans qu'aucune autre question ne soit posée. Cela oblige le développeur client à intercepter cette exception, à l'évaluer, puis à décider en fonction de cela s'il faut l'enregistrer comme une erreur détectée par exemple par un composant de surveillance ou s'il doit l'ignorer. Cela ne me semble pas joli non plus.

L'avantage de 404 sur 204 est qu'il peut renvoyer une entité de réponse qui peut contenir des informations sur la raison pour laquelle la ressource demandée n'a pas été trouvée. Mais si cela est vraiment pertinent, alors on peut également envisager d'utiliser une réponse 200 OK et de concevoir le système de manière à permettre des réponses d'erreur dans les données de charge utile. Alternativement, on pourrait utiliser la charge utile de la réponse 404 pour renvoyer des informations structurées à l'appelant. S'il reçoit par exemple une page html au lieu de XML ou JSON qu'il peut analyser, alors c'est un bon indicateur que quelque chose de technique a mal tourné au lieu d'une réponse "sans résultat" qui peut être valide du point de vue de l'appelant. Ou on pourrait utiliser un en-tête de réponse HTTP pour cela.

Je préférerais quand même un 204 ou 200 avec une réponse vide. De cette façon, l'état de l'exécution technique de la demande est séparé du résultat logique de la demande. 2xx signifie "exécution technique ok, c'est le résultat, faites-le".

Je pense que dans la plupart des cas, il devrait être laissé au client de décider si un résultat vide est acceptable ou non. En renvoyant le 404 sans entité de réponse malgré une exécution technique correcte, le client peut décider de considérer les cas comme des erreurs qui ne sont tout simplement pas des erreurs.

Une autre analogie rapide: renvoyer 404 pour "aucun résultat trouvé" revient à lancer une exception DatabaseConnectionException si une requête SQL n'a renvoyé aucun résultat. Il peut faire le travail, mais il existe de nombreuses causes techniques possibles qui déclenchent la même exception qui serait alors confondue avec un résultat valide.

Jens Wurm
la source
30
Les raisons techniques d'un «non trouvé» sont également appelées erreurs de serveur. Ceux-ci devraient être dans les 500s. Plus précisément: "Le service est introuvable" est 503 Service Unavailable.
Chris Pfohl
43
Le demandeur posait également des questions sur une ressource spécifique: un seul utilisateur (pas l' /usersitinéraire, mais /users/9, c'est-à-dire "l'utilisateur connu sous le nom de # 9"), donc votre comparaison "d'ensemble de résultats vide" n'a pas de sens. 404 signifie que l'objet n'existe pas.
Chris Pfohl
29
404 indique simplement que la ressource demandée (dans ce cas, l'utilisateur numéro 9) n'a pas été trouvée. Cela n'a rien à voir avec le déclenchement ou non du code d'application, cela n'a rien à voir avec la réponse ou non d'une application backend. Un serveur Web était le sujet de la question, il n'y avait aucune mention de proxy inverse dans la question.
Chris Pfohl
29
Le raisonnement de cette réponse est terriblement faux.
Kurt Spindler
21
404: le client a pu communiquer avec un serveur donné, mais le serveur n'a pas pu trouver ce qui était demandé. Littéralement: demande reçue, elle était correcte et correctement formatée (mauvaise demande 400), elle était authentifiée ou publique (non autorisée 401 / interdite 403), aucun paiement nécessaire (paiement requis 402), la méthode de demande était correcte (méthode non autorisée 405 ), la demande d'acceptation peut être satisfaite (non acceptable 406). 200 Ok doit être utilisé lorsque l'utilisateur obtient la ressource. Vide n'est pas une ressource. La plage 400 correspond aux erreurs du client La plage 400 correspond aux erreurs du serveur En bref: votre raisonnement est désactivé
Derk-Jan
62

Au début, je pensais qu'un 204 aurait du sens, mais après les discussions, je pense que le 404 est la seule vraie réponse correcte. Tenez compte des données suivantes:

Utilisateurs: John, Peter

METHOD  URL                      STATUS  RESPONSE
GET     /users                   200     [John, Peter]
GET     /users/john              200     John
GET     /users/kyle              404     Not found
GET     /users?name=kyle`        200     []
DELETE  /users/john              204     No Content

Quelques antécédents:

  1. la recherche renvoie un tableau, il n'a simplement pas de correspondance mais il a du contenu: un tableau vide .

  2. 404 est bien sûr surtout connu pour les URL qui ne sont pas prises en charge par le serveur demandé, mais une ressource manquante est en fait la même.
    Même s'il /users/:nameest associé à users/kyle, l'utilisateur Kyle n'est pas une ressource disponible, donc un 404 s'applique toujours. Ce n'est pas une requête de recherche, c'est une référence directe par une URL dynamique , donc 404 c'est le cas.

Quoi qu'il en soit, mes deux cents :)

Justus Romijn
la source
9
Jeter mon poids derrière ce style pour une API REST. Aucun client ne devrait demander / users / kyle à moins qu'on lui dise que la ressource existerait via un appel à / users ou / users? Name = kyle
Gary Barker
@GaryBarker Mais comme il s'agit en quelque sorte d'une "entrée utilisateur", l'API doit encore la gérer correctement. Bien que vous devriez empêcher le 404 dans VOTRE client, vous ne pouvez pas être certain qu'il a été vérifié en premier lieu. La conception de l'API doit être effectuée sans tenir compte de la mise en œuvre exacte de votre client, en particulier en termes de saisie utilisateur vérifiée.
RicoBrassers
C'est la réponse avec laquelle je suis le plus d'accord. Exemple parfait de la façon dont je souhaite que les API fonctionnent. @ Le commentaire de GaryBarker est parfait aussi. C'est une erreur lorsque vous recherchez quelque chose par ID et qu'il n'existe pas. Vous devez savoir que l'ID existe avant de passer l'appel. Principalement parce que l'obtention d'une réponse vide «réussie» ne fait que lancer l'erreur plus loin, probablement à certains «ne peut pas lire le nom de la propriété non définie» lors de la création de user.name ou quelque chose.
Jamie Twells
Qu'en est-il d'une combinaison des deux. En supposant que les utilisateurs ont des amis. / users / kyle / friends? name = fred. Kyle n'existe pas, alors cette réponse serait-elle 404? Ou serait-ce 200 parce que nous ne nous soucions pas exactement de Kyle, nous nous soucions seulement de chercher ses amis avec le nom de Fred?
JSextonn
OMI qui donnerait un 404, car il s'agit d'une demande invalide: Kyle n'existe pas, donc la recherche de ses amis n'est pas possible non plus.
Justus Romijn
23

Si l'on s'attend à ce que la ressource existe, mais qu'elle soit vide, je dirais qu'il pourrait être plus facile d'obtenir simplement un 200 OK avec une représentation qui indique que la chose est vide.

Je préfère donc que / things renvoie 200 OK avec {"Items": []} plutôt que 204 avec rien du tout, car de cette façon, une collection avec 0 éléments peut être traitée de la même manière qu'une collection avec un ou plus d'article en elle.

Je laisserais simplement le 204 Pas de contenu pour les PUT et DELETE, où il se pourrait qu'il n'y ait vraiment aucune représentation utile.

Dans le cas où / chose / 9 n'existe pas vraiment, un 404 est approprié.

j0057
la source
1
Il semble que vous préfériez programmer contre une API en utilisant un formulaire plus abstrait appelé RPC. Plutôt que d'accéder aux ressources en suivant de près les verbes et une URL basée sur les ressources comme customers/1/addressbook, la façon RPC est d'appeler un point de terminaison comme GetCustomerAddressBooket de recevoir les données ou essentiellement nulles et de ne pas avoir à se soucier autant des complexités de HTTP. Il y a des avantages et des inconvénients pour les deux.
The Muffin Man
2
@The Muffin Man, je ne sais pas comment vous pouvez prétendre savoir si je préfère REST ou RPC, ni pourquoi cela est pertinent pour une discussion sur le code d'état à retourner à une demande HTTP GET.
j0057
J'ai eu d'horribles problèmes de mise en cache lors de l'utilisation de 204. Chrome traiterait étrangement la demande et n'afficherait rien sur le réseau et mettrait en cache le résultat précédent. Même avec tous les en-têtes sans cache dans le monde. Je suis d'accord avec cette réponse, 200 semble être le meilleur avec un tableau / objet vide transmis à l'utilisateur.
Jack
22

Dans les projets précédents, j'ai utilisé 404. S'il n'y a pas d'utilisateur 9, alors l'objet n'a pas été trouvé. Par conséquent, 404 Not Found est approprié.

Pour l'objet existe, mais il n'y a pas de données, 204 Aucun contenu ne serait approprié. Je pense que dans votre cas, l'objet n'existe pas .

Max
la source
14

Selon w3 post,

200 OK

La demande a abouti. Les informations renvoyées avec la réponse dépendent de la méthode utilisée dans la demande

202 Accepté

La demande a été acceptée pour traitement, mais le traitement n'est pas terminé.

204 Aucun contenu

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.

400 Mauvaise demande

La demande n'a pas pu être comprise par le serveur en raison d'une syntaxe incorrecte. Le client NE DEVRAIT PAS répéter la demande sans modifications

401 non autorisé

La demande nécessite une authentification utilisateur. La réponse DOIT inclure un champ d'en-tête WWW-Authenticate

404 introuvable

Le serveur n'a rien trouvé correspondant à l'URI de demande. Aucune indication n'est donnée quant à savoir si la condition est temporaire ou permanente

JustCode
la source
La publication w3 concerne les codes d'état HTTP. HTTP n'est pas identique à REST. REST utilise principalement mais pas nécessairement HTTP comme protocole de transport. 404 est un code d'erreur de transport HTTP. Si REST serait identique à HTTP, ne devrait-il pas être appelé HTTP?
anneb
1
@anneb Comme vous l'avez dit, REST utilise HTTP, donc cette réponse est totalement logique. REST n'est pas HTTP, REST n'est pas un protocole de toute façon. REST n'a pas besoin d'être identique (ou identique à HTTP) pour que cette réponse ne soit pas logique.
Koray Tugay
@Koray Tugay: la recherche google utilise également http, donc selon cette réponse la recherche google devrait répondre au statut http 404 si rien ne correspond à la recherche?
anneb
@anneb La recherche Google mentionne-t-elle une application RESTful? Je ne pense pas. Par conséquent, la réponse sera non. Revenons à la question d'origine et à cette réponse au lieu de tomber dans un terrier de lapin. Si Google Search crée un jour une API RESTful (ou peut-être déjà, je ne sais pas), elle peut revenir 204 No Contentlorsqu'elle ne trouve aucun résultat. Non 404, il a un résultat pour vous, mais il n'a pas de contenu ..
Koray Tugay
13

Pour résumer ou simplifier,

2xx: données facultatives: URI bien formé: les critères ne font pas partie de l'URI: si les critères sont facultatifs, ils peuvent être spécifiés dans @RequestBody et @RequestParam devraient conduire à 2xx. Exemple: filtrer par nom / statut

4xx: Données attendues: URI mal formé: Les critères font partie de l'URI: Si les critères sont obligatoires qui ne peuvent être spécifiés que dans @PathVariable, cela devrait conduire à 4xx. Exemple: recherche par identifiant unique.

Ainsi pour la situation demandée: "utilisateurs / 9" serait 4xx (éventuellement 404) Mais pour "utilisateurs? Nom = superman" devrait être 2xx (éventuellement 204)

Ashish Singh
la source
12

Il y a deux questions posées. Un dans le titre et un dans l'exemple. Je pense que cela a conduit en partie à des controverses sur la réponse appropriée.

Le titre de la question concerne les données vides. Les données vides sont toujours des données mais ne sont pas identiques à aucune donnée. Cela suggère donc de demander un ensemble de résultats, c'est-à-dire une liste, peut-être à partir de /users. Si une liste est vide, c'est toujours une liste, donc un 204 (sans contenu) est le plus approprié. Vous venez de demander une liste d'utilisateurs et vous en avez fourni une, il se trouve qu'il n'y a pas de contenu.

L'exemple fourni demande au lieu d'un objet spécifique, un utilisateur, /users/9. Si l'utilisateur # 9 n'est pas trouvé, aucun objet utilisateur n'est renvoyé. Vous avez demandé une ressource spécifique (un objet utilisateur) et vous ne l'avez pas reçue car elle n'a pas été trouvée, un 404 est donc approprié.

Je pense que la façon de résoudre ce problème est de savoir si vous pouvez utiliser la réponse de la manière attendue sans ajouter de déclaration conditionnelle, puis utiliser un 204 sinon utiliser un 404.

Dans mes exemples, je peux parcourir une liste vide sans vérifier s'il contient du contenu, mais je ne peux pas afficher les données d'objet utilisateur sur un objet nul sans casser quelque chose ou ajouter une vérification pour voir s'il est nul.

Vous pouvez bien sûr renvoyer un objet en utilisant le modèle d'objet nul si cela convient à vos besoins mais c'est une discussion pour un autre thread.

Boite bleue
la source
9

Après avoir cherché en question, vous ne devriez pas utiliser 404pourquoi?

Sur la base de la RFC 7231, le code d'état correct est204

Dans les réponses ci-dessus, j'ai remarqué 1 petit malentendu:

1.- la ressource est: /users

2.- /users/8n'est pas la ressource, c'est: la ressource /usersavec le paramètre route 8, le consommateur peut ne pas le remarquer et ne connaît pas la différence, mais l'éditeur le sait et doit le savoir! ... donc il doit retourner une réponse précise pour les consommateurs. période.

alors:

La RFC: 404 est incorrecte car les ressources /userssont trouvées, mais la logique exécutée à l'aide du paramètre 8n'a trouvé aucune contentréponse à renvoyer, donc la bonne réponse est:204

Le point principal ici est: 404même la ressource n'a pas été trouvée pour traiter la logique interne

204est un: j'ai trouvé la ressource, la logique a été exécutée mais je n'ai trouvé aucune donnée en utilisant vos critères donnés dans le paramètre route donc je ne peux rien vous renvoyer. Désolé, vérifiez vos critères et appelez-moi à nouveau.

200: ok j'ai trouvé la ressource, la logique a été exécutée (même si je ne suis pas obligé de retourner quoi que ce soit) prenez cela et utilisez-le à votre guise.

205: (la meilleure option d'une réponse GET) J'ai trouvé la ressource, la logique a été exécutée, j'ai du contenu pour vous, utilisez-le bien, oh au fait si vous allez partager cela dans une vue, veuillez rafraîchir la vue pour affichez-le.

J'espère que ça aide.

rodfraga
la source
8

Ce que les réponses existantes ne développent pas, c'est que cela fait une différence que vous utilisiez des paramètres de chemin ou des paramètres de requête.

  • Dans le cas des paramètres de chemin, le paramètre fait partie du chemin de ressource. Dans ce cas /users/9, la réponse doit être 404due au fait que cette ressource n'a pas été trouvée. /users/9est la ressource, et le résultat est unaire, ou une erreur, il n'existe pas. Ce n'est pas une monade.
  • En cas de paramètres de requête, le paramètre ne fait pas partie du chemin de ressource. Dans ce cas /users?id=9, la réponse doit être 204due au fait que la ressource a /usersété trouvée mais qu'elle n'a pu renvoyer aucune donnée. La ressource /usersexiste et le résultat est n-aire, elle existe même si elle est vide. Si idest unique, c'est une monade.

L'utilisation des paramètres de chemin ou des paramètres de requête dépend du cas d'utilisation. Je préfère les paramètres de chemin pour les arguments obligatoires, normatifs ou d'identification et les paramètres de requête pour les arguments facultatifs, non normatifs ou d'attribution (comme la pagination, les paramètres régionaux de classement et d'autres éléments). Dans une API REST, je n'utiliserais /users/9pas /users?id=9spécialement à cause de l'imbrication possible pour obtenir des "enregistrements enfants" comme /users/9/ssh-keys/0pour obtenir la première clé ssh publique ou /users/9/address/2pour obtenir la troisième adresse postale.

Je préfère utiliser 404. Voici pourquoi:

  • Les appels aux méthodes unaire (1 résultat) et n-aire (n résultats) ne doivent pas varier sans raison valable. J'aime avoir les mêmes codes de réponse si possible. Le nombre de résultats attendus est bien sûr une différence, disons, vous vous attendez à ce que le corps soit un objet (unaire) ou un tableau d'objets (n-aire).
  • Pour n-aire, je retournerais un tableau, et au cas où il n'y aurait pas de résultats, je ne retournerais aucun ensemble (pas de document), je retournerais un ensemble vide (document vide, comme un tableau vide en JSON ou un élément vide en XML ). Autrement dit, c'est toujours 200 mais avec aucun record. Il n'y a aucune raison de mettre cette information sur le fil autre que dans le corps.
  • 204c'est comme une voidméthode. Je ne l' utiliser pour GET, seulement POST, PUTet DELETE. Je fais une exception dans le cas GEToù les identificateurs sont des paramètres de requête et non des paramètres de chemin.
  • Ne pas trouver l'enregistrement est comme NoSuchElementException, ArrayIndexOutOfBoundsExceptionou quelque chose comme ça, causé par le client utilisant un identifiant qui n'existe pas, c'est donc une erreur du client.
  • Du point de vue du code, obtenir 204signifie une branche supplémentaire dans le code qui pourrait être évitée. Cela complique le code client, et dans certains cas, il complique également le code du serveur (selon que vous utilisez des monades d'entité / modèle ou des entités / modèles simples; et je recommande fortement de rester à l'écart des monades d'entité / modèle, cela peut conduire à des bugs désagréables où parce que de la monade, vous pensez qu'une opération a réussi et retournez 200 ou 204 alors que vous auriez dû retourner autre chose).
  • Le code client est plus facile à écrire et à comprendre si 2xx signifie que le serveur a fait ce que le client a demandé, et 4xx signifie que le serveur n'a pas fait ce que le client a demandé et que c'est la faute du client. Ne pas donner au client l'enregistrement que le client demandé par id est la faute du client, car le client a demandé un identifiant qui n'existe pas.

Dernier point mais non le moindre: la cohérence

  • GET /users/9
  • PUT /users/9 et DELETE /users/9

PUT /users/9et DELETE /users/9doivent déjà revenir 204en cas de mise à jour ou de suppression réussie. Alors, que devraient-ils retourner au cas où l'utilisateur 9 n'existerait pas? Cela n'a aucun sens de présenter la même situation sous la forme de codes d'état différents selon la méthode HTTP utilisée.

De plus, ce n'est pas une raison normative, mais culturelle: si 204est utilisé pour la GET /users/9prochaine chose qui se passera dans le projet, c'est que quelqu'un pense que le retour 204est bon pour les méthodes n-aires. Et cela complique le code client, car au lieu de simplement vérifier 2xxpuis décoder le corps, le client doit maintenant vérifier spécifiquement 204et, dans ce cas, ignorer le décodage du corps. Bud, que fait le client à la place? Créer un tableau vide? Pourquoi ne pas l'avoir sur le fil, alors? Si le client crée le tableau vide, 204 est une forme de compression stupide. Si le client utilise à la nullplace, une toute autre boîte de vers est ouverte.

Christian Hujer
la source
3

204 est plus approprié. Surtout lorsque vous avez un système d'alerte pour vous assurer que votre site Web est sécurisé, 404 dans ce cas serait source de confusion car vous ne savez pas que certaines alertes 404 sont des erreurs de backend ou des demandes normales mais une réponse vide.

刘武豪
la source
Vous ne devriez pas retourner 404 si vous avez une erreur de backend.
effroyable22
3

Je dirais que ni l'un ni l'autre n'est vraiment approprié. Comme cela a été dit - par exemple par @anneb, moi aussi, je pense qu'une partie des problèmes provient de l'utilisation d'un code de réponse HTTP pour transporter un état lié à un service RESTful. Tout ce que le service REST a à dire sur son propre traitement doit être transporté au moyen de codes spécifiques REST.

1

Je dirais que, si le serveur HTTP trouve un service prêt à répondre à une demande qui lui a été envoyée, il ne devrait pas répondre avec un HTTP 404 - au final, quelque chose a été trouvé par le serveur - sauf indication contraire explicite du service qui traite la demande.

Supposons que pour un moment l'adresse suivante: http://example.com/service/return/test.

  • Le cas A est que le serveur «recherche simplement le fichier sur le système de fichiers». S'il n'est pas présent, 404c'est correct. La même chose est vraie, si elle demande à une sorte de service de livrer exactement ce fichier et que ce service lui indique que rien de ce nom n'existe.
  • Dans le cas B, le serveur ne fonctionne pas avec de "vrais" fichiers mais en réalité la demande est traitée par un autre service - par exemple une sorte de système de template. Ici, le serveur ne peut faire aucune réclamation sur l'existence de la ressource car il n'en sait rien (sauf si le service qui la gère) le dit.

Sans aucune réponse du service nécessitant explicitement un comportement différent, le serveur HTTP ne peut dire que 3 choses:

  • 503 si le service censé gérer la demande ne s'exécute pas ou ne répond pas;
  • 200 sinon, le serveur HTTP peut réellement satisfaire la demande - peu importe ce que le service dira plus tard;
  • 400ou 404pour indiquer qu'il n'y a pas un tel service (par opposition à «existe mais hors ligne») et rien d'autre n'a été trouvé.

2

Pour revenir à la question actuelle: je pense que l'approche la plus propre serait de ne pas utiliser de code de réponse HTTP autre que celui indiqué précédemment. Si le service est présent et répond, le code HTTP doit être 200. La réponse doit contenir le statut renvoyé par le service dans un en-tête distinct - ici, le service peut dire

  • REST:EMPTYpar exemple, si on lui a demandé de rechercher qch. et que la recherche est revenue vide;
  • REST:NOT FOUNDsi on lui a demandé spécifiquement qc. «ID-like» - qu'il s'agisse d'un nom de fichier ou d'une ressource par ID ou entrée n ° 24, etc. - et que cette ressource spécifique n'a pas été trouvée (généralement, une ressource spécifique a été demandée et introuvable);
  • REST:INVALID si une partie de la demande, elle a été envoyée n'est pas reconnue par le service.

(notez que j'ai préfixé ceux-ci avec "REST:" pour marquer le fait que même si ceux-ci peuvent avoir les mêmes valeurs ou libellés que les codes de réponse HTTP, ils sont sth. complètement différents)

3

Revenons à l'URL ci-dessus et inspectons le cas B où le service indique au serveur HTTP qu'il ne gère pas lui-même cette demande mais la transmet SERVICE. HTTP ne sert que ce qui lui est rendu SERVICE, il ne sait rien de la return/testpartie car il est géré par SERVICE. Si ce service est en cours d'exécution, HTTP devrait retourner 200car il a effectivement trouvé quelque chose pour gérer la demande.

Le statut retourné par SERVICE(et qui, comme dit ci-dessus, aimerait voir dans un en-tête séparé) dépend de l'action réellement attendue:

  • if return/testdemande une ressource spécifique: si elle existe, renvoyez-la avec le statut REST:FOUND; si cette ressource n'existe pas, retournez REST:NOT FOUND; cela pourrait être prolongé pour revenir REST:GONEsi nous savons qu'il a déjà existé et ne reviendra pas, et REST:MOVEDsi nous savons qu'il a disparu à Hollywood
  • if return/testest considéré comme une opération de recherche ou de type filtre: si l'ensemble de résultats est vide, retourne un ensemble vide dans le type demandé et un état de REST:EMPTY; un ensemble de résultats dans le type demandé et un état deREST:SUCCESS
  • if return/testn'est pas une opération reconnue par SERVICE: return REST:ERRORsi elle est complètement fausse (par exemple une faute de frappe comme retrun/test), ou REST:NOT IMPLEMENTEDsi elle est prévue pour plus tard.

4

Cette distinction est beaucoup plus nette que de mélanger les deux choses différentes. Cela rendra également le débogage plus facile et le traitement un peu plus complexe, voire pas du tout.

  • Si un HTTP 404 est retourné, le serveur me dit: «Je ne sais pas de quoi vous parlez». Bien que la partie REST de ma demande soit parfaitement correcte, je recherche par'Mach dans tous les mauvais endroits.
  • D'un autre côté, HTTP 200 et REST: ERR me disent que j'ai obtenu le service mais que j'ai fait quelque chose de mal dans ma demande au service.
  • Depuis HTTP 200 et REST: VIDE, je sais que je n'ai rien fait de mal - bon serveur, le serveur a trouvé le service, bonne demande au service - mais le résultat de la recherche est vide.

Résumé

Le problème et la discussion proviennent du fait que les codes de réponse HTTP sont utilisés pour désigner l'état d'un service dont les résultats sont servis par HTTP, ou pour indiquer qc. cela ne fait pas partie du domaine du serveur HTTP lui-même. En raison de cet écart, la question ne peut pas être répondue et toutes les opinions font l'objet de nombreuses discussions.

L'état d'une demande traitée par un service et non par le serveur HTTP NE DEVRAIT VRAIMENT PAS (RFC 6919) être donné par un code de réponse HTTP. Le code HTTP DEVRAIT (RFC 2119) contenir uniquement des informations que le serveur HTTP peut fournir à partir de sa propre portée: à savoir, si le service a été trouvé pour traiter la demande ou non.

Au lieu de cela, une manière différente DEVRAIT être utilisée pour informer un consommateur de l'état de la demande au service qui traite réellement la demande. Ma proposition est de le faire via un en-tête spécifique. Idéalement, le nom de l'en-tête et son contenu suivent une norme qui permet aux consommateurs de travailler facilement avec ces réponses.

dariok
la source
2

Selon la RFC7231 - page59 ( https://tools.ietf.org/html/rfc7231#page-59 ) la définition de la réponse du code d'état 404 est:

6.5.4. 404 Introuvable Le code d'état 404 (Introuvable) indique que le serveur d'origine n'a pas trouvé de représentation actuelle pour la ressource cible ou n'est pas disposé à divulguer qu'elle existe. Un code de statut 404 n'indique pas si ce manque de représentation est temporaire ou permanent; le code d'état 410 (disparu) est préféré à 404 si le serveur d'origine sait, vraisemblablement par certains moyens configurables, que la condition est susceptible d'être permanente. Une réponse 404 peut être mise en cache par défaut; c'est-à-dire, sauf indication contraire par la définition de la méthode ou les contrôles de cache explicites (voir la section 4.2.2 de la [RFC7234]).

Et la principale chose qui suscite des doutes est la définition de la ressource dans le contexte ci-dessus. Selon le même RFC (7231), la définition de ressource est:

Ressources: la cible d'une requête HTTP est appelée "ressource". HTTP ne limite pas la nature d'une ressource; il définit simplement une interface qui pourrait être utilisée pour interagir avec les ressources. Chaque ressource est identifiée par un identificateur de ressource uniforme (URI), comme décrit dans la section 2.7 de la [RFC7230]. Lorsqu'un client crée un message de requête HTTP / 1.1, il envoie l'URI cible sous l'une des différentes formes, comme défini dans (Section 5.3 de [RFC7230]). Lorsqu'une demande est reçue, le serveur reconstruit un URI de demande efficace pour la ressource cible (Section 5.5 de [RFC7230]). L'un des objectifs de conception de HTTP est de séparer l'identification des ressources de la sémantique des demandes, ce qui est rendu possible par l'acquisition de la sémantique des demandes dans la méthode de demande (section 4) et de quelques champs d'en-tête modifiant la demande (section 5).

Donc, à mon sens, le code d'état 404 ne doit pas être utilisé sur une demande GET réussie avec un résultat vide (exemple: une liste sans résultat pour un filtre spécifique)

Filipe Moisés
la source
2

De telles choses peuvent être subjectives et il y a des arguments solides intéressants et variés des deux côtés. Cependant [à mon avis] renvoyer un 404 pour les données manquantes n'est pas correct . Voici une description simplifiée pour que cela soit clair:

  • Demande: puis-je avoir des données s'il vous plaît?
  • Ressource (point de terminaison API): je recevrai cette demande pour vous, ici [envoie une réponse de données potentielles]

Rien ne s'est cassé, le point de terminaison a été trouvé et la table et les colonnes ont été trouvées, de sorte que la base de données a été interrogée et que les données ont été "correctement" retournées!

Maintenant - peu importe que cette "réponse réussie" ait des données ou non, vous avez demandé une réponse de données "potentielles" et cette réponse avec des données "potentielles" a été satisfaite. Null, vide, etc. sont des données valides.

200 signifie simplement que la demande que nous avons faite a été acceptée. Je demande des données, rien ne s'est mal passé avec HTTP / REST, et comme les données (bien que vides) ont été renvoyées, ma "demande de données" a réussi.

Renvoyez 200 et laissez le demandeur gérer les données vides comme chaque scénario spécifique le justifie!

Considérez cet exemple:

  • Requête: requête "infractions" table avec ID utilisateur 1234
  • Ressource (point de terminaison API): renvoie une réponse mais les données sont vides

Ces données étant vides sont entièrement valides. Cela signifie que l'utilisateur n'a aucune infraction. Il s'agit d'un 200 car il est tout à fait valide, comme alors je peux le faire:

Vous n'avez aucune infraction, prenez un muffin aux myrtilles!

Si vous considérez cela comme un 404, que dites-vous? Les infractions de l'utilisateur sont introuvables? Maintenant, grammaticalement, c'est correct, mais ce n'est tout simplement pas correct dans le monde REST où le succès ou l'échec concerne la demande. Les données "d'infraction" pour cet utilisateur ont pu être trouvées avec succès, il n'y a aucune infraction - un nombre réel représentant un état valide.


[Note effrontée ..]

Dans votre titre, vous acceptez inconsciemment que 200 est la bonne réponse:

Quel est le code de réponse REST approprié pour une demande valide mais des données vides?


Voici quelques éléments à considérer lors du choix du code d'état à utiliser, indépendamment de la subjectivité et des choix délicats:

  1. Cohérence . Si vous utilisez 404 pour «aucune donnée», utilisez-le chaque fois qu'une réponse ne renvoie aucune donnée.
  2. N'utilisez pas le même statut pour plus d'une signification . Si vous renvoyez 404 lorsqu'une ressource n'a pas été trouvée (par exemple, le point de terminaison de l'API n'existe pas, etc.), ne l'utilisez pas également pour qu'aucune donnée ne soit retournée. Cela rend la gestion des réponses difficile.
  3. Examinez attentivement le contexte . Qu'est-ce que la "demande"? Que dites-vous que vous essayez de réaliser?
James
la source
1

Encodez le contenu de la réponse avec une énumération commune qui permet au client de l'activer et de forger la logique en conséquence. Je ne sais pas comment votre client distinguerait la différence entre un "data not found" 404 et un "web resource not found" 404? Vous ne voulez pas que quelqu'un accède à l'utilisateur Z / 9 et que le client s'étonne comme si la demande était valide, mais aucune donnée n'a été retournée.

Entrez
la source
1

Pourquoi ne pas utiliser 410? Cela suggère que la ressource demandée n'existe plus et que le client ne devrait jamais faire de demande pour cette ressource, dans votre cas users/9.

Vous pouvez trouver plus de détails sur 410 ici: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

Akshat
la source
2
«le client ne devrait jamais faire de demande» - et si cet utilisateur est créé plus tard, votre réponse suggère que vous pourriez garantir que cet utilisateur n'existera jamais, c'est une hypothèse très audacieuse et probablement fausse
Holly
Ce que Holly a dit. Pour ajouter à son point de vue: même si l'utilisateur existait et a été supprimé, 410 est faux, car que se passe-t-il si l'utilisateur est restauré? (Quel type de cas particulier est créé plus tard.)
Christian Hujer
parce que 410 devrait être une situation permanente. restapitutorial.com/httpstatuscodes.html
Akostha
1

Il est triste que quelque chose d'aussi simple et bien défini soit devenu "basé sur l'opinion" dans ce fil.

Un serveur HTTP ne connaît que les "entités", ce qui est une abstraction pour tout contenu, que ce soit une page Web statique, une liste de résultats de recherche, une liste d'autres entités, une description json de quelque chose, un fichier multimédia, etc.

Chacune de ces entités devrait être identifiable par une URL unique, par exemple

  • / user / 9 - une seule entité: un USER ID = 9
  • / users - une seule entité: une LISTE de tous les utilisateurs
  • /media/x.mp3 - une seule entité: un FICHIER multimédia appelé x.mp3
  • / search - une seule entité: un CONTENU dynamique basé sur des paramètres de requête

Si un serveur trouve une ressource par l'URL donnée, peu importe quel est son contenu - 2G de données, null, {}, [] - tant qu'elle existe, ce sera 200. Mais si une telle entité est inconnu du serveur, il est ATTENDU de retourner 404 "Introuvable".

Une confusion semble provenir des développeurs qui pensent que si l'application a un gestionnaire pour une certaine forme de chemin, cela ne devrait pas être une erreur. Aux yeux du protocole HTTP, peu importe ce qui s'est passé dans les internes du serveur (c'est-à-dire si le routeur par défaut a répondu ou un gestionnaire pour une forme de chemin spécifique), tant qu'il n'y a pas d'entité correspondante sur le serveur avec le URL demandée (qui a demandé un fichier MP3, une page Web, un objet utilisateur, etc.), qui retournerait un contenu valide (vide ou autre), elle doit être 404 (ou 410, etc.).

Un autre point de confusion semble concerner «aucune donnée» et «aucune entité». Le premier concerne le contenu d'une entité et le second, son existence.

Exemple 1:

  • Aucune donnée: / users renvoie 200 OK, corps: [] car personne ne s'est encore inscrit
  • Aucune entité: / users renvoie 404 car il n'y a pas de chemin / users

Exemple 2:

  • Aucune donnée: / utilisateur / 9 renvoie retour 200 OK, corps: {}, car l'ID utilisateur = 9 n'a jamais entré ses données personnelles
  • Aucune entité: / user / 9 renvoie 404 car il n'y a pas d'ID utilisateur = 9

Exemple 3:

  • Aucune donnée: / search? Name = Joe renvoie 200 OK [], car il n'y a pas de Joe dans la base de données
  • Aucune entité: / search? Name = Joe renvoie 404 car il n'y a pas de chemin / recherche
Darko Maksimovic
la source
0

404 serait très déroutant pour tout client si vous revenez simplement parce qu'il n'y a pas de données en réponse.

Pour moi, le code de réponse 200 avec un corps vide est suffisant pour comprendre que tout est parfait, mais il n'y a pas de données correspondant aux exigences.

énergie noire
la source
0

Selon Microsoft: types de retour d'action du contrôleur dans l'API Web ASP.NET Core , faites défiler presque vers le bas, vous trouverez le texte de présentation suivant environ 404 relatif à un objet introuvable dans la base de données. Ici, ils suggèrent qu'un 404 est approprié pour les données vides.

entrez la description de l'image ici

Bill Roberts
la source
0

Comme beaucoup le disent, 404 est trompeur et ne permet pas au client de discriminer si l'URI de demande n'existe pas ou si l'URI demandé ne peut pas récupérer la ressource demandée.

Le statut 200 devrait contenir des données sur les ressources - ce n'est donc pas le bon choix. Le statut 204 signifie autre chose et ne doit pas être utilisé comme réponse aux requêtes GET.

Tous les autres statuts existants ne sont pas applicables, pour une raison ou une autre.

J'ai vu ce sujet être débattu à plusieurs reprises à plusieurs endroits. Pour moi, il est douloureusement évident que pour éliminer la confusion autour du sujet, un statut de réussite dédié est nécessaire. Quelque chose comme " 209 - Aucune ressource à afficher".

Ce sera un état 2xx car ne pas trouver d'ID ne devrait pas être considéré comme une erreur client (si les clients savaient tout ce qui se trouve dans la base de données du serveur, ils n'auraient pas besoin de demander quoi que ce soit au serveur, n'est-ce pas?). Ce statut dédié résoudra tous les problèmes débattus avec l'utilisation d'autres statuts.

La seule question est: comment puis-je faire en sorte que RFC accepte cela comme standard?

Umberto Bar
la source