Créer une demande avec POST, dont les codes de réponse 200 ou 201 et le contenu


125

Supposons que j'écris un service REST dont l'intention est d'ajouter un nouvel élément de données à un système.

Je prévois de POSTER sur

http://myhost/serviceX/someResources

Supposons que cela fonctionne, quel code de réponse dois-je utiliser? Et quel contenu pourrais-je retourner.

Je regarde les définitions des codes de réponse HTTP et vois ces possibilités:

200: Renvoie une entité décrivant ou contenant le résultat de l'action;

201: ce qui signifie CRÉÉ. Signification * La demande a été satisfaite et a entraîné la création d'une nouvelle ressource. La ressource nouvellement créée peut être référencée par le ou les URI retournés dans l'entité de la réponse, l'URI le plus spécifique pour la ressource étant donné par un champ d'en-tête Location. La réponse DEVRAIT inclure une entité contenant une liste de caractéristiques de ressources et d'emplacements à partir desquels l'utilisateur ou l'agent d'utilisateur peut choisir celui qui convient le mieux. Le format d'entité est spécifié par le type de média indiqué dans le champ d'en-tête Content-Type. *

Ce dernier semble plus conforme à la spécification Http, mais je ne sais pas du tout quoi

La réponse DEVRAIT inclure une entité contenant une liste de caractéristiques de ressources et d'emplacement (s)

veux dire.

Des recommandations? Interprétations?

Réponses:


78

L'idée est que le corps de la réponse vous donne une page qui vous relie à l'objet:

201 Créé

Le code d'état 201 (Créé) indique que la demande a été satisfaite et a entraîné la création d'une ou plusieurs nouvelles ressources. La ressource principale créée par la demande est identifiée par un champ d'en-tête Location dans la réponse ou, si aucun champ Location n'est reçu, par l'URI de demande effective.

Cela signifie que vous incluez un Locationdans l'en- tête de réponse qui donne l'URL de l'endroit où vous pouvez trouver l' élément nouvellement créé :

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597

Corps de réponse

Ils continuent ensuite en mentionnant ce que vous devez inclure dans le corps de la réponse :

La charge utile de réponse 201 décrit et lie généralement à la ou aux ressources créées.

Pour l'humain qui utilise le navigateur, vous lui donnez quelque chose qu'il peut consulter et cliquez pour accéder à sa ressource nouvellement créée:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: text/html

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

Si la page ne sera utilisée que par un robot, il est logique que la réponse soit lisible par ordinateur:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/xml

<createdResources>
   <questionID>1860645</questionID>
   <answerID>36373586</answerID>
   <primary>/a/36373586/12597</primary>
   <additional>
      <resource>http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586</resource>
      <resource>http://stackoverflow.com/a/1962757/12597</resource>
   </additional>
</createdResource>

Ou, si vous préférez:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/json

{ 
   "questionID": 1860645, 
   "answerID": 36373586,
   "primary": "/a/36373586/12597",
   "additional": [
      "http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586",
      "http://stackoverflow.com/a/36373586/12597"
   ]
}

La réponse dépend entièrement de vous; c'est arbitrairement ce que vous voudriez.

Cache convivial

Enfin, il y a l'optimisation que je peux pré-mettre en cache la ressource créée (car j'ai déjà le contenu; je viens de le télécharger). Le serveur peut renvoyer une date ou un ETag que je peux stocker avec le contenu que je viens de télécharger:

Voir la section 7.2 pour une discussion sur la signification et le but des champs d'en-tête du validateur, tels que ETag et Last-Modified, dans une réponse 201.

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/23704283/12597
Content-Type: text/html
ETag: JF2CA53BOMQGU5LTOQQGC3RAMV4GC3LQNRSS4
Last-Modified: Sat, 02 Apr 2016 12:22:39 GMT 

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

Et les ETags sont des valeurs purement arbitraires. Tout ce qui compte, c'est de les avoir différents lorsqu'une ressource change (et que les caches doivent être mis à jour). L'ETag est généralement un hachage (par exemple SHA2). Mais cela peut être une base de données rowversionou un numéro de révision incrémenté. Tout ce qui changera lorsque la chose changera.


Jusqu'à présent, votre réponse semble la plus raisonnable. Je suis un peu inquiet au sujet de l'ontologie de la réponse, mais à part cela, cela semble être l'interprétation la plus mature de la spécification. Je suis curieux de savoir s'il existe une sorte de moyen "réactif" léger pour gérer la sortie humaine / machine. mais je suis surtout intrigué par votre suggestion de "mettre en cache votre propre entrée". La plupart des applications Web que je connais ne créeront pas une version 1: 1 de la ressource. Même si c'est quelque chose de trivial comme normaliser la capitalisation d'une chaîne. N'est-il pas un peu douteux de traiter votre version soumise comme la version contre laquelle etag a été créé?
Anthony

1
@Anthony, mise en cache: cela pourrait être une sorte d'application de stockage de fichiers 1: 1. Comparez par exemple WebDAV PUT & POST. D'énormes fichiers à gérer.
kxr

@Anthony C'est à vous de décider si vous souhaitez renvoyer un ETag au client. Si le contenu que le client vient de télécharger n'est pas celui que vous avez enregistré, ne renvoyez pas l'ETag. C'est votre flexibilité et votre choix.
Ian Boyd

Pourquoi vos réponses ne contiennent pas Content-Length?
Vinnie Falco le

1
@VinnieFalco Ceci est une réponse sur le code de réponse 201. Content-Length a été élidé à des fins d’exposition.
Ian Boyd

91

Je pense que l'API REST atompub est un excellent exemple de service reposant. Voir l'extrait ci-dessous de la spécification atompub:

POST /edit/ HTTP/1.1
Host: example.org
User-Agent: Thingio/1.0
Authorization: Basic ZGFmZnk6c2VjZXJldA==
Content-Type: application/atom+xml;type=entry
Content-Length: nnn
Slug: First Post

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
</entry>

Le serveur signale une création réussie avec un code d'état de 201. La réponse comprend un en-tête Location indiquant l'URI d'entrée de membre de l'entrée Atom, et une représentation de cette entrée dans le corps de la réponse.

HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content-Length: nnn
Content-Type: application/atom+xml;type=entry;charset="utf-8"
Location: http://example.org/edit/first-post.atom
ETag: "c180de84f991g8"  

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
  <link rel="edit"
      href="http://example.org/edit/first-post.atom"/>
</entry>

L'entrée créée et renvoyée par la collection peut ne pas correspondre à l'entrée publiée par le client. Un serveur PEUT changer les valeurs de divers éléments dans l'entrée, tels que les valeurs atom: id, atom: updated et atom: author, et PEUT choisir de supprimer ou d'ajouter d'autres éléments et attributs, ou de changer le contenu des éléments et les valeurs d'attributs.


9
Renvoyer la ressource créée peut être un peu trop, si la ressource est de l'ordre du gigaoctet ...
Tor Valamo

10
D'accord! C'est l'optimisation de la nécessité - mais vous ne voulez pas le faire prématurément. Il est important de concevoir dans des esprits reposants et de faire des exceptions uniquement lorsque cela est nécessaire.
Chandra Patni

3
@ChandraPatni, Atom est mort . Besoin de meilleurs exemples.
Pacerier

16
Atom est peut-être mort, mais l'esprit de l'exemple est toujours parfait.
Ashimema

2
Mon interprétation originale de la réponse 201 ressemblait plus à "hé, vous vouliez créer une ressource, mais en fonction du contexte, vous n'étiez pas intéressé par le résultat final ou vous disposiez d'un accès en écriture mais pas en lecture à cette ressource. cas, tout ce dont vous avez besoin avant de retourner à la collection principale est l'URL de la ressource créée. Comme preuve de sa création. " Tout ce qui dépasse cela semble être une réponse de 200, essentiellement. À moins que la RFC n'ait autre chose en tête.
Anthony

50

En quelques mots:

  • 200 lorsqu'un objet est créé et renvoyé
  • 201 lorsqu'un objet est créé mais que seule sa référence est renvoyée (comme un identifiant ou un lien)

Source pour cela?
sudo soul


3
Après avoir lu tools.ietf.org/html/rfc7231#section-6.3.1 , je suis d'accord avec cette compréhension - je suppose que je demandais plus comment vous y êtes arrivé. Mais maintenant dans ma compréhension ... 200 = ressource créée et retournée | 201 = ressource créée et référence est retournée | 204 = ressource créée et aucune charge utile retournée
sudo soul

34

Consultez HTTP: définitions de méthode: POST .

L'action effectuée par la méthode POST peut ne pas aboutir à une ressource identifiable par un URI. Dans ce cas, 200 (OK) ou 204 (Pas de contenu) est le statut de réponse approprié, selon que la réponse inclut ou non une entité qui décrit le résultat.

Si une ressource a été créée sur le serveur d'origine, la réponse DEVRAIT être 201 (Créé) et contenir une entité qui décrit l'état de la demande et se réfère à la nouvelle ressource, et un en-tête Location (voir la section 14.30).


18

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19

C'est juste une valeur-clé délimitée par deux points.

ETag: "xyzzy"

Il peut s'agir de n'importe quel type de données texte - j'inclus généralement une chaîne JSON avec l'identifiant de l'élément créé. La facilité des tests à elle seule en vaut la peine.

ETag: "{ id: 1234, uri: 'http://domain.com/comments/1234', type: 'comment' }"

Dans cet exemple, l'identifiant, l'URI et le type de l'élément créé sont les «caractéristiques et emplacement de la ressource».


3
Vous dites qu'un ETag correspond à une entité contenant une liste de caractéristiques de ressources et d'emplacement (s) . Je peux voir que votre suggestion est bonne, tout à fait d'accord avec votre point de vue sur les tests. Cependant, je ne vois pas comment cela correspond à «une liste de caractéristiques et d'emplacements de ressources».
djna

La «liste des caractéristiques et emplacements des ressources» serait le contenu de toute structure de données fournie. Une implémentation plus stricte serait que la structure JSON inclue l'URI de la ressource et peut-être le type de ressource qui a été créée. Je vais ajuster la réponse en tant que telle.
tempire

7
Précisez les problèmes afin que les gens puissent apprendre. Sinon, le commentaire est juste un signe de la main.
tempire

@SimonGibbs Quels problèmes?
MEMark

2
Bien que ce soit strictement correct selon les spécifications, il recommande une option de mise en œuvre très inhabituelle. De plus, il ne répond pas réellement à la question en haut de la page (ou bien il le fait en mélangeant les mots ETag et entité). La réponse avec 43 voix est probablement meilleure.
Simon Gibbs

1

La sortie dépend en fait du type de contenu demandé. Cependant, au minimum, vous devez placer la ressource créée dans Location. Tout comme le modèle Post-Redirect-Get.

Dans mon cas, je laisse ce champ vide jusqu'à ce que cela soit demandé autrement. Puisque c'est le comportement de JAX-RS lors de l'utilisation de Response.created ().

Cependant, notez simplement que les navigateurs et les frameworks comme Angular ne suivent pas automatiquement les 201. J'ai noté le comportement dans http://www.trajano.net/2013/05/201-created-with-angular-resource/


-2

Une autre réponse que j'aurais pour cela serait d'adopter une approche pragmatique et de conserver votre contrat d'API REST simple. Dans mon cas, j'avais refactorisé mon API REST pour rendre les choses plus testables sans recourir à JavaScript ou XHR, juste de simples formulaires et liens HTML.

Donc, pour être plus précis sur votre question ci-dessus, j'utiliserais simplement le code de retour 200 et sorte que le message retourné contienne un message JSON que votre application peut comprendre. En fonction de vos besoins, il peut nécessiter l'ID de l'objet nouvellement créé afin que l'application Web puisse obtenir les données dans un autre appel.

Une note, dans mon contrat d'API refactorisé, les réponses POST ne doivent contenir aucune donnée pouvant être mise en cache car les POST ne sont pas vraiment cachable, alors limitez-le aux ID qui peuvent être demandés et mis en cache à l'aide d'une requête GET.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.