web-dev-qa-db-fra.com

Quand utiliser le code d'état HTTP 404 dans une API

Je travaille sur un projet et après m'être disputé avec des gens au travail pendant plus d'une heure. J'ai décidé de savoir ce que les gens sur l'échange de pile pourraient dire.

Nous écrivons une API pour un système, il y a une requête qui devrait retourner un arbre d'organisation ou un arbre d'objectifs.

L'arbre d'organisation est l'organisation dans laquelle l'utilisateur est présent. En d'autres termes, cet arbre doit toujours exister. Dans l'organisation, un arbre de but doit toujours être présent. (c'est là que l'argument a commencé). Dans le cas où l'arborescence n'existe pas, mon collègue a décidé qu'il serait juste de répondre à la réponse avec le code d'état 200. Et puis a commencé à me demander de corriger mon code car l'application s'effondrait lorsqu'il n'y a pas d'arborescence.

J'essaierai d'épargner les flammes et la fureur.

J'ai suggéré de déclencher une erreur 404 lorsqu'il n'y a pas d'arbre. Cela me permettrait au moins de savoir que quelque chose ne va pas. Lorsque j'utilise 200, je dois ajouter une vérification spéciale à ma réponse dans le rappel de réussite pour gérer les erreurs. Je m'attends à recevoir un objet, mais je peux en fait recevoir une réponse vide car rien n'est trouvé. Il semble tout à fait juste de marquer la réponse comme un 404. Et puis la guerre a commencé et j'ai reçu le message que je ne comprenais pas le schéma du code d'état HTTP. Je suis donc ici et je demande ce qui ne va pas avec 404 dans ce cas? J'ai même eu l'argument "Il n'a trouvé rien, il est donc juste de retourner 200". Je pense que c'est faux car l'arbre doit toujours être présent. Si nous n'avons rien trouvé et que nous attendons quelque chose, ce devrait être un 404.

Plus d'informations,

J'ai oublié d'ajouter les URL récupérées.

Les organisations

/OrgTree/Get

Buts

/GoalTree/GetByDate?versionDate=...
/GoalTree/GetById?versionId=...

Mon erreur, les deux paramètres sont obligatoires. Si une versionDate qui peut être analysée à une date est fournie, elle renverra la révision de fermeture. Si vous entrez quelque chose dans le passé, il retournera la première révision. Si par ID avec un identifiant qui n'existe pas, je soupçonne que cela va retourner une réponse vide avec 200.

Supplémentaire

De plus, je pense que la meilleure réponse au problème est de créer des objets par défaut lors de la création d'organisations, le fait de ne pas avoir d'arbre ne devrait pas être un cas valide et devrait être considéré comme un comportement non défini. Il est impossible d'utiliser un compte sans les deux arbres. Pour ces raisons, ils doivent toujours être présents.

j'ai aussi lié ceci (un similaire mais je ne le trouve pas)

http://viswaug.files.wordpress.com/2008/11/http-headers-status1.png

62

En cas de doute, consultez la documentation . L'examen des définitions du W3C pour les codes d'état HTTP nous donne ceci:

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

404 Introuvable - Le serveur n'a rien trouvé correspondant à l'URI de demande.

Dans le contexte de votre API, cela dépend beaucoup de la façon dont les requêtes sont créées et comment les objets sont récupérés. Mais, mon interprétation a toujours été que:

  • Si je demande un objet particulier, et qu'il existe, retournez 200 code, s'il n'existe pas, renvoyez le bon 404 code.
  • Mais, si je demande un ensemble d'objets qui correspondent à une requête, un ensemble nul est une réponse valide et je veux qu'il soit renvoyé avec un 200 code. La raison en est que la requête était valide, qu'elle a réussi et que la requête n'a renvoyé rien.

Donc dans ce cas vous avez raison , le service ne recherche pas pour "une chose spécifique" c'est demander une chose particulière, si cette chose n'est pas trouvée, dites-le clairement.

Je pense que Wikipedia le met mieux:

200 OK - ... La réponse réelle dépendra de la méthode de demande utilisée. Dans une demande GET, la réponse contiendra une entité correspondant à la ressource demandée.

404 Introuvable - La ressource demandée est introuvable mais peut être à nouveau disponible à l'avenir. Les demandes ultérieures du client sont autorisées.

Cela me semble assez clair.

Concernant les exemples de demandes

/GoalTree/GetByDate?versionDate=...
/GoalTree/GetById?versionId=...

Pour le format, vous avez dit, vous renvoyez toujours la révision la plus proche à cette date. Il ne renverra jamais un objet, il devrait donc toujours renvoyer 200 OK. Même si cela pouvait prendre une plage de dates, et la logique était de retourner tous les objets dans ce délai en retournant 200 OK - 0 Les résultats sont corrects, car c'est ce à quoi la demande était destinée - l'ensemble des choses qui répondaient à ces critères.

Cependant, ce dernier est différent car vous demandez un objet spécifique, vraisemblablement unique, avec cette identité. Retour 200 OK dans ce cas est incorrect car la ressource demandée n'existe pas et est introuvable .

Concernant le choix des codes de statut

  • Codes 2xx Dites à un UA que il a fait la bonne chose, la demande a fonctionné. Il peut continuer à le faire à l'avenir.
  • Codes 3xx Dites à un UA ce que vous avez demandé fonctionnait probablement, mais cette chose est maintenant ailleurs. À l'avenir, l'UA pourrait envisager de simplement aller à la redirection.
  • Codes 4xx Dites à un UA il a fait quelque chose de mal, la requête qu'il a construite n'est pas correcte et ne devrait pas essayer à nouveau, sans au moins quelques modifications.
  • Codes 5xx Dites à un UA le serveur est en quelque sorte cassé. Mais bon, cette requête pourrait fonctionner à l'avenir, il n'y a donc aucune raison de ne pas la réessayer. (sauf pour 501, qui est plus un problème 400).

Vous avez mentionné dans un commentaire en utilisant un code 5xx, mais votre système fonctionne. On lui a demandé une requête qui ne fonctionne pas et doit la communiquer à l'UA. Peu importe comment vous le découpez, c'est le territoire 4xx.

Considérez un étranger interrogeant notre système solaire

Alien: Ordinateur, dites-moi s'il vous plaît toutes les planètes que les humains habitent.

Ordinateur: 1 résultat trouvé. Terre

Alien: Ordinateur, parlez-moi de Terre .

Ordinateur: Terre - en grande partie inoffensif.

Alien: Ordinateur, parlez-moi de toutes les planètes que les humains habitent, en dehors de la ceinture d'astéroïdes.

Ordinateur: 0 résultats trouvés.

Alien: Computer, s'il vous plaît détruire la Terre.

Ordinateur: 200 OK.

Alien: Ordinateur, parlez-moi de Terre .

Ordinateur: 404 - introuvable

Alien: Ordinateur, dites-moi s'il vous plaît toutes les planètes que les humains habitent.

Ordinateur: 0 résultats trouvés.

Alien: Victoire pour le puissant empire Irken!

85
user69037

En ignorant le fait que/GoalTree/Get * ressemble à un verbe, pas à des ressources, vous devez toujours renvoyer 200 car l'URI/GoalTree/Get * représente des ressources qui sont toujours disponibles pour l'accès et ce n'est pas une erreur client s'il n'y a pas d'arbre à la suite de une requête. Renvoyez simplement 200 avec un ensemble vide lorsqu'il n'y a aucune entité à renvoyer.

Vous utilisez 404 si la ressource n'est pas trouvée, pas lorsqu'il n'y a pas d'entité.

En d'autres termes, si vous souhaitez renvoyer 404 pour vos objets, donnez-leur leurs propres URI.

12
imel96

Il s'agit d'une question intéressante, car tout dépend des spécifications du système.

réponse d'imel96 m'a convaincu qu'un 404 ne serait pas une réponse appropriée, car la famille de codes 4xx est principalement destinée aux erreurs utilisateur/client , et ce n'en est pas un. L'URL est bien formée et l'arborescence doit être là; sinon, le système est dans un état incohérent!

Il s'agit donc d'une erreur de serveur , c'est-à-dire quelque chose dans la famille 5xx. Peut-être une erreur de serveur interne 500 générique ou un service 503 non disponible (le service étant "récupérez-moi l'arborescence qui doit être là").

8
Andres F.

Je dirais que un code de réponse 200 ou 404 peut être valide , selon la façon dont vous regardez la situation.

Le fait est que codes de réponse HTTP sont définis dans le contexte d'un serveur, qui peut fournir diverses ressources en fonction de leur URL . Dans ce contexte, la signification de 200 OK et 404 Not Found sont parfaitement sans ambiguïté: le premier dit "voici la ressource que vous avez demandée", tandis que le second dit "désolé, je n'ai pas de ressource comme ça".

Toutefois, dans votre situation, vous disposez d'une couche supplémentaire application entre le serveur HTTP et les ressources (arborescences) réelles qui sont demandées. L'application occupe une sorte d'espace intermédiaire qui n'est pas bien traité dans la spécification HTTP.

Du point de vue du serveur Web, l'application ressemble à en quelque sorte à une ressource: il s'agit généralement d'un fichier sur le serveur, identifié par (une partie de) l'URL, tout comme d'autres ressources (par exemple des fichiers statiques) le serveur pourrait servir. D'un autre côté, c'est une sorte de ressource étrange, car elle se compose de code exécutable qui détermine dynamiquement le contenu, et même potentiellement le code d'état, de la réponse, ce qui la fait se comporter à certains égards plus comme un mini-serveur.

En particulier, dans votre exemple, le serveur Web peut très bien localiser l'application, mais l'application ne parvient pas à localiser la sous-ressource (arborescence) qui a été demandée. Maintenant, si vous considérez que l'application est juste une extension du serveur et que le sous-élément (arbre) est la ressource réelle, alors un La réponse 404 est appropriée: le serveur a simplement délégué la tâche de trouver la ressource réelle à l'application, ce qu'il a échoué à faire.

D'un autre côté, si votre point de vue est que l'application est la ressource demandée, alors le serveur Web doit évidemment renvoyer un 200 réponses ; après tout, l'application a été trouvée et exécutée correctement. De toute évidence, dans ce cas, l'application doit en fait renvoyer un corps de réponse valide au format attendu, indiquant (en utilisant le protocole de niveau supérieur que le format code) qu'aucune donnée réelle correspondant à la requête n'a été trouvée.

Ces deux points de vue peuvent avoir un sens. Dans la plupart des cas , au moins pour les applications destinées à être directement accessibles via HTTP avec un navigateur Web ordinaire, je favoriser la vue précédente : l'utilisateur ne se soucie généralement pas des détails internes comme la différence entre le serveur et l'application, il se soucie simplement de savoir si les données qu'il souhaite sont là ou non.

Cependant, dans le cas spécifique d'une application conçue pour communiquer avec d'autres programmes informatiques à l'aide d'un protocole API de haut niveau personnalisé, en utilisant HTTP uniquement comme couche de transport de bas niveau , il y a un argument à faire en faveur de cette dernière vue : pour les clients qui interfacent avec une telle application, tout ce dont ils se soucient vraiment, = au niveau HTTP, c'est s'ils ont réussi à contacter l'application ou non. Dans de tels cas, tout le reste est souvent communiqué de façon plus naturelle à l'aide du protocole de niveau supérieur.


Dans tous les cas, quelle que soit la vue ci-dessus que vous préférez, il y a quelques détails que vous devez garder à l'esprit. La première est que, dans de nombreux cas, il peut y avoir une distinction significative entre une ressource (essentiellement) vide et une inexistant un.

Au niveau HTTP, une ressource vide serait simplement indiquée par un code de réponse 200 et un corps de réponse vide, tandis qu'une ressource inexistante serait indiquée par une réponse 404 et un corps de ressource expliquant l'absence de la ressource. Dans un protocole d'API de niveau supérieur, on indiquerait généralement une ressource inexistante par une réponse d'erreur, contenant un code/message d'erreur spécifique au protocole approprié, tandis qu'une réponse vide serait simplement une structure de réponse normale sans éléments de données.

(Notez qu'une ressource n'a pas besoin d'être littéralement zéro octet pour être "vide" dans le sens que je veux dire ci-dessus. Par exemple, un résultat de recherche sans éléments correspondants compterait comme vide au sens large, comme le ferait un résultat de requête SQL avec pas de lignes ou un document XML ne contenant aucune donnée réelle.)

De plus, bien sûr, si l'application croit vraiment que la sous-ressource demandée devrait être là, mais ne la trouve pas, alors un troisième code de réponse possible existe: 500 Internal Server Error. Une telle réponse a du sens si l'existence de la ressource est une condition préalable supposée pour l'application, de telle sorte que son absence indique nécessairement un dysfonctionnement interne.

Enfin, vous devriez toujours garder à l'esprit loi de Postel :

" Soyez prudent dans ce que vous envoyez et libéral dans ce que vous recevez."

Que le serveur devrait répondre dans une situation particulière avec une réponse 200 ou 404, qui n'excuse pas vous en tant qu'implémentateur client pour gérer l'une ou l'autre réponse de manière appropriée et de la manière maximise une interopérabilité robuste. Bien sûr, ce que signifie une manipulation "appropriée" dans différentes situations peut être discuté, mais cela ne devrait certainement pas inclure normalement un crash ou une "décomposition".

6
Ilmari Karonen

Si l'URL représente une ressource qui n'a jamais existé, retournez 404 Introuvable

Si l'URL représente une ressource qui est une liste vide, renvoyez une liste vide et 200 OK.

Exemple:

{
  total: 0,
  items: []
}

Si l'URL représente une ressource qui existait auparavant, retournez 410 Gone.

Concernant la boîte de dialogue de Lego Stormtrooper:

Alien: Computer, please tell me all planets that humans inhabit. GET /planets?inhabitedBy=humans

Computer: 200 OK. { total: 1, items:[{name:'Earth'}] }

Alien: Computer, please tell me about Earth. GET /planets/earth

Computer: 200 OK. {name:'Earth', status: 'Mostly Harmless'}

Alien: Computer, please tell me about all planets humans inhabit, outside the asteroid belt. GET /planets?inhabitedBy=humans&distanceFromSun=lots

Computer: 200 OK. {total:0, items:[] }

Alien: Computer, please destroy Earth. DELETE /planets/earth

Computer: 204 No Content. (or 202 Accepted if it takes some time to destroy Earth)

Alien: Computer, please tell me about Earth. GET /planets/earth

Computer: 410 Gone

Alien: Computer, please tell me all planets that humans inhabit. GET /planets?inhabitedBy=humans

Computer: 200 OK 0 {total: 0, items:[] }

Alien: Victory for the mighty Irken Empire!
3
Neil McGuigan

Que diriez-vous d'un 204 sans contenu? Il semblerait que votre demande a été traitée avec succès mais ne renvoie rien. C'est toujours un "succès" mais vous permet de voir si vous avez des résultats basés uniquement sur le code de statut.

3
modernserf

D'après le son, il s'agit d'une API pour interne utilisation. Cela donne à Edge l'utilisation du schéma qui donne le plus avantage, qu'il soit ou non standard (spécification). Cela ne signifie pas d'inventer complètement vos propres codes de statut, mais il est OK de `` plier '' un peu les règles si cela est bénéfique.

Je suis d'accord avec votre position que vous devriez obtenir un code d'état qui indique que quelque chose s'est mal passé. C'est après tout à cela que servent les codes d'état. Vous bénéficiez également des bibliothèques qui lèvent des exceptions/etc. sur un code de statut autre que 200, vous n'avez donc pas à vérifier explicitement (ou vous pouvez écrire votre propre wrapper qui fait cela).

Je suis également d'accord avec le point de vue d'Andres F. selon lequel 500 est approprié car l'arbre devrait exister. Dans la pratique cependant, j'aime diviser les erreurs de serveur en deux catégories. Quelque chose inattendu s'est mal passé et quelque chose que je peux pratiquement vérifier s'est mal passé. Il en résulte les codes d'état suivants,

  • 200 - Tout va bien
  • 404 - Mauvaise URL
  • 409 - Quelque chose a mal tourné
  • 500 - Une erreur inattendue s'est produite sur le serveur

Dans votre cas particulier, vous pouvez vérifier si l'arborescence existe ou non côté serveur et si elle n'est pas là, renvoyer un 409. C'est une erreur attendue (vous savez que cela peut arriver, vous pouvez le vérifier, etc.) . Le conflit 409 n'est que ma préférence personnelle, un 5xx peut également être approprié tant que vous pouvez vous asseoir et en décider avec votre équipe.

La catégorisation de codes comme celui-ci vous permet d'identifier plus rapidement le type d'erreur, mais cela peut avoir des avantages au-delà de l'organisation. Souvent, avec des erreurs de site Web, vous ne voulez pas que le client obtienne des erreurs inattendues car cela peut être un problème de sécurité et révéler des vulnérabilités, donc vous renvoyez un 500 générique "Une erreur s'est produite." et enregistrez l'erreur complète sur le serveur. Mais si une erreur attendue se produit en tant que 409, vous savez qu'il serait sûr de montrer l'erreur au client et vous n'avez pas à les laisser dans l'ignorance de ce qui s'est passé. C'est juste une utilisation pratique que je peux raconter, mais il y a beaucoup de possibilités.

C'est un peu un piège parce que vous publiez cela parce que vous ne pouvez pas être d'accord avec vos collègues, mais il semble que vous vous disputiez davantage sur la sémantique et qui est politiquement correct. Peu importe qui est le plus approprié, tant que vous pouvez trouver un système qui profite le plus à l'entreprise.

Par contre, s'il s'agit d'une API publique suivant les spécifications le plus près possible, il serait plus important d'éviter la confusion au sein de la communauté.

1
Despertar

404 == Le client a indiqué une ressource "individuelle"/"concrète" qui n'existe pas. C'est une erreur client.

200 == Le client a demandé de construire un ensemble de ressources "concrètes". Un ensemble peut toujours être également vide. Ainsi, même si la collection (résultat de la requête) est vide, le client n'a pas fait d'erreur.

0
Dave

Prenons un coup tangentiel à ceci: Si un humain utilise finalement l'API (via une interface graphique), je suggère de faire tout ce qui rend la vie facile pour l'utilisateur final. L'inexistence de l'arborescence alors qu'elle devrait exister est une erreur "Incohérence du modèle de domaine". Une erreur système survient lorsque vous manquez de mémoire ou avez rencontré une autre défaillance systémique. Donc, retourner 5xx est inapproprié. Comme mentionné par plusieurs personnes ci-dessus, 4xx pourrait être approprié si l'arbre lui-même avait son propre URI, ce qui n'est pas le cas ici. Mais voici ce que 404 dit au client: vous pouvez réessayer jusqu'à ce que vous récupériez quelque chose. Si vous avez renvoyé 200, vous pouvez renvoyer suffisamment de diagnostics à l'utilisateur ou à l'agent utilisateur pour que l'agent utilisateur puisse afficher une mesure afin que l'utilisateur cesse de réessayer et contacte uniquement le support. D'un autre côté, si cette API est destinée uniquement aux systèmes, un "message d'exception" doit faire partie de l'API afin que vous n'ayez pas à vous fier au flou inhérent aux codes d'erreur HTTP et que vous puissiez renvoyer quelque chose de significatif qui puisse être enregistré par le consommateur et escaladé.

0
user90766