Quelle est la réponse de code d'état HTTP appropriée pour une demande générale infructueuse (pas une erreur)?

109

Je crée une API RESTful qui traitera un certain nombre d'interactions utilisateur, y compris la passation de commandes à l'aide de cartes de crédit stockées.

Dans le cas d'une commande réussie, je retourne un 200 OK, et dans le cas où la demande de commande est mal formée ou invalide, je retourne une 400 Bad Request. Mais que dois-je retourner en cas de problème lors du traitement proprement dit de la commande?

  1. Le client POST une commande au serveur pour une ressource utilisateur. Si l'utilisateur n'existe pas, 404 Not Found est renvoyé.
  2. Le format et les informations de la commande sont validés. Si non valide, 400 Bad Request est renvoyé.
  3. La commande est traitée. Si la commande est réussie, un 201 Created est retourné pour la commande. Si une erreur inattendue se produit, une erreur de serveur 500 est renvoyée.

La dernière étape est le problème - que dois-je retourner si la commande ne se termine pas pour une autre raison? Les scénarios possibles pourraient inclure:

  • Le produit est épuisé
  • Limite de commande maximale de l'utilisateur atteinte
  • Échec de la transaction par carte de crédit (fonds insuffisants, etc.)

Cela ne semble pas approprié pour un 400 ou un 500. Si quoi que ce soit, je pourrais le voir comme un 400 s'il n'y a pas de meilleur code - la demande était invalide selon les règles métier. Cela ne semble tout simplement pas exact.

Edit: a également trouvé cette discussion existante sur le même sujet. Toutes les réponses semblent indiquer l'utilisation de codes d'état pour ce type de violation, avec une discussion entre l'utilisation de l'extension 400, 409 ou 422.

Raelshark
la source
8
J'aime «422 entité non traitable» pour les erreurs de validation. Et l'utiliser pour vos exemples ci-dessus, inclure un message dans la réponse avec le problème commercial réel "Le produit est épuisé" et éventuellement ajouter vos propres "codes" si le client doit prendre des décisions par programmation différentes en fonction de la réponse
maison9
avant de sauter dans 422, considérez si vous prenez en charge les capacités WebDAV
Mbithy Mbithy

Réponses:

90

Vous devez utiliser 400 pour les règles métier. Ne retournez pas 2xx si la commande n'a pas été acceptée. HTTP est un protocole d'application, ne l'oubliez jamais. Si vous retournez 2xx, le client peut supposer que la commande a été acceptée, quelles que soient les informations que vous envoyez dans le corps.


À partir du livre de recettes des services Web RESTful :

Une erreur courante que font certains services Web est de renvoyer un code d'état qui reflète le succès (codes d'état de 200 à 206 et de 300 à 307) mais inclut un corps de message qui décrit une condition d'erreur. Cela empêche les logiciels compatibles HTTP de détecter les erreurs. Par exemple, un cache la stockera en tant que réponse réussie et la servira aux clients suivants, même lorsque les clients peuvent être en mesure de faire une demande réussie.

Je vous laisse le soin de choisir entre 4xx et 5xx, mais vous devriez utiliser un code d'état d'erreur.

Max Toro
la source
1
Avez-vous des exemples ou des références pour cette approche par rapport à l'autre? Vos réponses et celles de Widor ont du sens, l'une du point de vue de HTTP en tant que protocole d'application, et l'autre car il est strictement destiné au transfert. La spécification le définit comme un "protocole au niveau de l'application", ce qui est un peu vague. J'ai également vu des perspectives et des exemples sur le Web lors de mes recherches.
Raelshark
c'est tellement vrai.
Young Hyun Yoo
2
Voulez-vous dire, "Vous devriez utiliser 4xx pour les règles métier"?
Yawar
28

Vous devez utiliser 4xx pour une erreur client si le client peut modifier la demande pour contourner l'erreur. Utilisez un 5xx pour une erreur de serveur que le client ne peut pas vraiment contourner.

Le produit épuisé serait une erreur de serveur. Le client ne peut pas modifier la demande d'une manière ou d'une autre pour contourner l'erreur. Vous pourriez passer à un autre produit mais ne serait-ce pas une nouvelle demande?

La limite de commande maximale de l'utilisateur atteinte est également une erreur de serveur. Rien que le client ne peut faire pour contourner cette erreur.

L'échec de la transaction par carte de crédit serait une erreur du client. Le client peut resoumettre la demande avec un autre mode de paiement ou numéro de carte de crédit pour contourner l'erreur.

Paul Morgan
la source
6
Si la limite de commande est atteinte, le client ne devrait-il pas en avertir l'utilisateur et le laisser modifier sa demande de manière appropriée? Cela semble être une erreur 4xx. Il en va de même pour le produit en rupture de stock. Les erreurs 5xx sont destinées aux erreurs causées par une panne du système, et non à une action interdite par une règle métier.
carlin.scott
7
Je suis d'accord avec le commentaire ci-dessus. Les erreurs 5xx sont pour quand le serveur a des problèmes. Erreurs 4xx pour les règles métier.
Merc
21

Type d'erreur:

4×× Client Error

Code d'erreur:

422 Unprocessable Entity

Le serveur comprend le type de contenu de l'entité de demande (par conséquent, 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 un code d'état 400 Bad Request est inapproprié) mais n'a pas pu traiter le contenu instructions.

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.

https://httpstatuses.com/422

stamster
la source
16

Je sais que cette question est ancienne, mais j'ai posé la même question aujourd'hui. Si mon utilisateur n'a plus de crédits, quel code de statut doit renvoyer mon API REST?

J'ai tendance à me pencher vers 402 Payment Required:

Selon Wikipedia :

Réservé pour une utilisation future. L'intention initiale était que ce code puisse être utilisé dans le cadre d'une forme quelconque de système de paiement en espèces ou de micropaiement numérique, mais cela ne s'est pas produit et ce code n'est généralement pas utilisé. L'API Google Developers utilise ce statut si un développeur particulier a dépassé la limite quotidienne de demandes.

Et en effet, ils font :

PAYMENT_REQUIRED (402)

  • Une limite de budget quotidien définie par le développeur a été atteinte.
  • L'opération demandée nécessite plus de ressources que le quota ne le permet. Le paiement est requis pour terminer l'opération.
  • L'opération demandée nécessite une sorte de paiement de la part de l'utilisateur authentifié.
Benjamin
la source
C'est la réponse la plus réfléchie et la plus logique.
GTodorov
5

Et pourquoi pas 424 Failed Dependency? La spécification le décrit comme:

La méthode n'a pas pu être exécutée sur la ressource car l'action demandée dépendait d'une autre action et cette action a échoué.

Mais il y a aussi cette définition :

Le code d'état 424 est défini dans le standard WebDAV et est pour un cas où le client doit changer ce qu'il fait - le serveur ne rencontre aucun problème ici.

Vous pouvez dire au client (ou faire semblant) que vous avez des actions internes qui sont censées créer la commande et déduire le solde, et que l'une de ces actions a échoué, bien que pour des raisons parfaitement valables, et c'est pourquoi la demande a échoué.

Pour autant que je sache, «action» est un terme assez large et peut être utilisé dans diverses situations, notamment un stock insuffisant, un crédit insuffisant ou une soirée entrepôt.


Une autre option pourrait être 422 Unprocessable Entity:

Le serveur comprend le type de contenu de l'entité de demande (par conséquent, 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 un code d'état 400 Bad Request est inapproprié) mais n'a pas pu traiter le contenu instructions.

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.

Tenter de demander un article en rupture de stock, ou lorsque votre crédit est insuffisant, peut être considéré comme une erreur au niveau sémantique.

MozDev dit que cela indique une erreur du côté client, en particulier: Le client ne doit pas répéter cette demande sans modification.

Le bouclage 4 utilise 422 lorsque la validation d'entrée échoue.


On peut soutenir qu'un stock insuffisant ou une nuit dans l'entrepôt pourraient être considérés comme des états temporaires, de sorte que la demande pourrait être réessayée plus tard. Cette situation peut être indiquée par503 Service Unavailable

Le serveur est actuellement incapable de traiter la demande en raison d'une surcharge temporaire ou d'une maintenance planifiée, qui sera probablement atténuée après un certain délai.

Le serveur PEUT envoyer un champ d'en-tête Retry-After pour suggérer une durée appropriée pour que le client attende avant de réessayer la demande.

joeytwiddle
la source
Aucun de ceux-ci ne concerne un paiement. Je vais avec 402 de la réponse précédente!
GTodorov
2

Je ne pense pas que 400 puisse être utilisé pour tous les scénarios commerciaux. Il peut être utilisé pour la validation d'entrée de données de base. Au-delà de cela, nous pourrions avoir du mal à intégrer une autre logique métier dans ce code d'erreur. Les erreurs gérées par ceci sont principalement des erreurs de conception que le développeur rencontrera éventuellement lors du codage du client.

Disons que tous les paramètres sont corrects et disons que nous transmettons le numéro de compte utilisateur dans la requête.

La requête n'est donc plus une mauvaise requête, le serveur est capable d'accepter la requête. Mais maintenant, il refuse de répondre à la demande sur la base des nouvelles informations disponibles, ce qui est - le compte n'a pas un solde suffisant.

Je suggérerais que nous devrions utiliser 403 avec un message d'erreur approprié dans ces scénarios.

Un autre code d'erreur possible pourrait être un conflit 409. Mais cela est utilisé dans les scénarios où la ressource est dans un état cohérent.

Rajender Saini
la source
-1

Je vais avec 406 Not Acceptable.

Voici une liste 4xx:

const HTTP_BAD_REQUEST = 400;
const HTTP_UNAUTHORIZED = 401;
const HTTP_PAYMENT_REQUIRED = 402;
const HTTP_FORBIDDEN = 403;
const HTTP_NOT_FOUND = 404;
const HTTP_METHOD_NOT_ALLOWED = 405;
const HTTP_NOT_ACCEPTABLE = 406;
const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
const HTTP_REQUEST_TIMEOUT = 408;
const HTTP_CONFLICT = 409;
const HTTP_GONE = 410;
const HTTP_LENGTH_REQUIRED = 411;
const HTTP_PRECONDITION_FAILED = 412;
const HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
const HTTP_REQUEST_URI_TOO_LONG = 414;
const HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
const HTTP_EXPECTATION_FAILED = 417;
const HTTP_I_AM_A_TEAPOT = 418;                                               // RFC2324
const HTTP_MISDIRECTED_REQUEST = 421;                                         // RFC7540
const HTTP_UNPROCESSABLE_ENTITY = 422;                                        // RFC4918
const HTTP_LOCKED = 423;                                                      // RFC4918
const HTTP_FAILED_DEPENDENCY = 424;                                           // RFC4918
const HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425;   // RFC2817
const HTTP_UPGRADE_REQUIRED = 426;                                            // RFC2817
const HTTP_PRECONDITION_REQUIRED = 428;                                       // RFC6585
const HTTP_TOO_MANY_REQUESTS = 429;                                           // RFC6585
Mahmoud Zalt
la source
8
Bien que le nom du code d'état 406 puisse sembler exact en lui-même, vous devez être conscient que chaque code d'état a une description textuelle faisant autorité. La description du code d'état 406 ne convient pas au cas d'espèce. Voir httpstatuses.com/406 , par exemple.
Zero3 du
1
@ Zero3 a raison, ce code signifie que le type de réponse n'est pas acceptable, car il y a une discordance entre les en-têtes d'acceptation envoyés par le client et le ou les MediaType (s) envoyés par le point de terminaison, par exemple application / json vs text / plain
Gregor