web-dev-qa-db-fra.com

Les codes d'état HTTP doivent-ils être utilisés pour représenter des erreurs de logique métier sur un serveur?

Je suis à la croisée des chemins avec une conception d'API permettant à un client (JS dans un navigateur) de parler à un serveur. Nous utilisons HTTP 409 Conflict pour représenter l'échec d'une action en raison d'un verrou de sécurité en vigueur. Le verrou Satefy empêche les développeurs de modifier accidentellement les systèmes de production de nos clients. J'ai été chargé de gérer les 409 un peu plus gracieusement sur le client pour indiquer pourquoi un appel d'API particulier a échoué.

Ma solution était d'envelopper les gestionnaires d'échecs de l'un de nos appels AJAX qui afficheront une notification sur le client en cas d'échec en raison de 409 - tout va bien et fonctionne bien avec les autres 4XX et 5XX erreurs qui utilisent le même mécanisme.

Un problème est survenu lorsqu'un de nos gestionnaires d'itinéraire répond par 409 lorsqu'il rencontre une erreur de logique métier - mon wrapper AJAX signale que le verrou de sécurité est activé, tandis que le gestionnaire d'échec existant du client signale quoi (il pense que le problème est basé sur le corps de la réponse. Une solution simple serait de changer la réponse du gestionnaire ou le code d'état que nous utilisons pour représenter le verrou de sécurité.

Ce qui m'amène à mon carrefour: les codes de statut HTTP devraient-ils même être utilisés pour représenter des erreurs de logique métier? Cette question résout le même problème auquel je suis confronté mais il n'a pas gagné beaucoup de traction. Comme suggéré dans la réponse liée, je penche pour l'utilisation de HTTP 200 OK avec un corps approprié pour représenter l'échec dans la logique métier.

Quelqu'un a-t-il des opinions bien arrêtées ici? Quelqu'un peut-il me convaincre que c'est la mauvaise façon de représenter l'échec?

22
Joe Shanahan

Kasey couvre le point principal.

L'idée clé de toute API Web: vous adaptez votre domaine pour qu'il ressemble à un magasin de documents. GET/PUT/POST/DELETE et ainsi de suite sont tous des moyens d'interagir avec le magasin de documents.

Donc une façon de penser aux codes à utiliser, est de comprendre à quoi ressemble l'opération dans un magasin de documents et à quoi ressemblerait cet échec dans cet analogique.

2xx est totalement inadapté

La classe de code d'état 2xx (Réussi) indique que la demande du client a été reçue, comprise et acceptée avec succès.

5xx ne convient pas non plus

La classe 5xx (Erreur de serveur) de code d'état indique que le serveur est conscient qu'il a commis une erreur

Dans ce cas, le serveur n'a pas fait d'erreur; il est conscient que vous n'êtes pas censé modifier cette ressource de cette façon pour le moment.

Les erreurs de logique métier (ce qui signifie que l'invariant métier ne permet pas la modification proposée pour le moment) sont probablement un 409

Le code d'état 409 (Conflit) indique que la demande n'a pas pu être traitée en raison d'un conflit avec l'état actuel de la ressource cible. Ce code est utilisé dans les situations où l'utilisateur peut être en mesure de résoudre le conflit et de soumettre à nouveau la demande. Le serveur DEVRAIT générer une charge utile qui comprend suffisamment d'informations pour qu'un utilisateur reconnaisse la source du conflit.

Notez ce dernier bit - la charge utile de la réponse 409 devrait être de communiquer des informations au consommateur sur ce qui ne va pas, et comprend idéalement des contrôles hypermédias qui conduisent le consommateur aux ressources qui peuvent aider à résoudre le conflit.

Ma solution était d'envelopper les gestionnaires d'échecs de l'un de nos appels AJAX qui afficheront une notification sur le client en cas d'échec en raison de 409 - tout va bien et fonctionne bien avec les autres 4XX et 5XX erreurs qui utilisent le même mécanisme.

Et je soulignerais que c'est le problème; votre implémentation chez le client supposait que le code d'état était suffisant pour définir le problème. Au lieu de cela, votre code client devrait examiner la charge utile et agir sur les informations disponibles.

C'est, après tout, comment un magasin de documents le ferait

409  Conflict

your proposed change has been declined because ${REASON}.  
The following resolution protocols are available: ${LINKS[@]})

La même approche avec un 400 Bad Request serait également acceptable; qui se traduit en gros par "Il y a eu un problème avec votre demande. Nous ne pouvons pas être dérangés pour déterminer quel code d'état est le mieux adapté, alors voilà. Voir la charge utile pour plus de détails. "

J'utiliserais 422. L'entrée est valide, donc 400 n'est pas le bon code d'erreur à utiliser

La spécification WebDAV comprend cette recommandation

Le code d'état 422 (entité non traitable) signifie que le serveur comprend le type de contenu de l'entité de demande (donc un code d'état 415 (type de support non pris en charge) est inapproprié) et la syntaxe de l'entité de demande est correcte (donc 400 (mauvaise demande) ) le code d'état est inapproprié) mais n'a pas pu traiter les instructions contenues. Par exemple, cette condition d'erreur peut se produire si un corps de requête XML contient des instructions XML bien formées (c'est-à-dire syntaxiquement correctes) mais sémantiquement erronées.

Je ne pense pas que ce soit tout à fait un match (bien que je convienne que cela jette un doute sur 400 comme alternative). Mon interprétation est que 422 signifie "vous avez envoyé la mauvaise entité" où 409 est "vous avez envoyé l'entité au mauvais moment".

En d'autres termes, 422 indique un problème avec le message de demande considéré isolément, où 409 indique que le message de demande est en conflit avec l'état actuel de la ressource.

discussion de Ben Nadal sur 422 peut être utile à considérer.

20
VoiceOfUnreason

D'après mon expérience, les codes d'erreur HTTP sont insuffisants pour représenter les erreurs commerciales. Cependant, ils sont utiles pour représenter des classes d'erreurs.

Donc, ma recommandation serait d'utiliser des codes d'erreur HTTP pour les catégories d'erreurs, mais choisissez une erreur spécifique pour les échecs de logique métier (par exemple, 409 Conflit ... 200 OK serait trompeur ici) et incluez des données dans la réponse indiquant l'erreur métier spécifique . Assurez-vous que cela fait partie du contenu de la réponse et non du texte d'état car certains navigateurs ignorent le texte d'état personnalisé. La langue que j'aime utiliser a des types d'unions qui sont pratiques pour représenter des messages. Mais vous pouvez également définir des constantes de chaîne pour les cas d'erreur.

Exemples

// error with text response
409 Conflict "safety_lock_engaged"
409 Conflict "customer_not_eligible_for_selected_discount"
// warning with JSON response
202 Accepted { "backorderedProductIds": [ 37, 476 ] }
20
Kasey Speakman

Vous pouvez utiliser "Bad Request" et inclure l'id de la règle commerciale violée ainsi que plus de détails sur le corps de la réponse.

6
noneconnex

En général, j'éviterais d'utiliser des codes d'état HTTP pour représenter spécifiques les erreurs de logique métier. En effet, ils ont déjà une signification sémantique définie par la norme mondiale. Les autres systèmes, les nouveaux développeurs et ainsi de suite seront confondus par votre déviation de la norme.

Ce que j'ai trouvé dans des recherches récentes et similaires, c'est qu'il est généralement accepté d'utiliser 400 Bad Request en cas d'erreurs de validation et autres. De cette façon, vous utilisez n code d'état pour toutes les erreurs de logique métier.

Par ailleurs, 409 doit être utilisé lorsqu'une ressource a changé pendant que vous la modifiiez et que vous avez réessayé de l'enregistrer.

5
Ivo Coumans