Codes d'état HTTP REST pour échec de validation ou doublon non valide

826

Je crée une application avec une API basée sur REST et j'en suis arrivé au point où je spécifie des codes d'état pour chaque demande.

Quel code d'état dois-je envoyer pour les demandes qui n'ont pas été validées ou où une demande essaie d'ajouter un doublon dans ma base de données?

J'ai parcouru http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html mais aucun ne semble correct.

Existe-t-il une pratique courante lors de l'envoi de codes d'état?

alexn
la source
14
Ouvrez httpstatus.es , Clic droit >> Onglet Pin: P
Salman von Abbas

Réponses:

780

En cas d'échec de validation d'entrée: 400 Bad Request + votre description facultative. Ceci est suggéré dans le livre " RESTful Web Services ". Pour double soumission: 409 Conflict


Mise à jour juin 2014

La spécification pertinente était RFC2616 , qui donnait l'utilisation de 400 (Bad Request) de manière assez étroite comme

La demande n'a pas pu être comprise par le serveur en raison d'une syntaxe incorrecte

On aurait donc pu dire que c'était inapproprié pour les erreurs sémantiques. Mais plus maintenant; depuis juin 2014, la norme pertinente RFC 7231 , qui remplace la précédente RFC2616, donne l'utilisation de 400 (Bad Request) plus largement que

le serveur ne peut pas ou ne traitera pas la demande en raison de quelque chose qui est perçu comme une erreur client

démon
la source
3
Oui, le corps de la demande fait partie de la syntaxe.
Deamon
62
Une mauvaise demande est certainement la réponse la plus courante à ce type de problème. La seule autre alternative est 422 Entité non traitable. Il provient en fait de WebDav mais il est parfaitement valide pour réutiliser tout code d'état qui a été enregistré auprès de l'IANA.
Darrel Miller
19
Alors, comment différenciez-vous les données malformées que le serveur ne peut même pas analyser et une erreur de validation? Un client traiterait ces deux réponses complètement différemment. Pour la validation, ils afficheraient probablement les erreurs à l'utilisateur. Pour de véritables "données malformées", ils enregistreraient l'erreur afin que le bogue de la méthode qui génère la demande puisse être corrigé.
Josh Noe
18
Je ne suis pas d'accord avec votre interprétation de la RFC7231, bien qu'elle indique something perceived to be a client error, tous les exemples donnés dans ce paragraphe sont des violations du protocole HTTP, pas des erreurs logiques: syntaxe, cadrage, routage. Ainsi, je considère que la spécification HTTP ne permet pas 400 pour la validation a échoué au niveau de l'application.
Dima Tisnek
2
pourquoi ne pas utiliser une 422 - Entité non traitable?
Cela
278
  • Échec de la validation: 403 interdit ("Le serveur a compris la demande, mais refuse de la satisfaire"). Contrairement à l'opinion populaire, la RFC2616 ne dit pas que "403 est uniquement destiné à l'échec de l'authentification", mais "403: je sais ce que vous voulez, mais je ne le ferai pas". Cette condition peut ou non être due à l'authentification.
  • Tentative d'ajout d'un doublon: 409 Conflit ("La demande n'a pas pu être terminée en raison d'un conflit avec l'état actuel de la ressource.")

Vous devriez certainement donner une explication plus détaillée dans les en-têtes et / ou le corps de la réponse (par exemple avec un en-tête personnalisé - X-Status-Reason: Validation failed).

Piskvor a quitté le bâtiment
la source
17
@deamon: Ce n'est pas la spécification, c'est Wikipedia, c'est-à-dire l'opinion de quelqu'un sur "ce que signifient les codes de statut HTTP"; notez que la page indique essentiellement "c'est ce que Apache signifie avec 403, c'est ce que IIS signifie avec 403", et nulle part il ne fait référence au RFC officiel. Vous semblez répéter "403 signifie tout ce qu'Apache dit". NE PAS. La RFC réelle (qui est le document pertinent, pas l'implémentation d'Apache, l'implémentation d'IIS, ni l'implémentation de quelqu'un d'autre) est ici: w3.org/Protocols/rfc2616/rfc2616-sec10.html
Piskvor a quitté le bâtiment le
57
"10.4.4 403 Interdit Le serveur a compris la demande, mais refuse de la remplir. L'autorisation n'aidera pas et la demande NE DEVRAIT PAS être répétée. Si la méthode de demande n'était pas HEAD et que le serveur souhaite rendre public pourquoi la demande n'a pas été rempli, il DEVRAIT décrire la raison du refus dans l'entité. Si le serveur ne souhaite pas mettre ces informations à la disposition du client, le code d'état 404 (Not Found) peut être utilisé à la place. " Je n'y vois aucune emphase ("DEVRAIT / NE DEVRAIT PAS" sont des mots-clés RFC 2119, pas d'accentuation); c'est votre idée de ce que signifie "interdit", pas des RFC.
Piskvor a quitté le bâtiment le
10
J'aime cette réponse, mais je vois toujours un petit problème. Selon la spécification , lorsqu'un 403 est retourné, "la demande NE DEVRAIT PAS être répétée". Cependant, renvoyer un 409 "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". Dans le cas d'un doublon, je pense que 403 est alors plus approprié, car vous ne pouvez pas vraiment résoudre le conflit (sauf en supprimant l'instance précédente de la ressource).
pablobm
2
Pour le message d'erreur lui-même, vous devez modifier la phrase de raison, donc l'envoi de l'en-tête HTTP/1.0 403 Form validation errorsest la façon la plus simple de procéder.
aleemb
6
OMI, 422 "Entité non traitable" a beaucoup plus de sens. Mon raisonnement est que ce n'est pas que le serveur refuse de répondre à la demande, c'est que le serveur ne peut pas répondre à la demande.
tybro0103
225

Je recommande le code d'état 422, "Entité non traitable" .

11.2. 422 Entité non traitable

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.

Julian Reschke
la source
11
Bien sûr, il s'agit d'un code d'état HTTP, voir iana.org/assignments/http-status-codes . Il y a plus de codes d'état que ceux définis dans la RFC 2616.
Julian Reschke
7
WebDAV est une extension HTTP . "Extensions HTTP pour la création et la version distribuées sur le Web (WebDAV)" Ainsi, le code d'état 422 n'est pas un code d'état http, mais un code d'état d'extensions de http.
Deamon
16
démon, ça n'a pas de sens. HTTP définit comment définir de nouveaux codes, et c'est ce que fait WebDAV. Il y a un registre de code d'état pour une raison.
Julian Reschke
14
FYI - Description RFC de 422: 11.2. 422 Unprocessable Entity Le code d'état 422 (Unprocessable Entity) signifie que le serveur comprend le type de contenu de l'entité de demande (donc un code d'état 415 (Unsupported Media Type) est inapproprié), et la syntaxe de l'entité de demande est correcte (donc 400 (Bad Request) 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.
Steve Kallestad
6
Et les threads n'expirent pas. Ils doivent être conservés ou les meilleurs résultats de recherche Google commencent à devenir inexacts.
James Billingham
81

200 300, 400, 500 sont tous très génériques. Si vous voulez générique, 400 est OK.

422 est utilisé par un nombre croissant d'API, et est même utilisé par Rails prêt à l'emploi.

Quel que soit le code d'état que vous choisissez pour votre API, quelqu'un sera en désaccord. Mais je préfère 422 parce que je pense que '400 + statut du texte' est trop générique. De plus, vous ne profitez pas d'un analyseur prêt pour JSON; en revanche, un 422 avec une réponse JSON est très explicite, et beaucoup d'informations d'erreur peuvent être transmises.

En parlant de réponse JSON, j'ai tendance à standardiser la réponse d'erreur Rails pour ce cas, qui est:

{
    "errors" :
    { 
        "arg1" : ["error msg 1", "error msg 2", ...]
        "arg2" : ["error msg 1", "error msg 2", ...]
    }
}

Ce format est parfait pour la validation de formulaire, que je considère comme le cas le plus complexe à prendre en charge en termes de «richesse de rapport d'erreurs». Si votre structure d'erreurs est la suivante, elle gérera probablement tous vos besoins de rapport d'erreurs.

sethcall
la source
2
Qu'en est-il des erreurs résultant des interactions entre les arguments. Autrement dit, arg1est valide et arg2est valide, mais la combinaison des deux, avec les valeurs spécifiques envoyées, n'est pas valide.
Jonah
1
Je n'y penserais pas trop; choisissez simplement celui qui semble posséder la relation.
sethcall
ou même simplement une erreur sur les deux arguments. En tant qu'utilisateur, je pense que je voudrais voir l'erreur sur chacun des champs qui sont en conflit, je pense.
blottit
Agréable!. explicite vaut mieux qu'implicite
bhathiya-perera
46

200

Ugh ... (309, 400, 403, 409, 415, 422) ... beaucoup de réponses essayant de deviner, argumenter et standardiser quel est le meilleur code retour pour une requête HTTP réussie mais un appel REST ayant échoué .

C'est mal de mélanger les codes d'état HTTP et les codes d'état REST.

Cependant, j'ai vu de nombreuses implémentations les mélanger, et de nombreux développeurs peuvent ne pas être d'accord avec moi.

Les codes de retour HTTP sont liés à HTTP Requestlui - même. Un appel REST est effectué à l'aide d'une demande de protocole de transfert hypertexte et il fonctionne à un niveau inférieur à la méthode REST invoquée elle-même. REST est un concept / approche, et sa sortie est un résultat métier / logique , tandis que le code de résultat HTTP est un transport .

Par exemple, retourner "404 Not found" lorsque vous appelez / users / est confus, car cela peut signifier:

  • L'URI est incorrect (HTTP)
  • Aucun utilisateur trouvé (REST)

"403 Interdit / Accès refusé" peut signifier:

  • Autorisation spéciale nécessaire. Les navigateurs peuvent le gérer en demandant à l'utilisateur / mot de passe. (HTTP)
  • Autorisations d'accès incorrectes configurées sur le serveur. (HTTP)
  • Vous devez être authentifié (REST)

Et la liste peut continuer avec '500 Server error "(une erreur HTTP Apache / Nginx lancée ou une erreur de contrainte métier dans REST) ​​ou d'autres erreurs HTTP, etc.

À partir du code, il est difficile de comprendre quelle était la raison de l'échec, un échec HTTP (transport) ou un échec REST (logique).

Si la requête HTTP a été exécutée physiquement avec succès, elle doit toujours renvoyer 200 codes, quel que soit le ou les enregistrements trouvés ou non. Parce que la ressource URI est trouvée et a été gérée par le serveur HTTP. Oui, il peut renvoyer un ensemble vide. Est-il possible de recevoir une page Web vide avec 200 comme résultat HTTP, non?

Au lieu de cela, vous pouvez retourner 200 codes HTTP avec quelques options:

  • objet "erreur" dans le résultat JSON en cas de problème
  • Tableau / objet JSON vide si aucun enregistrement trouvé
  • Un indicateur de résultat / succès booléen en combinaison avec les options précédentes pour une meilleure manipulation.

De plus, certains fournisseurs d'accès Internet peuvent intercepter vos demandes et vous renvoyer un code HTTP 404. Cela ne signifie pas que vos données ne sont pas trouvées, mais c'est quelque chose de mal au niveau du transport.

De Wiki :

En juillet 2004, le fournisseur britannique de télécommunications BT Group a déployé le système de blocage de contenu Cleanfeed, qui renvoie une erreur 404 à toute demande de contenu identifié comme potentiellement illégal par Internet Watch Foundation. D'autres FAI renvoient une erreur HTTP 403 "interdite" dans les mêmes circonstances. La pratique consistant à utiliser de fausses erreurs 404 comme moyen de dissimuler la censure a également été signalée en Thaïlande et en Tunisie. En Tunisie, où la censure était sévère avant la révolution de 2011, les gens ont pris conscience de la nature des fausses erreurs 404 et ont créé un personnage imaginaire nommé "Ammar 404" qui représente "la censure invisible".

Pourquoi ne pas simplement répondre avec quelque chose comme ça?

{
  "result": false,
  "error": {"code": 102, "message": "Validation failed: Wrong NAME."}
}

Google renvoie toujours 200 comme code d'état dans son API de géocodage, même si la demande échoue logiquement: https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes

Facebook renvoie toujours 200 pour les demandes HTTP réussies, même si la demande REST échoue: https://developers.facebook.com/docs/graph-api/using-graph-api/error-handling

C'est simple, les codes d'état HTTP sont pour les requêtes HTTP. L'API REST vous appartient, définissez vos codes d'état.

Marcodor
la source
3
En fait, l'utilisation de codes d'état HTTP pour REST est encore plus déroutante sur la route: 1) vous voyez 4xx dans la boîte à outils de votre développeur et vous ne pouvez pas dire en jetant simplement un coup d'œil si le serveur a renvoyé une valeur sensible ou n'a pas du tout traité votre demande puis 2) tous vos gestionnaires d'erreur / d'exception / de capture devraient vérifier quel serveur a renvoyé comme réponse (la plupart du temps ils ne le font pas puisque vous devriez le faire à chaque appel de service) et plusieurs fois 3) vous obtenez la même charge utile ( type) à la fois sur le chemin de réussite et d'erreur menant à un code compliqué / dupliqué ... Très déroutant en effet.
szczepanpp
9
Cette réponse confond la sémantique originale du protocole HTTP et la façon dont REST sur HTTP en tant que style architectural réutilise HTTP pour implémenter les API de service Web. En tant que style architectural, REST n'est pas une norme à suivre rigoureusement, c'est une approche suggérée. L'utilisation d'une réponse 200 pour un échec de validation n'est ni correcte ni erronée, mais il est déroutant pour vos clients de répondre que la demande a abouti, mais a échoué en raison d'un échec de validation, un détail important qui est masqué dans le corps de la réponse, la sémantique que le client doit analyser pour comprendre.
Kevin Hooke
5
@Marcodor si votre appel API échoue mais que vous renvoyez 200 indiquant le succès, en quoi est-ce une bonne idée? c'est peu clair et déroutant pour les consommateurs de votre API.
Kevin Hooke
3
Corrigez pour de nombreuses raisons, pas seulement la séparation des erreurs HTTP vs REST. La validation REST nécessite souvent plus de nuances. Par exemple, enregistrement accepté mais marqué comme doublon ou rejeté pour une violation d'index unique. Vous voulez également un modèle de retour cohérent. La BadRequest()méthode .NET a son propre modèle de retour qui sera différent de votre modèle de retour normal. C'est un cauchemar à analyser. @KevinHooke, renvoyer HTTP 200 pour une erreur de validation REST revient à dire: "J'ai reçu votre message, la réponse est non, et voici pourquoi." Le retour de HTTP 400 dit: "Je ne sais pas de quoi vous parlez."
Neil Laslett
5
l'argument "parce que google le fait, il doit être juste" est fou pour moi..il est ok de contester quelque chose que google a implémenté pour les enfants. Renvoyer HTTP 200 pour un appel de repos infructueux confond l'appelant de l'API, il devrait être 4xx et on peut inclure un joli JSON / XML dans le corps ... permet de stopper la folie ensemble.
Jeryl Cook
43

Un doublon dans la base de données devrait être a 409 CONFLICT.

Je recommande d'utiliser 422 UNPROCESSABLE ENTITYpour les erreurs de validation.

Je donne une explication plus longue des codes 4xx ici .

Phil Parker
la source
6

Le code de statut 304 non modifié donnerait également une réponse acceptable à une demande en double. Cela revient à traiter un en-tête à l' If-None-Matchaide d'une balise d'entité.

À mon avis, la réponse de @ Piskvor est le choix le plus évident de ce que je perçois comme l'intention de la question d'origine, mais j'ai une alternative qui est également pertinente.

Si vous souhaitez traiter une demande en double comme un avertissement ou une notification plutôt que comme une erreur, un code d'état de réponse 304Non modifié etContent-Location tête identifiant la ressource existante seraient tout aussi valides. Lorsque l'intention est simplement de garantir l'existence d'une ressource, une demande en double ne serait pas une erreur mais une confirmation. La demande n'est pas fausse, mais est simplement redondante et le client peut se référer à la ressource existante.

En d'autres termes, la demande est bonne, mais comme la ressource existe déjà, le serveur n'a pas besoin d'effectuer de traitement supplémentaire.

Suncat2000
la source
6
J'ai cru comprendre que 304 est destiné aux opérations GET pour aider à la mise en cache.
Sinaesthetic
6

L'adaptateur ActiveRecord d'Ember-Data s'attend 422 UNPROCESSABLE ENTITYà être renvoyé du serveur. Donc, si votre client est écrit dans Ember.js, vous devez utiliser 422. Seulement alors, DS.Errors sera rempli avec des erreurs renvoyées. Vous pouvez bien sûr remplacer 422 par n'importe quel autre code dans votre adaptateur.

Daniel Kmak
la source
0

406 - Inacceptable

Ce qui signifie que cette réponse est envoyée lorsque le serveur Web, après avoir effectué une négociation de contenu pilotée par le serveur, ne trouve aucun contenu conforme aux critères donnés par l'agent utilisateur.

Hasan Sefa Ozalp
la source