web-dev-qa-db-fra.com

Une API REST doit-elle renvoyer une erreur de serveur interne 500 pour indiquer qu'une requête fait référence à un objet qui n'existe pas?

Je travaille avec une API REST qui réside sur un serveur qui gère les données d'une multitude d'appareils IoT.

Ma tâche consiste à interroger le serveur à l'aide de l'API pour collecter des informations de performances spécifiques sur lesdits appareils.

Dans un cas, j'obtiens une liste des périphériques disponibles et leurs identifiants correspondants, puis interroge plus tard le serveur pour plus de détails à l'aide de ces identifiants (GUID).

Le serveur renvoie un 500 Internal Server Error pour une requête sur l'un de ces ID. Dans mon application, une exception est levée et je ne vois pas de détails sur l'erreur. Si j'examine la réponse de plus près avec Postman , je peux voir que le serveur a renvoyé JSON dans le corps qui contient:

errorMessage: "This ID does not exist".

Ne tenez pas compte du fait que le serveur a fourni l'ID pour commencer - c'est un problème distinct pour le développeur.

Si un REST API retourne un 500 Internal Server Error pour signaler qu'une requête fait référence à un objet qui n'existe pas? À mon avis, les codes de réponse HTTP devraient se référer strictement à l'état de l'appel REST, plutôt qu'à la mécanique interne de l'API. Je m'attendrais à un 200 OK avec la réponse contenant l'erreur et la description, qui serait la propriété de l'API en question.


Il me semble qu'il y a une différence potentielle dans les attentes en fonction de la façon dont l'appel REST est structuré.

Considérez ces exemples:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

Dans le premier cas, l'ID de périphérique est transmis en tant que variable GET. Un 404 ou 500 indiquerait que le chemin (/restapi/deviceinfo) est introuvable ou a provoqué une erreur de serveur.

Dans le second cas, l'ID d'appareil fait partie de l'URL. Je serais plus compréhensif d'un 404 Not Found, mais pourrait encore discuter en fonction des parties du chemin qui sont interprétées comme des variables par rapport aux points de terminaison.

40
JYelton

Je pense qu'une réponse 404 est la meilleure correspondance sémantique ici, car la ressource que vous tentiez de trouver (représentée par l'URI utilisé pour la requête) n'a pas été trouvée. Le renvoi d'une charge utile d'erreur dans le corps est raisonnable, mais pas obligatoire.

Selon RFC 2616 , la définition du code d'état 404 est:

10.4.5 404 introuvable
Le serveur n'a rien trouvé correspondant à l'URI de la demande. Aucune indication n'est donnée quant à savoir si la condition est temporaire ou permanente. Le code d'état 410 (disparu) DEVRAIT être utilisé si le serveur sait, par le biais d'un mécanisme configurable en interne, qu'une ancienne ressource est indisponible en permanence et n'a pas d'adresse de transfert. Ce code d'état est couramment utilisé lorsque le serveur ne souhaite pas révéler exactement pourquoi la demande a été refusée, ou lorsqu'aucune autre réponse n'est applicable.

96
Andy Hunt

J'utiliserai vos exemples.

http://example.com/restapi/deviceinfo?id=12

Si le point de terminaison renvoie un tableau json , le meilleur choix pour est 200 OK avec un tableau vide si aucun résultat n'a été trouvé.

Si le point de terminaison est conçu pour renvoyer un résultat unique , mon choix serait 404 NOT FOUND, car, pour moi, la bonne syntaxe pour ce type de point de terminaison est: http://example.com/restapi/deviceinfo/123. J'utilise généralement request param uniquement pour le filtrage et lorsque mon point de terminaison renvoie un tableau.

http://example.com/restapi/device/123/info

Je pense que cette question a déjà été répondue ici . POST ou GET, le meilleur choix semble 404 NOT FOUND parce que la ressource 123 n'a pas été trouvé.

Dans les deux cas, je ne vois pas la nécessité d'expliquer pourquoi la demande n'a pas été complétée. Les informations de demande et le code HTTP expliquent déjà pourquoi.

34
Dherik

HTTP 404 est correct, car le serveur comprend quelle ressource le client demande, mais il n'a pas cette ressource.

Le fait que vous travailliez avec une "API REST" est la clé. L'API doit se comporter comme si elle effectuait un transfert d'état représentatif, sans exécuter de fonction. (Bien sûr, le terme "REST" a pris un sens plus large, mais vous pouvez toujours utiliser son sens littéral à bon escient ici.) Le client a demandé l'état d'une ressource décrite par l'URL http://example.com/restapi/device/123/info. Une chaîne de requête (/deviceinfo?id=123) ne changerait pas la situation. Le serveur sait que vous demandez de transférer l'état de l'appareil 123, mais il ne le reconnaît pas comme une ressource connue. Par conséquent HTTP 404.

Les autres réponses possibles discutées ici ont également des significations spécifiques:

  • HTTP 200 - Nous avons l'état pour vous; c'est dans le corps de réponse.
  • HTTP 204 - Nous avons l'état pour vous; c'est vide.
  • HTTP 400 - Nous ne pouvons pas dire de quelle ressource vous parlez. Corrigez votre URL.
  • HTTP 500 - Nous avons mal fonctionné. Pas ta faute.

Voir RFC 2616 Sec. 10 selon le cas.

27
Travis Wilson

Une erreur 5xx est généralement utilisée pour indiquer que le serveur a rencontré une erreur et ne peut pas terminer la demande. Si le serveur accepte la demande, peut l'analyser avec succès, puis fait son travail, cela ne devrait pas renvoyer une erreur 5xx.

Je ne sais pas s'il existe une sorte de convention sur ce qu'il faut retourner si une requête ne donne aucun résultat. J'ai vu à la fois ce que vous décrivez (un 200 avec un corps qui contient un message) ainsi qu'un 404 indiquant que les résultats n'ont pas été trouvés. Le 200 est probablement le plus logique - la demande a été traitée avec succès et il n'y a eu aucun problème avec la demande du client ou pendant le traitement de la demande par le serveur. Un corps peut délivrer un message au client.


Je traiterais vos deux exemples (http://example.com/restapi/deviceinfo?id=123 et http://example.com/restapi/device/123/info) pareil - le 123 est un paramètre. Les deux cas sont des manières différentes de structurer une demande pour obtenir des informations sur un périphérique avec un ID 123.

Tout d'abord, je considérerais l'autorisation et l'authentification. Si l'utilisateur n'a pas les autorisations appropriées, je retournerais un 403 ou un 401 selon le cas. Bien que cela s'appelle "non autorisé", je crois comprendre que 401 concerne davantage l'authentification et 403 une autorisation non autorisée ou refusée. Je ne serais pas trop pointilleux ici, cependant, si vous vouliez simplement vous en tenir au 403 pour toutes les erreurs d'authentification et d'autorisation.

Ensuite, je gérerais l'ID. D'après votre exemple, il semble que ce soit un ID numérique. Si une valeur non numérique était fournie, je retournerais un 400. Si le paramètre pouvait éventuellement être un identifiant de périphérique valide, je continuerais le traitement. S'il y avait d'autres arguments, ils seraient également vérifiés ici. Je m'attendrais à ce que l'organe de réponse contienne des informations appropriées sur les raisons de la mauvaise demande.

Si tous les paramètres étaient valides, je commencerais à traiter la demande. Si le système ou toute dépendance (une base de données, un service tiers, un autre service interne) n'est pas disponible, je retournerais un code 5xx - 503 serait spécifique, mais un 500 serait également acceptable. Dans les deux cas, je retournerais un corps avec des détails supplémentaires. Considérez que si une dépendance externe signale un délai d'attente de demande 408, je mangerais cela et retournerais un 500 à mon client, permettant à un client de recevoir un 408 uniquement si la demande à mon système a expiré. Si le système est en mesure de répondre à la demande, je retournerais un 200 et le corps approprié.

204 peut être utile dans certains cas, mais il vous empêche d'envoyer un corps de réponse. Surtout dans un paramètre API, l'envoi d'un corps de réponse avec des informations pouvant être introduites dans un mécanisme de journalisation ou de rapport semble être la bonne décision à prendre dans la plupart des cas.

La seule fois où un 404 serait retourné, c'est si le serveur n'avait pas de /deviceinfo point final ou /device/:id/info point final.

Je ne considérerais pas une identification qui n'est pas identique à la ressource non trouvée. La ressource est l'information sur le périphérique pour un périphérique particulier (dans votre exemple). Renvoyer un 404 signifierait que la ressource (les informations sur le périphérique) n'existe pas. Un 200 avec un corps approprié signifie que le système peut en effet fournir des informations sur l'appareil. Il peut y avoir ou non un périphérique avec l'ID spécifié.

11
Thomas Owens

Une erreur HTTP série 500 indique un dysfonctionnement du serveur. Excepté 501 Not Implemented et 505 HTTP Version Not Supported, l'utilisation de ces codes d'erreur implique que la nouvelle tentative de la demande à un moment ultérieur peut réussir (bien que seulement 503 Service Unavailable le dit explicitement). Idéalement, un serveur ne devrait jamais produire l'un de ces codes, bien que l'impossibilité d'écrire un logiciel sans bogue et de fournir au serveur des ressources infinies signifie que vous en aurez besoin de temps en temps.

Pour un résultat "l'objet n'existe pas", vous devriez probablement retourner soit 404 Not Found (lorsque la demande porte sur un objet par son nom), ou 200 Success avec un corps de résultat vide (lors de la recherche d'un objet par attributs). 204 No Content semble tentant, mais je ne l'emploierais que dans les situations où un manque de corps de réponse est le résultat attendu.

5
Mark

En tant que client de votre API, lorsque je fais l'un de ces appels:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

Je m'attends à récupérer un (représentation de) un objet DeviceInfo (ou un type particulier de toute façon, que ce soit un type formel ou juste quelque chose conforme à une convention documentée de "type de canard"). Je veux un 200 statut signifie que j'en ai effectivement un, et je peux continuer à l'utiliser.

Pour les API REST, je considère les codes d'état 400 et 500 comme des exceptions. Vous les utilisez pour indiquer quand vous ne pouvez pas renvoyer une réponse "normale" pour la demande que vous avez reçue, le client devra donc faire quelque chose d'exceptionnel plutôt que de traiter les informations qu'il s'attendait à récupérer.

Cela signifie, en tant que consommateur d'API, que je peux utiliser une sorte de fonction d'appel de repos vérifié qui récupère une réponse ou lève une exception. C'est génial; ma logique normale peut être du code en ligne droite, et je peux organiser ma gestion des erreurs de la même manière que je le fais en code local. Les 404 inattendus se manifesteront comme des exceptions "aucune ressource trouvée" sans que je doive faire quoi que ce soit, pas comme des erreurs "d'attribut manquant" lorsque je traiterai plus tard { errorMessage: "Device 123 not found" } comme s'il s'agissait d'un objet DeviceInfo.

Si vous pensez que le noeud final http://example.com/restapi/deviceinfoest trouvé, et ce n'est que le id=123 ce n'est pas le cas, et donc retournez 200 avec un message d'erreur dans le corps, puis vous créez exactement le même genre de problèmes d'interface que les fonctions C qui pourraient renvoyer un résultat correct ou un code d'erreur, ou des méthodes qui indiquent problèmes en renvoyant arbitrairement null. Il est beaucoup plus agréable en tant qu'utilisateur de votre interface d'avoir des erreurs signalées via un canal "séparé" des retours réguliers. Cela s'applique également ici, même si les réponses HTTP 200, 404 et 500 sont le même canal d'un point de vue bas niveau. Ils sont standardisés et faciles à distinguer, donc mon REST peut facilement activer ces statuts pour les transformer en les structures appropriées dans mon langage; pour faire la même chose avec la couche JSON ( où vous dites toujours 200 et donnez-moi un DeviceInfo ou un message d'erreur) J'ai besoin d'intégrer une certaine connaissance des schémas JSON que vous utilisez.

N'utilisez donc que 200 lorsque vous pouvez renvoyer une valeur valide du type attendu (c'est pourquoi http://example.com/restapi/search-devices?colour=blue peut renvoyer 200 avec un tableau vide s'il n'y a pas de périphériques bleus; un tableau vide est un tableau valide et une réponse sensée à la demande "Je voudrais les détails de tous les périphériques bleus"). Si vous ne le pouvez pas, utilisez le code d'état non 200 le plus approprié. Même si "le périphérique 123 n'existe pas" est la bonne réponse à "donnez-moi les détails du périphérique 123", et ce n'est pas une erreur pour le serveur, c'est une exception pour le client qui s'attend à ce qu'ils 'va récupérer un DeviceInfo et ne devrait pas être communiqué comme une réponse normale "voici ce que vous avez demandé".

1
Ben

Vous pouvez utiliser l'erreur 422 Entité non traitable pour faire la différence avec 404 introuvable. 422 signifie que le serveur comprend la demande mais il ne peut pas donner une réponse appropriée. J'utilise ce code dans des situations similaires.

0
FiNeX

L'erreur 500 indique normalement que la demande a bloqué un programme côté serveur; dans les environnements d'entreprise, ces erreurs sont traitées comme un œuf au visage et sont évitées.

L'erreur 4xx doit signaler au programmeur que le point de terminaison API (ressource) n'existe pas. Par conséquent, une fois que le point final approprié est atteint, toute gestion d'erreur à partir de ce point est la responsabilité du programmeur de l'API qui doit être gérée avec élégance, c'est-à-dire avec un message d'erreur d'une réponse 200.

0
postronnim

Bien que le w3 note que 404 est utilisé lorsque aucune autre réponse n'est applicable , ne serait-ce pas pour cela qu'une réponse 204 (sans contenu) est bonne? La demande était valide du point de vue du traitement et le serveur a traité la demande et a un résultat. C'est un succès, qui penche vers des réponses 2xx. Il n'y avait pas de contenu pour cette demande particulière, 204 indique donc à l'utilisateur qu'il n'y a rien de mal à sa requête mais qu'il n'y a rien.

Vous pouvez également faire valoir que le 409 (Conflit) est une réponse appropriée. Bien que le 409 soit le plus souvent utilisé pour un POST, il est dit

La demande n'a pas pu être traitée en raison d'un conflit avec l'état actuel de la ressource. Ce code n'est autorisé que dans les situations où l'on s'attend à ce que l'utilisateur puisse résoudre le conflit et soumettre à nouveau la demande. Le corps de réponse DEVRAIT inclure suffisamment d'informations pour que l'utilisateur reconnaisse la source du conflit. Idéalement, l'entité de réponse comprendrait suffisamment d'informations pour que l'utilisateur ou l'agent utilisateur puisse résoudre le problème; cependant, cela pourrait ne pas être possible et n'est pas requis.

sans doute l'inexistence de l'identifiant demandé est le conflit ici, et renvoyer dans le message qu'aucun identifiant de ce type n'existe dans le système suffit à l'utilisateur pour reconnaître et résoudre le conflit.

0
moneyt

Les autres réponses le couvrent, mais je voulais juste souligner qu'une erreur de la série 500 signifie "j'ai foiré". Dans ce cas, "I" signifie l'API, donc une erreur de serveur non gérée ou similaire. Une erreur de la série 400 signifie "vous avez foiré" - l'appelant de l'API a envoyé quelque chose de incorrect.

0
Marcie