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

20

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 a été 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 aux côtés d'autres erreurs 4XX et 5XX 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 ce qu'il pense (que le problème) est basé sur le corps de la réponse. Une solution simple serait de modifier 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 aborde le même problème auquel je fais face, mais elle 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?

Joe Shanahan
la source
3
J'hésite à poster ma simple opinion comme réponse. En bref: j'évite généralement d'utiliser des codes d'état HTTP pour représenter des erreurs commerciales. Ils ne doivent concerner que l'état de la communication entre le client et le serveur. Un code d'état adapté pour renvoyer des erreurs de validation ou de logique métier serait 400 Bad Request. La raison de cette séparation est que les futurs systèmes, développeurs ou lecteurs de documents peuvent être confondus par votre déviation de la norme mondiale.
Ivo Coumans
@IvoCoumans: veuillez faire ceci ^ une réponse pour que je puisse le voter. 400 Bad Requesten tant que code HTTP global semble préférable pour couvrir les erreurs de logique métier en tant que classe.
9000
Préférence personnelle, mais j'ai tendance à utiliser 400 Bad Requestlorsque les données sont manquantes ou ne peuvent pas être lues / analysées. C'est-à-dire que les données de demande elles-mêmes sont mauvaises d'une manière ou d'une autre.
Kasey Speakman
Veuillez développer ce que vous entendez par «erreur de logique métier». C'est extrêmement vague. Voulez-vous dire une entrée non valide conformément aux vérifications de validation des données (correctes), une entrée qui pourrait être valide à un autre moment, mais qui n'est pas valide dans l'état actuel, ou un bogue dans la logique métier où il rejette une entrée valide?
jpmc26
@ jpmc26 J'étais intentionnellement vague car c'était une question générale. Les serveurs ont très bien répondu à la demande mais ont décidé que la requête / assertion n'avait pas de sens.
Joe Shanahan

Réponses:

19

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 ce qu'est l'opération analogue 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 est également inadapté

La classe 5xx (erreur de serveur) de code d'état indique que le serveur est conscient qu'il s'est trompé

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 des 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 a mal tourné, et comprend idéalement des contrôles hypermédias qui conduisent le consommateur vers les ressources qui peuvent aider à résoudre le conflit.

Ma solution a été 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 aux côtés d'autres erreurs 4XX et 5XX 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 Requestserait é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 inclut 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 crois pas que ce soit tout à fait un match (bien que je convienne que cela jette un doute sur 400une alternative). Mon interprétation est que cela 422signifie "vous avez envoyé la mauvaise entité" où 409est "vous avez envoyé l'entité au mauvais moment".

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

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

VoiceOfUnreason
la source
5
" vous adaptez votre domaine pour qu'il ressemble à un magasin de documents " - J'aimerais voir les gens lire ceci et comprendre pleinement toutes les conséquences et implications avant de décider pour (ou contre) REST. Vraiment.
JensG
Les «erreurs de logique métier» ressemblent à une «entrée non valide», ce qui est généralement un 400 droit, car il n'y a pas de code d'erreur plus spécifique. Si ce n'est pas l'entrée qui n'est pas valide, le serveur a un bogue et 500 est approprié. Votre réponse semble trop présumer de la nature d'une «erreur de logique métier».
jpmc26
J'utiliserais 422. L'entrée est valide, donc 400 n'est pas le bon code d'erreur à utiliser
Konrad
19

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 ] }
Kasey Speakman
la source
Les codes d'état 4xx supérieurs à 400 ont des significations très spécifiques. Choisissez 400 si votre cas n'est pas spécifiquement couvert par les autres.
jpmc26
@ jpmc26 Si je n'utilise pas les codes d'état de cette façon, ils ne sont jamais utilisés. Mais n'hésitez pas à les utiliser de la bonne manière dans vos réponses.
Kasey Speakman
Dans un certain sens, vous avez raison. Ils ne sont jamais utilisés. Les significations choisies pour les codes spécifiques ne semblent pas être des cas d'utilisation très courants pour la plupart des applications. C'est bon. Il y a beaucoup d'exceptions que nous n'écrivons jamais de code pour intercepter non plus.
jpmc26
@ jpmc26 Les exceptions ne sont pas le meilleur modèle à suivre . Mais bien sûr, allez-y.
Kasey Speakman,
Ne pas lancer ou intercepter des types d' exceptions spécifiques est l'analogue de ne jamais utiliser de codes HTTP spécifiques ou tout autre code d'erreur. J'ai supposé que ce serait évident. La question de savoir si un modèle d'exception est «le meilleur» est totalement hors de propos.
jpmc26
5

En général, j'éviterais d'utiliser des codes d'état HTTP pour représenter des erreurs de logique métier spécifiques . 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 Requesten cas d'erreurs de validation et autres. De cette façon, vous utilisez un code d'état pour toutes les erreurs de logique métier.

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

Ivo Coumans
la source
4

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.

noneconnex
la source
Je ne sais pas si ce vote a été rejeté. C'est ainsi que les entreprises peuvent renvoyer des exceptions commerciales.
Skadoosh