PUT vs POST dans REST

5377

Selon la spécification HTTP / 1.1:

La POSTméthode est utilisée pour demander que le serveur d'origine accepte l'entité incluse dans la demande en tant que nouveau subordonné de la ressource identifiée par le Request-URIdans leRequest-Line

En d'autres termes, POSTest utilisé pour créer .

La PUTméthode demande que l'entité incluse soit stockée sous le fourni Request-URI. Si le Request-URIfait référence à une ressource déjà existante, l'entité incluse DEVRAIT être considérée comme une version modifiée de celle résidant sur le serveur d'origine. Si le Request-URIne pointe pas vers une ressource existante et que cet URI peut être défini comme une nouvelle ressource par l'agent utilisateur demandeur, le serveur d'origine peut créer la ressource avec cet URI. "

Autrement dit, PUTest utilisé pour créer ou remplacer .

Alors, lequel devrait être utilisé pour créer une ressource? Ou faut-il soutenir les deux?

alex
la source
56
Il peut être utile d'utiliser les définitions dans HTTPbis - Roy a mis beaucoup de travail à les clarifier. Voir: tools.ietf.org/html/…
Mark Nottingham
16
Juste pour apporter le commentaire de @ MarkNottingham à la dernière révision, voici POST et PUT , comme défini sur HTTPbis.
Marius Butuc
38
Il me semble que ce débat est né de la pratique courante de simplification excessive de REST en décrivant les méthodes HTTP en termes d'opérations CRUD.
Stuporman
5
Malheureusement, les premières réponses sont fausses à propos de POST. Consultez ma réponse pour une meilleure explication des différences: stackoverflow.com/a/18243587/2458234
7hi4g0
23
PUT et POST sont deux méthodes dangereuses. Cependant, PUT est idempotent, alors que POST ne l'est pas. - Voir plus sur: restcookbook.com/HTTP%20Methods/put-vs-post/…
Dinesh Saini

Réponses:

4240

Global:

PUT et POST peuvent être utilisés pour la création.

Vous devez demander "à quoi effectuez-vous l'action?" pour distinguer ce que vous devez utiliser. Supposons que vous concevez une API pour poser des questions. Si vous souhaitez utiliser POST, vous le feriez pour une liste de questions. Si vous souhaitez utiliser PUT, vous le feriez pour une question particulière.

Les deux peuvent être utilisés, alors lequel dois-je utiliser dans ma conception RESTful:

Vous n'avez pas besoin de prendre en charge PUT et POST.

Ce qui est utilisé vous appartient. Mais n'oubliez pas d'utiliser le bon en fonction de l'objet auquel vous faites référence dans la demande.

Quelques considérations:

  • Donnez-vous un nom aux objets URL que vous créez explicitement ou laissez-vous le serveur décider? Si vous les nommez, utilisez PUT. Si vous laissez le serveur décider, utilisez POST.
  • PUT est idempotent, donc si vous METTEZ un objet deux fois, cela n'a aucun effet. Ceci est une belle propriété, donc j'utiliserais PUT lorsque cela est possible.
  • Vous pouvez mettre à jour ou créer une ressource avec PUT avec la même URL d'objet
  • Avec POST, vous pouvez avoir 2 demandes en même temps apportant des modifications à une URL, et elles peuvent mettre à jour différentes parties de l'objet.

Un exemple:

J'ai écrit ce qui suit dans le cadre d'une autre réponse sur SO à ce sujet :

PUBLIER:

Utilisé pour modifier et mettre à jour une ressource

POST /questions/<existing_question> HTTP/1.1
Host: www.example.com/

Notez que ce qui suit est une erreur:

POST /questions/<new_question> HTTP/1.1
Host: www.example.com/

Si l'URL n'est pas encore créée, vous ne devez pas utiliser POST pour la créer lors de la spécification du nom. Cela devrait entraîner une erreur «ressource introuvable» car <new_question>n'existe pas encore. Vous devez d'abord METTRE la <new_question> ressource sur le serveur.

Vous pouvez cependant faire quelque chose comme ça pour créer des ressources en utilisant POST:

POST /questions HTTP/1.1
Host: www.example.com/

Notez que dans ce cas, le nom de la ressource n'est pas spécifié, le nouveau chemin d'URL des objets vous sera retourné.

METTRE:

Utilisé pour créer une ressource ou la remplacer. Pendant que vous spécifiez la nouvelle URL des ressources.

Pour une nouvelle ressource:

PUT /questions/<new_question> HTTP/1.1
Host: www.example.com/

Pour remplacer une ressource existante:

PUT /questions/<existing_question> HTTP/1.1
Host: www.example.com/

De plus, et un peu plus concis, la RFC 7231 Section 4.3.4 PUT déclare (non souligné dans l'original),

4.3.4. METTRE

La méthode PUT demande que l'état de la ressource cible soit createdou replacedavec l'état défini par la représentation incluse dans la charge utile du message de demande.

Brian R. Bondy
la source
1027
Je pense que l'on ne peut pas assez insister sur le fait que PUT est idempotent: si le réseau est bâclé et que le client n'est pas sûr de savoir si sa demande a abouti, il peut simplement l'envoyer une seconde (ou 100e) fois, et il est garanti par le Spécification HTTP que cela a exactement le même effet que d'envoyer une fois.
Jörg W Mittag
77
@ Jörg W Mittag: Pas nécessaire. La deuxième fois pourrait renvoyer un conflit 409 ou quelque chose si la demande a été modifiée entre-temps (par un autre utilisateur ou la première demande elle-même, qui a abouti).
Mitar
633
Si je ne me trompe pas, ce que nous devrions souligner, c'est que PUT est défini comme étant idempotent. Vous devez encore écrire votre serveur de telle manière que PUT se comporte correctement, oui? Il vaut peut-être mieux dire "PUT fait en sorte que le transport assume l'idempotence, ce qui peut affecter le comportement du transport, par exemple la mise en cache".
Ian Ni-Lewis
151
@ JörgWMittag Idempotence slogan? Que diriez-vous "Envoyer et envoyer et envoyer mon ami, cela ne fait aucune différence à la fin."
James Beninger
39
Les pense comme: PUT = insérer ou mettre à jour; POST = insérer. Ainsi, lorsque vous effectuez deux PUT - vous obtenez le seul nouvel enregistrement, lorsque vous effectuez deux POST - vous obtenez deux nouveaux enregistrements.
Eugen Konkov
2218

Vous pouvez trouver des affirmations sur le Web qui disent

Ni l'un ni l'autre n'a tout à fait raison.


Mieux vaut choisir entre PUT et POST en fonction de l' idempotence de l'action.

PUT implique de mettre une ressource - en remplaçant complètement tout ce qui est disponible à l'URL donnée par une chose différente. Par définition, un PUT est idempotent. Faites-le autant de fois que vous le souhaitez et le résultat est le même. x=5est idempotent. Vous pouvez METTRE une ressource qu'elle existe ou non (par exemple, pour créer ou mettre à jour)!

POST met à jour une ressource, ajoute une ressource subsidiaire ou provoque une modification. Un POST n'est pas idempotent, de la même manière qu'il x++n'est pas idempotent.


Par cet argument, PUT sert à créer lorsque vous connaissez l'URL de la chose que vous allez créer. POST peut être utilisé pour créer lorsque vous connaissez l'URL de la «fabrique» ou du gestionnaire pour la catégorie de choses que vous souhaitez créer.

donc:

POST /expense-report

ou:

PUT  /expense-report/10929
Cheeso
la source
72
Je suis d'accord, où que ce soit l'idempotence, cela devrait l'emporter sur toute autre préoccupation, car se tromper peut provoquer de nombreux bugs inattendus.
Josh
16
Si POST peut mettre à jour une ressource, comment cela n'est-il pas idempotent? Si je change l'âge d'un élève en utilisant PUT et que je le fais 10 fois, l'âge des élèves est le même si je le fais une fois.
Jack Ukleja
28
@Schneider, dans ce cas, votre serveur fait un effort supplémentaire pour garantir l'idempotence, mais il n'en fait pas la publicité. Les navigateurs avertiront toujours l'utilisateur s'ils tentent de recharger une telle demande POST.
Tobu
47
@Schneider POST peut créer une ressource subsidiaire; par conséquent, vous pouvez POST à ​​la collecte, comme POST / notes de frais et cela créerait autant d'entités (notes de frais) sur votre serveur que la quantité de demandes que vous avez envoyées, même si elles sont complètement similaires. Considérez-le comme l'insertion de la même ligne dans la table DB (/ notes de dépenses) avec la clé primaire auto-incrémentée. Les données restent les mêmes, la clé (l'URI dans ce cas) est générée par le serveur et est différente pour chaque autre insert (demande). Ainsi, l'effet POST peut être idempotent, mais peut-être pas. Par conséquent, POST n'est pas idempotent.
Snifff
11
Disons que nous avons des entités qui peuvent avoir deux propriétés - nameet date. Si nous avons une entité avec un existant nameet date, mais que nous lui demandons ensuite en spécifiant seulement un name, le bon comportement de PUT serait d'effacer le datede l'entité, alors que POST peut mettre à jour uniquement les propriétés spécifiées, en laissant les propriétés non spécifiées telles qu'elles étaient avant la demande. Est-ce que cela semble correct / raisonnable, ou s'agit-il d'une mauvaise utilisation de PUT (j'ai vu des références à PATCH , ce qui semble être plus approprié, mais n'existe pas encore)?
Jon z
707
  • POST vers une URL crée une ressource enfant sur une URL définie par le serveur .
  • PUT vers une URL crée / remplace la ressource dans son intégralité à l' URL définie par le client .
  • PATCH vers une URL met à jour une partie de la ressource à cette URL définie par le client.

La spécification pertinente pour PUT et POST est RFC 2616 §9.5ff.

POST crée une ressource enfant , donc POST /itemscrée des ressources qui vivent sous la /itemsressource. Par exemple. /items/1. L'envoi du même post-paquet deux fois créera deux ressources.

PUT sert à créer ou à remplacer une ressource à une URL connue du client .

Par conséquent: PUT est uniquement un candidat pour CREATE où le client connaît déjà l'URL avant la création de la ressource. Par exemple. /blogs/nigel/entry/when_to_use_post_vs_putcar le titre est utilisé comme clé de ressource

PUT remplace la ressource à l'url connue si elle existe déjà, donc envoyer deux fois la même demande n'a aucun effet. En d'autres termes, les appels à PUT sont idempotents .

Le RFC se lit comme suit:

La différence fondamentale entre les requêtes POST et PUT se reflète dans la signification différente de l'URI de demande. L'URI dans une demande POST identifie la ressource qui gérera l'entité incluse. Cette ressource peut être un processus d'acceptation de données, une passerelle vers un autre protocole ou une entité distincte qui accepte les annotations. En revanche, l'URI dans une demande PUT identifie l'entité jointe à la demande - l'agent utilisateur sait quel URI est prévu et le serveur NE DOIT PAS tenter d'appliquer la demande à une autre ressource. Si le serveur souhaite que la demande soit appliquée à un URI différent,

Remarque: PUT a été principalement utilisé pour mettre à jour les ressources (en les remplaçant dans leur intégralité), mais récemment, on s'oriente vers l'utilisation de PATCH pour mettre à jour les ressources existantes, car PUT spécifie qu'il remplace la ressource entière. RFC 5789.

Mise à jour 2018 : il y a un cas qui peut être fait pour éviter le PUT. Voir "REST sans PUT"

Avec la technique «REST without PUT», l'idée est que les consommateurs sont obligés de publier de nouvelles ressources de demande «non annoncées». Comme indiqué précédemment, la modification de l'adresse postale d'un client est un POST vers une nouvelle ressource «ChangeOfAddress», et non un PUT d'une ressource «Client» avec une valeur de champ d'adresse postale différente.

extrait de REST API Design - Modélisation des ressources par Prakash Subramaniam de Thoughtworks

Cela oblige l'API à éviter les problèmes de transition d'état avec plusieurs clients mettant à jour une seule ressource, et correspond mieux avec le sourcing d'événements et le CQRS. Lorsque le travail est effectué de manière asynchrone, POSTER la transformation et attendre qu'elle soit appliquée semble approprié.

Nigel Thorne
la source
53
Ou de l'autre côté de la clôture: PUT si le client détermine l'adresse de la ressource résultante, POST si le serveur le fait.
DanMan
3
Je pense que cette réponse devrait être modifiée pour rendre plus clair ce que @DanMan a montré d'une manière très simple. Ce que je trouve le plus précieux ici est la note à la fin, indiquant qu'un PUT ne doit être utilisé que pour remplacer la ressource entière.
Hermes
3
PATCH n'est pas une option réaliste pendant au moins quelques années, mais je suis d'accord avec l'idéologie.
écraser
4
J'essaie de comprendre, mais utiliser PUT pour créer quelque chose n'aurait de sens que si le client sait avec certitude que la ressource n'existe pas encore, non? En suivant l'exemple du blog, disons que vous avez créé des centaines de billets de blog en quelques années, puis choisissez accidentellement le même titre que vous l'avez fait pour un message il y a deux ans. Maintenant, vous êtes allé remplacer ce poste, qui n'était pas prévu. Donc, utiliser PUT pour créer obligerait le client à suivre ce qui est pris et ce qui ne l'est pas, et pourrait entraîner des accidents et des effets secondaires imprévus, ainsi que des itinéraires qui font deux choses complètement différentes?
galaxyAbstractor
5
Vous avez raison. METTRE un article de blog à la même URL qu'un article existant entraînerait une mise à jour de cet article existant (bien que vous puissiez évidemment vérifier d'abord avec un GET). Cela indique pourquoi ce serait une mauvaise idée d'utiliser uniquement le titre comme URL. Cela fonctionnerait cependant partout où il y avait une clé naturelle dans les données ... ce qui, selon mon expérience, est rare. Ou si vous avez utilisé des GUID
Nigel Thorne
221

Sommaire:

Créer:

Peut être effectué avec PUT ou POST de la manière suivante:

METTRE

Crée LA nouvelle ressource avec newResourceId comme identifiant, sous l'URI / resources ou collection .

PUT /resources/<newResourceId> HTTP/1.1 

PUBLIER

Crée une nouvelle ressource sous l'URI / resources, ou collection . Habituellement, l'identifiant est renvoyé par le serveur.

POST /resources HTTP/1.1

Mise à jour:

Ne peut être exécuté avec PUT que de la manière suivante:

METTRE

Met à jour la ressource avec existingResourceId comme identificateur, sous l'URI / resources ou collection .

PUT /resources/<existingResourceId> HTTP/1.1

Explication:

Lorsque vous traitez REST et URI en général, vous avez générique à gauche et spécifique à droite . Les génériques sont généralement appelés collections et les éléments plus spécifiques peuvent être appelés ressource . Notez qu'une ressource peut contenir une collection .

Exemples:

<- générique - spécifique ->

URI: website.com/users/john
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource

URI:website.com/users/john/posts/23
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource
posts        - collection of posts from john
23           - post from john with identifier 23, also a resource

Lorsque vous utilisez POST, vous vous référez toujours à une collection , donc chaque fois que vous dites:

POST /users HTTP/1.1

vous publiez un nouvel utilisateur dans la collection d' utilisateurs .

Si vous continuez et essayez quelque chose comme ceci:

POST /users/john HTTP/1.1

cela fonctionnera, mais sémantiquement vous dites que vous voulez ajouter une ressource à la collection john sous la collection users .

Une fois que vous utilisez PUT, vous vous référez à une ressource ou à un élément unique, éventuellement à l'intérieur d'une collection . Donc, quand vous dites:

PUT /users/john HTTP/1.1

vous dites à la mise à jour du serveur, ou créez si elle n'existe pas, la ressource john sous la collection users .

Spec:

Permettez-moi de souligner certaines parties importantes de la spécification:

PUBLIER

La méthode POST est utilisée pour demander au serveur d'origine d' accepter l'entité incluse dans la demande en tant que nouveau subordonné de la ressource identifiée par l'URI de demande dans la ligne de demande.

Par conséquent, crée une nouvelle ressource sur une collection .

METTRE

La méthode PUT demande que l'entité incluse soit stockée sous l'URI de demande fourni. Si l'URI de demande fait référence à une ressource déjà existante , l'entité incluse DEVRAIT être considérée comme une version modifiée de celle résidant sur le serveur d'origine. Si l'URI de demande ne pointe pas vers une ressource existante et que cet URI peut être défini comme une nouvelle ressource par l'agent utilisateur demandeur, le serveur d'origine peut créer la ressource avec cet URI. "

Par conséquent, créez ou mettez à jour en fonction de l'existence de la ressource .

Référence:

7hi4g0
la source
11
Ce message m'a aidé à comprendre que POST ajoute "quelque chose" en tant qu'enfant à la collection donnée (URI), tandis que PUT définit explicitement le "quelque chose" à l'emplacement URI donné.
kwah
3
C'est la meilleure réponse, ici, je pense: rien de tout cela "POST peut mettre à jour une ressource" un non-sens. J'aime votre déclaration, "La mise à jour ne peut être effectuée qu'avec PUT".
Thomas
4
Non, PUT n'est pas destiné à être mis à jour ou créé. C'est pour remplacer. Notez que vous ne pouvez rien remplacer par quelque chose pour l'effet de créer.
thecoshman
2
@ 7hi4g0 PUT est destiné à la mise à jour avec un remplacement complet, en d'autres termes, il remplace. Vous ne remplacez rien par quelque chose, ou quelque chose par quelque chose de complètement nouveau. PUT n'est pas destiné à apporter une modification mineure (à moins que le client n'effectue cette modification mineure et fournisse la nouvelle version entière, même ce qui reste le même). Pour une modification partielle, PATCH est la méthode de choix.
thecoshman
1
@thecoshman Vous pourriez, mais il ne serait pas trop clair que la création y soit également couverte. Dans ce cas, il vaut mieux être explicite.
7hi4g0
175

POST signifie "créer un nouveau" comme dans "Voici l'entrée pour créer un utilisateur, créez-le pour moi".

PUT signifie "insérer, remplacer s'il existe déjà" comme dans "Voici les données pour l'utilisateur 5".

Vous POSTà example.com/users puisque vous ne connaissez pas encore l' URLutilisateur, vous voulez que le serveur le crée.

Vous PUTà example.com/users/id puisque vous souhaitez remplacer / créer un utilisateur spécifique .

POSTER deux fois avec les mêmes données signifie créer deux utilisateurs identiques avec des identifiants différents. PUT deux fois avec les mêmes données crée l'utilisateur le premier et le met à jour au même état la deuxième fois (pas de changement). Puisque vous vous retrouvez avec le même état après un PUTnombre de fois que vous l'exécutez, il est dit à chaque fois "tout aussi puissant" - idempotent. Ceci est utile pour réessayer automatiquement les demandes. Vous n'êtes plus sûr de vouloir renvoyer lorsque vous appuyez sur le bouton de retour du navigateur.

Un conseil général est à utiliser POSTlorsque vous avez besoin que le serveur contrôle la URLgénération de vos ressources. Utilisez PUTautrement. Préférez PUT plus POST.

Alexander Torstling
la source
12
La négligence peut avoir pour conséquence qu'il est communément enseigné qu'il n'y a que deux verbes dont vous avez besoin: GET et POST. OBTENIR pour obtenir, POST pour changer. Même PUT et DELETE ont été effectuées à l'aide de POST. Demander ce que PUT signifie vraiment 25 ans plus tard peut-être un signe que nous l'avons mal compris au début. La popularité de REST a ramené les gens à l'essentiel où nous devons maintenant désapprendre les mauvaises erreurs passées. Le POST était surutilisé et maintenant couramment enseigné de manière incorrecte. Meilleure partie: "POSTER deux fois avec les mêmes données signifie créer deux [ressources] identiques". Bon point!
maxpolk
1
Comment pouvez-vous utiliser PUT pour créer un enregistrement par l'ID, comme dans votre exemple user 5s'il n'existe pas encore? Tu ne veux pas dire update, replace if already exists? ou quelque chose
Luke
@Coulton: Je voulais dire ce que j'ai écrit. Vous insérez l'utilisateur 5 si vous placez / utilisateurs / 5 et # 5 n'existe pas encore.
Alexander Torstling
@Coulton: Et PUTpeut également être utilisé pour remplacer la valeur d'une ressource existante dans son intégralité.
DavidRR
1
"Préférez PUT plutôt que POST" ... vous voulez justifier cela?
thecoshman
173

Je voudrais ajouter mon conseil "pragmatique". Utilisez PUT lorsque vous connaissez l '"id" par lequel l'objet que vous enregistrez peut être récupéré. L'utilisation de PUT ne fonctionnera pas trop bien si vous avez besoin, par exemple, d'un identifiant généré par la base de données à renvoyer pour que vous puissiez effectuer des recherches ou des mises à jour futures.

Donc: pour enregistrer un utilisateur existant, ou celui où le client génère l'ID et il a été vérifié que l'ID est unique:

PUT /user/12345 HTTP/1.1  <-- create the user providing the id 12345
Host: mydomain.com

GET /user/12345 HTTP/1.1  <-- return that user
Host: mydomain.com

Sinon, utilisez POST pour créer initialement l'objet et PUT pour mettre à jour l'objet:

POST /user HTTP/1.1   <--- create the user, server returns 12345
Host: mydomain.com

PUT /user/12345 HTTP/1.1  <--- update the user
Host: mydomain.com
ThaDon
la source
17
En fait, ça devrait l'être POST /users. (Notez qu'il /usersest au pluriel.) Cela a pour effet de créer un nouvel utilisateur et d'en faire une ressource enfant de la /userscollection.
DavidRR
6
@DavidRR pour être juste, comment gérer les groupes est un autre débat. GET /usersest logique, il se lit comme vous le souhaitez, mais je serais d'accord avec GET /user/<id>ou POST /user(avec la charge utile pour ledit nouvel utilisateur) car il lit correctement `` get me users 5 '' est étrange, mais `` get me user 5 '' est plus naturel. Je tomberais probablement toujours du côté de la pluralisation cependant :)
thecoshman
126

Utilisez POST pour créer et PUT pour mettre à jour. Voilà comment Ruby on Rails le fait, de toute façon.

PUT    /items/1      #=> update
POST   /items        #=> create
Tim Sullivan
la source
4
POST /itemsajoute un nouvel élément à une ressource déjà définie («élément»). Il ne s'agit pas, comme le dit la réponse, de "créer un groupe". Je ne comprends pas pourquoi cela a 12 voix.
David J.21
Par défaut, Rails ne prend pas en charge la «création d'un groupe» via REST. Pour «créer un groupe», je veux dire «créer une ressource», vous devez le faire via le code source.
David J.21
8
Il s'agit d'une ligne directrice juste, mais d'une simplification excessive. Comme les autres réponses le mentionnent, l'une ou l'autre méthode peut être utilisée à la fois pour créer et mettre à jour.
Brad Koch
2
Je suis d'accord avec la réponse avec une légère modification. Utilisez POST pour créer et PUT pour mettre à jour complètement la ressource. Pour les mises à jour partielles, nous pouvons utiliser PUT ou PATCH. Disons que nous voulons mettre à jour le statut d'un groupe. Nous pouvons utiliser PUT / groups / 1 / status avec le statut est la charge utile de la demande ou PATCH / groups / 1 avec les détails de l'action dans la charge utile
java_geek
2
Il convient également de préciser que cela PUT /items/42est également valable pour la création d' une ressource, mais uniquement si le client a le privilège de nommer la ressource . (Est-ce que Rails
accorde
123

Les deux sont utilisés pour la transmission de données entre le client et le serveur, mais il existe de subtiles différences entre eux, qui sont:

Entrez la description de l'image ici

Analogie:

  • PUT c'est à dire prendre et mettre où il était.
  • POST comme envoyer du courrier au bureau de poste.

entrez la description de l'image ici

Analogie des réseaux sociaux / réseaux:

  • Publier sur les réseaux sociaux: lorsque nous publions un message, cela crée un nouveau message.
  • Mettez (c'est-à-dire modifier) ​​pour le message que nous avons déjà publié.
Premraj
la source
21
@MobileMon Non, les méthodes REST ne sont pas CRUD.
jlr
1
Je dirais PUT pour UPSERTS
Hola Soy Edu Feliz Navidad
@MobileMon no: POSTEZ lorsque vous créez une nouvelle ressource et que vous ne connaissez pas le point final pour l'obtenir. PUT pour les autres cas.
Portekoi
67

REST est un concept de très haut niveau. En fait, il ne mentionne même pas du tout HTTP!

Si vous avez des doutes sur la façon d'implémenter REST dans HTTP, vous pouvez toujours jeter un œil à la spécification Atom Publication Protocol (AtomPub) . AtomPub est un standard pour l'écriture de services Web RESTful avec HTTP qui a été développé par de nombreux luminaires HTTP et REST, avec une contribution de Roy Fielding, l'inventeur de REST et (co-) inventeur de HTTP lui-même.

En fait, vous pourriez même être en mesure d'utiliser directement AtomPub. Bien qu'il soit issu de la communauté des blogueurs, il n'est en aucun cas limité aux blogs: c'est un protocole générique pour interagir RESTfully avec des collections arbitraires (imbriquées) de ressources arbitraires via HTTP. Si vous pouvez représenter votre application comme une collection imbriquée de ressources, vous pouvez simplement utiliser AtomPub et ne pas vous soucier d'utiliser PUT ou POST, les codes d'état HTTP à renvoyer et tous ces détails.

Voici ce qu'AtomPub a à dire sur la création de ressources (section 9.2):

Pour ajouter des membres à une collection, les clients envoient des requêtes POST à ​​l'URI de la collection.

Jörg W Mittag
la source
8
Il n'y a rien de mal à autoriser PUT à créer des ressources. Sachez simplement que cela signifie que le client fournit l'URL.
Julian Reschke
5
Il y a quelque chose de très mal à autoriser PUT à créer des ressources: le client fournit l'URL. C'est le travail du serveur!
Joshcodes
@Joshcodes Il n'est pas toujours vrai que le travail du serveur consiste à créer des identifiants client. J'ai vu de plus en plus de conceptions qui permettent aux clients de générer une sorte d'UUID comme identifiant de ressource. Cette conception se prête notamment à augmenter l'échelle.
Justin Ohms
@JustinOhms Je suis d'accord avec votre point sur les identifiants générés par le client (note latérale: tous les systèmes conçus par moi depuis environ 2008 exigent que le client crée l'identifiant en tant qu'UUID / Guid). Cela ne signifie pas que le client doit spécifier l'URL.
Joshcodes
1
Oui, si la ressource existe déjà, utilisez PUT. Cependant, dans presque tous les cas, les ressources doivent être créées avec POST et le client ne doit pas fournir l'URL. Roy Fielding est d'accord avec cette déclaration FWIW: roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
Joshcodes
61

La décision d'utiliser PUT ou POST pour créer une ressource sur un serveur avec une API HTTP + REST est basée sur le propriétaire de la structure URL. La connaissance ou la participation du client à la définition de la structure de l'URL est un couplage inutile semblable aux couplages indésirables résultant de SOA. Les types de raccords d'échappement sont la raison pour laquelle REST est si populaire. Par conséquent, la méthode appropriée à utiliser est POST. Il existe des exceptions à cette règle et elles se produisent lorsque le client souhaite conserver le contrôle de la structure de localisation des ressources qu'il déploie. C'est rare et signifie probablement que quelque chose d'autre ne va pas.

À ce stade, certaines personnes diront que si des URL RESTful sont utilisées, le client connaît l'URL de la ressource et donc un PUT est acceptable. Après tout, c'est pourquoi les URL canoniques, normalisées, Ruby on Rails, Django sont importantes, regardez l'API Twitter… bla bla bla. Ces personnes doivent comprendre qu'il n'y a pas d'URL reposante et que Roy Fielding lui-même déclare que :

Une API REST ne doit pas définir de noms ou de hiérarchies de ressources fixes (un couplage évident entre client et serveur). Les serveurs doivent avoir la liberté de contrôler leur propre espace de noms. Au lieu de cela, autorisez les serveurs à indiquer aux clients comment construire des URI appropriés, comme cela se fait dans les formulaires HTML et les modèles d'URI, en définissant ces instructions dans les types de médias et les relations de liaison. [L'échec ici implique que les clients supposent une structure de ressources en raison d'informations hors bande, comme une norme spécifique au domaine, qui est l'équivalent orienté données du couplage fonctionnel de RPC].

http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

L'idée d'une URL RESTful est en fait une violation de REST car le serveur est responsable de la structure de l'URL et devrait être libre de décider comment l'utiliser pour éviter le couplage. Si cela vous embrouille, lisez l'importance de la découverte de soi sur la conception d'API.

L'utilisation de POST pour créer des ressources s'accompagne d'une considération de conception car POST n'est pas idempotent. Cela signifie que la répétition d'un POST plusieurs fois ne garantit pas le même comportement à chaque fois. Cela fait peur aux gens d'utiliser PUT pour créer des ressources alors qu'ils ne devraient pas. Ils savent que c'est faux (POST est pour CREATE) mais ils le font quand même parce qu'ils ne savent pas comment résoudre ce problème. Cette préoccupation se manifeste dans la situation suivante:

  1. Le client POST une nouvelle ressource sur le serveur.
  2. Le serveur traite la demande et envoie une réponse.
  3. Le client ne reçoit jamais la réponse.
  4. Le serveur ignore que le client n'a pas reçu la réponse.
  5. Le client n'a pas d'URL pour la ressource (donc PUT n'est pas une option) et répète le POST.
  6. POST n'est pas idempotent et le serveur…

L'étape 6 est l'endroit où les gens se trompent généralement sur ce qu'il faut faire. Cependant, il n'y a aucune raison de créer un kludge pour résoudre ce problème. Au lieu de cela, HTTP peut être utilisé comme spécifié dans RFC 2616 et le serveur répond:

10.4.10 409 Conflit

La demande n'a pas pu être traitée en raison d'un conflit avec l'état actuel de la ressource. Ce code 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. Le corps de réponse DEVRAIT inclure suffisamment

informations permettant à l'utilisateur de reconnaître la source du conflit. Idéalement, l'entité de réponse comprendrait suffisamment d'informations pour que l'utilisateur ou l'agent utilisateur puisse résoudre le problème; cependant, cela pourrait ne pas être possible et n'est pas requis.

Les conflits sont plus susceptibles de se produire en réponse à une demande PUT. Par exemple, si le contrôle de version était utilisé et que l'entité PUT incluait des modifications apportées à une ressource qui entrent en conflit avec celles apportées par une demande antérieure (tierce), le serveur peut utiliser la réponse 409 pour indiquer qu'il ne peut pas terminer la demande. . Dans ce cas, l'entité de réponse contiendrait probablement une liste des différences entre les deux versions dans un format défini par le type de contenu de la réponse.

Répondre avec un code d'état 409 Conflit est le bon recours car :

  • L'exécution d'un POST de données dont l'ID correspond à une ressource déjà présente dans le système est «un conflit avec l'état actuel de la ressource».
  • Puisque la partie importante est pour le client de comprendre que le serveur a la ressource et de prendre les mesures appropriées. Il s'agit d'une «situation (s) où l'on s'attend à ce que l'utilisateur puisse résoudre le conflit et soumettre à nouveau la demande».
  • Une réponse qui contient l'URL de la ressource avec l'ID en conflit et les conditions préalables appropriées pour la ressource fournirait «suffisamment d'informations pour l'utilisateur ou l'agent utilisateur pour résoudre le problème», ce qui est le cas idéal selon la RFC 2616.

Mise à jour basée sur la publication de RFC 7231 pour remplacer 2616

RFC 7231 est conçu pour remplacer 2616 et dans la section 4.3.3 décrit la réponse possible suivante pour un POST

Si le résultat du traitement d'un POST serait équivalent à une représentation d'une ressource existante, un serveur d'origine PEUT rediriger l'agent utilisateur vers cette ressource en envoyant une réponse 303 (Voir Autre) avec l'identifiant de la ressource existante dans le champ Emplacement. Cela présente l'avantage de fournir à l'agent utilisateur un identifiant de ressource et de transférer la représentation via une méthode plus adaptée à la mise en cache partagée, mais au prix d'une demande supplémentaire si l'agent utilisateur n'a pas déjà la représentation mise en cache.

Il peut maintenant être tentant de renvoyer simplement un 303 dans le cas où un POST est répété. Cependant, l'inverse est vrai. Renvoyer un 303 n'aurait de sens que si plusieurs demandes de création (création de ressources différentes) renvoient le même contenu. Un exemple serait un «merci d'avoir soumis votre message de demande» que le client n'a pas besoin de re-télécharger à chaque fois. La RFC 7231 maintient toujours dans la section 4.2.2 que le POST ne doit pas être idempotent et continue de maintenir que le POST doit être utilisé pour la création.

Pour plus d'informations à ce sujet, lisez cet article .

Joshcodes
la source
Une réponse 409 Conflict serait-elle le code approprié pour quelque chose comme essayer de créer un nouveau compte avec un nom d'utilisateur qui existe déjà? J'ai utilisé 409 pour les conflits de version en particulier, mais après avoir lu votre réponse, je me demande si elle ne devrait pas être utilisée pour des requêtes "en double".
Eric B.
@EricB. Oui, dans la situation que vous décrivez "en raison d'un conflit avec l'état actuel de la ressource", l'opération échoue. En outre, il est raisonnable de s'attendre à ce que l'utilisateur puisse résoudre le conflit et le corps du message n'a qu'à informer l'utilisateur que le nom d'utilisateur existe déjà.
Joshcodes
@Joshcodes pouvez-vous en dire plus sur le processus de résolution des conflits? Dans ce cas, si le nom d'utilisateur existe déjà, le client est-il censé demander à l'utilisateur final un autre nom d'utilisateur? Que faire si le client essaie réellement d'utiliser POST pour changer le nom d'utilisateur? Les requêtes PUT doivent-elles toujours être utilisées pour mettre à jour les paramètres, alors que POST est utilisé pour créer des objets, que ce soit un à la fois ou plusieurs? Merci.
BFar
@ BFar2 si le nom d'utilisateur existe déjà, le client doit inviter l'utilisateur. Pour changer le nom d'utilisateur, en supposant que le nom d'utilisateur fait partie d'une ressource déjà créée qui doit être modifiée, PUT serait utilisé parce que vous avez raison, POST est utilisé pour créer, toujours et PUT pour les mises à jour.
Joshcodes
expliquer des choses en utilisant un langage court et efficace est également une compétence souhaitable
Junchen Liu
53

J'aime ce conseil, de la définition RFC 2616 de PUT :

La différence fondamentale entre les requêtes POST et PUT se reflète dans la signification différente de l'URI de demande. L'URI dans une demande POST identifie la ressource qui gérera l'entité incluse. Cette ressource peut être un processus d'acceptation de données, une passerelle vers un autre protocole ou une entité distincte qui accepte les annotations. En revanche, l'URI dans une demande PUT identifie l'entité jointe à la demande - l'agent utilisateur sait quel URI est prévu et le serveur NE DOIT PAS tenter d'appliquer la demande à une autre ressource.

Cela concorde avec l'autre conseil ici, que PUT est mieux appliqué aux ressources qui ont déjà un nom, et POST est bon pour créer un nouvel objet sous une ressource existante (et laisser le serveur le nommer).

J'interprète cela, et les exigences d'idempotence sur PUT, pour signifier que:

  • POST est bon pour créer de nouveaux objets sous une collection (et créer n'a pas besoin d'être idempotent)
  • PUT est bon pour mettre à jour des objets existants (et la mise à jour doit être idempotente)
  • POST peut également être utilisé pour des mises à jour non idempotentes d'objets existants (en particulier, changer une partie d'un objet sans spécifier le tout - si vous y pensez, la création d'un nouveau membre d'une collection est en fait un cas spécial de ce type de mise à jour, du point de vue de la collection)
  • PUT peut également être utilisé pour créer si et seulement si vous autorisez le client à nommer la ressource. Mais comme les clients REST ne sont pas censés faire d'hypothèses sur la structure des URL, cela est moins dans l'esprit des choses.
metamatt
la source
3
"POST peut également être utilisé pour les mises à jour non idempotentes des objets existants (en particulier, changer une partie d'un objet sans spécifier le tout" C'est à cela que sert PATCH
Snuggs
48

En bref:

METTRE est idempotent, où l'état de la ressource sera le même si la même opération est exécutée une ou plusieurs fois.

PUBLIER n'est pas idempotent, où l'état des ressources peut devenir différent si l'opération est exécutée plusieurs fois par rapport à l'exécution d'une seule fois.

Analogie avec requête de base de données

METTRE Vous pouvez penser à similaire à "UPDATE STUDENT SET address =" abc "where id =" 123 ";

PUBLIER Vous pouvez penser à quelque chose comme "INSERT IN STUDENT (nom, adresse) VALEURS (" abc "," xyzzz ");

L'ID étudiant est généré automatiquement.

Avec PUT, si la même requête est exécutée plusieurs fois ou une fois, l'état de la table STUDENT reste le même.

En cas de POST, si la même requête est exécutée plusieurs fois, plusieurs enregistrements Student sont créés dans la base de données et l'état de la base de données change à chaque exécution d'une requête "INSERT".

REMARQUE: PUT a besoin d'un emplacement de ressource (déjà ressource) sur lequel la mise à jour doit avoir lieu, alors que POST ne l'exige pas. Par conséquent, intuitivement, POST est destiné à la création d'une nouvelle ressource, tandis que PUT est nécessaire pour mettre à jour la ressource déjà existante.

Certains peuvent proposer que les mises à jour puissent être effectuées avec POST. Il n'y a pas de règle stricte à utiliser pour les mises à jour ou à utiliser pour créer. Encore une fois, ce sont des conventions, et intuitivement je suis enclin au raisonnement mentionné ci-dessus et le suis.

bharatj
la source
6
pour PUT est similaire à la requête INSERT ou UPDATE
Eugen Konkov
1
en fait PUT Vous pouvez penser à similaire à "UPDATE STUDENT SET address =" abc "where id =" 123 "; serait une déclaration pour PATCH." UPDATE STUDENT SET address = "abc", name = "newname" where id = " 123 "serait une analogie correcte pour PUT
mko
Put pourrait également être utilisé pour INSERT. Par exemple, si votre serveur détecte que vous essayez de télécharger plusieurs fois le même fichier, cela rendra votre demande idempotente. (Aucun nouveau téléchargement de fichier n'est effectué).
kiwicomb123
43

POST, c'est comme publier une lettre dans une boîte aux lettres ou poster un e-mail dans une file d'attente d'emails. PUT, c'est comme lorsque vous placez un objet dans un compartiment ou un endroit sur une étagère (il a une adresse connue).

Avec POST, vous publiez à l'adresse de la QUEUE ou de la COLLECTION. Avec PUT, vous mettez à l'adresse de l'ARTICLE.

PUT est idempotent. Vous pouvez envoyer la demande 100 fois et cela n'aura pas d'importance. POST n'est pas idempotent. Si vous envoyez la demande 100 fois, vous recevrez 100 e-mails ou 100 lettres dans votre boîte postale.

Une règle générale: si vous connaissez l'identifiant ou le nom de l'article, utilisez PUT. Si vous souhaitez que l'ID ou le nom de l'élément soit attribué par le destinataire, utilisez POST.

POST versus PUT

Homer6
la source
1
Non, PUT implique que vous connaissez l'URL. Si vous ne connaissez que l'ID, puis POST avec cet ID pour obtenir l'URL.
Joshcodes
6
L'ID fait partie de l'URL, alors oui, utilisez PUT si vous connaissez l'URL (qui inclut l'ID).
Homer6
Non, l'URL est déterminée par le serveur et l'ID ne fait pas nécessairement partie de l'URL. Roy Fielding vous dirait la même chose ou vous pourriez simplement lire sa thèse .
Joshcodes
@Joshcodes, est-ce que cela suppose REST? Dans une architecture RESTful, l'ID d'élément fait définitivement partie de l'URL, comme dans: / people / 123. J'aime ce site pour REST: microformats.org/wiki/rest/urls
Beez
1
@Beez le lien mircoformats suggère un bon moyen pour les serveurs de structurer leurs URL mais le serveur détermine l'URL. Le client ne le fait presque jamais. Voir ma réponse ou l' article associé si vous ne comprenez pas cela.
Joshcodes
39

Nouvelle réponse (maintenant que je comprends mieux REST):

PUT est simplement une déclaration du contenu que le service devrait désormais utiliser pour rendre des représentations de la ressource identifiée par le client; POST est une déclaration du contenu que le service doit désormais contenir (éventuellement dupliqué), mais c'est au serveur comment identifier ce contenu.

PUT x(si xidentifie une ressource ): "Remplacez le contenu de la ressource identifiée par xpar mon contenu."

PUT x(si xn'identifie pas une ressource): "Créer une nouvelle ressource contenant mon contenu et l'utiliser xpour l'identifier."

POST x: "Stockez mon contenu et donnez-moi un identifiant que je peux utiliser pour identifier une ressource (ancienne ou nouvelle) contenant ledit contenu (éventuellement mélangé à d'autres contenus). Cette ressource doit être identique ou subordonnée à celle qui l' xidentifie." « Y « de la ressource est subordonnée à x » ressource s » est généralement , mais pas nécessairement mis en œuvre en faisant y un sous - chemin de x (par exemple x = /fooet y = /foo/bar) et modifier la représentation (s) de x ressources de l » afin de refléter l'existence d'une nouvelle ressource, par exemple avec un hyperlien vers yressources et quelques métadonnées. Seul ce dernier est vraiment essentiel à une bonne conception, car les URL sont opaques dans REST - vous êtes censé utiliser l'hypermédia au lieu de la construction d'URL côté client pour traverser le service de toute façon.

Dans REST, il n'y a pas de ressource contenant du "contenu". J'appelle «contenu» les données que le service utilise pour rendre les représentations de manière cohérente. Il se compose généralement de quelques lignes associées dans une base de données ou un fichier (par exemple, un fichier image). C'est au service de convertir le contenu de l'utilisateur en quelque chose que le service peut utiliser, par exemple convertir une charge utile JSON en instructions SQL.

Réponse originale (peut être plus facile à lire) :

PUT /something(s'il /somethingexiste déjà): "Prenez tout ce que vous avez /somethinget remplacez-le par ce que je vous donne."

PUT /something(s'il /somethingn'existe pas déjà): "Prenez ce que je vous donne et mettez-le /something."

POST /something: "Prends ce que je te donne et mets-le où tu veux /somethingtant que tu me donnes son URL quand tu auras fini."

Jordan
la source
Mais comment pouvez-vous utiliser PUT pour créer une nouvelle ressource si elle n'existe pas, alors que votre méthode de génération d'ID est en incrémentation automatique? Habituellement, ORM génère automatiquement l'ID pour vous, comme la façon dont vous voulez qu'il soit dans un POST par exemple. Cela signifie-t-il que si vous voulez implémenter PUT de la bonne façon, vous devez changer la génération automatique de votre identifiant? C'est gênant si la réponse est oui.
Roni Axelrad
1
@RoniAxelrad: PUT est comme une instruction "INSERT OR UPDATE" de la base de données où vous incluez la clé dans la déclaration, donc applicable uniquement lorsque vous ne pouvez garantir aucune collision. par exemple. votre domaine a une «clé naturelle» ou vous utilisez un guide. POST, c'est comme insérer dans une table avec une clé d'incrémentation automatique. La base de données doit vous indiquer quel ID elle a obtenu après son insertion. Notez que votre "INSÉRER OU METTRE À JOUR" remplacera toutes les données précédentes si elles existaient.
Nigel Thorne
@NigelThorne Merci pour votre réponse. Donc, par exemple, si j'essaye de mettre un livre id 10 avec un URI: PUT books / 10. Si l'id 10 du livre n'existe pas, je devrais créer un livre avec l'id 10, n'est-ce pas? mais je ne peux pas contrôler le numérateur ID de création, car il est incrémenté automatiquement. que dois-je faire dans cette situation?
Roni Axelrad
1
@RoniAxelrad REST PUT vers un ID qui n'existe pas est une demande au serveur de créer une ressource. C'est toujours au serveur de décider s'il veut autoriser cela. Le serveur est aux commandes. Il peut répondre par "Non. Je ne vais pas faire ça". Vous le faites déjà si l'utilisateur n'a pas assez d'autorisations ... etc. Il est normal que le serveur dise "Non". REST est une convention qui nous permet de définir la signification de différents types de requêtes ... votre serveur décide quoi faire de ces requêtes en fonction de votre logique métier :) Même s'il dit "non", il suit toujours REST :)
Nigel Thorne
38

Réponse courte:

Règle générale simple: utilisez POST pour créer, utilisez PUT pour mettre à jour.

Longue réponse:

PUBLIER:

  • POST est utilisé pour envoyer des données au serveur.
  • Utile lorsque l'URL de la ressource est inconnue

METTRE:

  • PUT est utilisé pour transférer l'état au serveur
  • Utile lorsque l'URL d'une ressource est connue

Réponse plus longue:

Pour le comprendre, nous devons nous demander pourquoi PUT était requis, quels étaient les problèmes que PUT essayait de résoudre et que POST ne pouvait pas résoudre.

Du point de vue d'une architecture REST, il n'y en a pas qui compte. Nous aurions pu vivre sans PUT également. Mais du point de vue d'un développeur client, cela a rendu sa vie beaucoup plus simple.

Avant PUT, les clients ne pouvaient pas savoir directement l'URL que le serveur avait générée ou si tout ce qu'il avait généré ou si les données à envoyer au serveur étaient déjà mises à jour ou non. PUT a soulagé le développeur de tous ces maux de tête. PUT est idempotent, PUT gère les conditions de concurrence et PUT laisse le client choisir l'URL.

ishandutta2007
la source
3
Votre réponse courte pourrait être TRÈS erronée. HTTP PUT est libre d'être répété par des proxys HTTP. Et donc, si PUT fait réellement SQL INSERT, il pourrait échouer une deuxième fois, ce qui signifie qu'il retournerait un résultat différent et qu'il ne serait donc pas IDEMPOTENT (ce qui est la différence entre PUT et POST)
Kamil Tomšík
36

Ruby on Rails 4.0 utilisera la méthode 'PATCH' au lieu de PUT pour effectuer des mises à jour partielles.

RFC 5789 dit à propos de PATCH (depuis 1995):

Une nouvelle méthode est nécessaire pour améliorer l'interopérabilité et éviter les erreurs. La méthode PUT est déjà définie pour remplacer une ressource par un nouveau corps complet et ne peut pas être réutilisée pour effectuer des modifications partielles. Sinon, les proxys et les caches, et même les clients et les serveurs, peuvent être confus quant au résultat de l'opération. POST est déjà utilisé mais sans large interopérabilité (pour un, il n'y a pas de moyen standard de découvrir la prise en charge du format de patch). PATCH était mentionné dans les spécifications HTTP antérieures, mais pas complètement défini.

" Edge Rails: PATCH est la nouvelle méthode HTTP principale pour les mises à jour ", explique-t-il.

germanlinux
la source
27

Au risque de reformuler ce qui a déjà été dit, il semble important de se rappeler que PUT implique que le client contrôle ce que l' URL finira par être, lors de la création d'une ressource. Donc, une partie du choix entre PUT et POST sera de savoir dans quelle mesure vous pouvez faire confiance au client pour fournir une URL correcte et normalisée qui soit cohérente avec votre schéma d'URL.

Lorsque vous ne pouvez pas entièrement faire confiance au client pour faire la bonne chose, il serait plus approprié d'utiliser POST pour créer un nouvel élément, puis de renvoyer l'URL au client dans la réponse.

voleur de poêles
la source
2
Je suis un peu en retard à cela - mais quelqu'un disant quelque chose de similaire sur un autre site Web l'a fait cliquer pour moi. Si vous créez une ressource et utilisez un ID auto-incrémenté comme «identificateur» au lieu d'un nom attribué par l'utilisateur, il doit s'agir d'un POST.
Ixmatus
2
Ce n'est pas tout à fait raison - PUT peut encore créer une ressource en se référant à elle avec un nom non-canonique, tant que dans la réponse, le serveur renvoie un en- Locationtête qui ne contient le nom de la ressource canonique.
Ether
1
@Joshcodes n'oubliez pas que vous pouvez avoir plusieurs URI référençant la même ressource sous-jacente. Donc, ce qu'Ether a dit est un bon conseil, le client peut mettre une URL (qui pourrait être plus sémantique, comme PUT /X-files/series/4/episodes/max) et le serveur répond avec un URI qui fournit un court lien canonique unique vers cette nouvelle ressource (c.-à-d. /X-Ffiles/episodes/91)
thecoshman
@thecoshman, le problème est que la structure URL n'appartient pas au client. La lecture de la découverte de soi (qui fait également partie de REST) ​​peut aider à clarifier cela.
Joshcodes
@Joshcodes alors selon cette logique, un client ne devrait jamais utiliser PUT pour créer car il ne devrait pas se soucier de fournir l'URL. Eh bien ... sauf si le serveur a fourni une URL vers PUT si le client veut y mettre ... quelque chose comme "PUT / comments / new" et le serveur peut répondre "204 / comments / 234532" mais cela semble un peu RPC pour moi, le client devrait simplement POSTER / commentaires ...
thecoshman
24

D'une manière très simple, je prends l'exemple de la chronologie Facebook.

Cas 1: Lorsque vous postez quelque chose sur votre chronologie, c'est une nouvelle entrée. Dans ce cas, ils utilisent donc la méthode POST car la méthode POST n'est pas idempotente.

Cas 2: Si votre ami commente votre message pour la première fois, cela créera également une nouvelle entrée dans la base de données afin que la méthode POST soit utilisée.

Cas 3: Si votre ami modifie son commentaire, dans ce cas, il avait un identifiant de commentaire, il mettra donc à jour un commentaire existant au lieu de créer une nouvelle entrée dans la base de données. Par conséquent, pour ce type d'opération, utilisez la méthode PUT car elle est idempotente. *

Sur une seule ligne, utilisez POST pour ajouter une nouvelle entrée dans la base de données et PUT pour mettre à jour quelque chose dans la base de données.

UniCoder
la source
4
Si le commentaire est un objet avec une propriété telle que l'ID utilisateur, la date de création, le message de commentaire, etc. et au moment de la modification, seul le message de commentaire est mis à jour, PATCH doit être fait ici?
Habeeb Perwad
PUT est utilisé par FB pour mettre à jour le commentaire car une ressource existante est en cours de mise à jour, et c'est ce que PUT fait (met à jour une ressource). PUT se trouve être idempotent, contrairement à POST. Un verbe HTTP idempotent affecte la gestion des erreurs mais ne dicte pas son utilisation. Voir ma réponse pour une explication plus détaillée: stackoverflow.com/questions/630453/put-vs-post-in-rest/…
Joshcodes
22

La considération la plus importante est la fiabilité . Si un message POST est perdu, l'état du système n'est pas défini. La récupération automatique est impossible. Pour les messages PUT, l'état n'est indéfini que jusqu'à la première tentative réussie.

Par exemple, il peut ne pas être judicieux de créer des transactions par carte de crédit avec POST.

S'il vous arrive d'avoir des URI générés automatiquement sur votre ressource, vous pouvez toujours utiliser PUT en passant un URI généré (pointant vers une ressource vide) au client.

Quelques autres considérations:

  • POST invalide les copies mises en cache de la totalité de la ressource contenant (meilleure cohérence)
  • Les réponses PUT ne peuvent pas être mises en cache alors que celles POST le sont (Exiger l'emplacement du contenu et l'expiration)
  • PUT est moins pris en charge par exemple Java ME, les anciens navigateurs, les pare-feu
Hans Malherbe
la source
Ceci est une erreur. Pour POST, l'état n'est également défini que jusqu'à la première tentative réussie. Ensuite, le serveur accepte le POST (message jamais arrivé), lance un conflit 409 pour un ID en double (message arrivé, réponse perdue) ou toute autre réponse valide.
Joshcodes
En général, un agent utilisateur ne pourrait pas réessayer en toute sécurité l'opération POST car l'opération POST ne garantit pas que deux opérations auraient le même effet qu'une. Le terme "ID" n'a rien à voir avec HTTP. L'URI identifie la ressource.
Hans Malherbe
Un agent utilisateur peut réessayer "en toute sécurité" une opération POST autant de fois qu'il le souhaite. Il recevra simplement une erreur d'ID en double (en supposant que la ressource a un ID) ou une erreur de données en double (en supposant que c'est un problème et que la ressource n'a pas d'ID).
Joshcodes
Frappe la tête contre le mur. HTTP n'a pas de solution au problème de la fiabilité, et cela n'est pas bien compris, pas beaucoup discuté, et tout simplement pas pris en charge dans la grande majorité des applications Web. @Joshcodes J'ai une réponse à cette question. Je suis essentiellement d'accord avec Hans. Il ya un problème.
bbsimonbb
@bbsimonbb, HTTP dispose d'un ensemble robuste et bien documenté de réponses d'erreur. Ma réponse à cette question ( stackoverflow.com/questions/630453/put-vs-post-in-rest/… ) couvre comment utiliser http selon les spécifications pour atteindre la cohérence.
Joshcodes
17

Les lecteurs de nouvelles à ce sujet seront frappés par la discussion sans fin sur ce que vous devriez faire, et l'absence relative des enseignements tirés de l' expérience. Le fait que REST soit "préféré" par rapport à SOAP est, je suppose, un apprentissage de haut niveau par expérience, mais bonté, nous devons avoir progressé à partir de là? Nous sommes en 2016. La thèse de Roy remonte à 2000. Qu'avons-nous développé? C'était amusant? A-t-il été facile de s'intégrer avec? Soutenir? Va-t-il gérer la montée en puissance des smartphones et des connexions mobiles feuilletées?

Selon ME, les réseaux réels ne sont pas fiables. Délai d'expiration des demandes. Les connexions sont réinitialisées. Les réseaux tombent pendant des heures ou des jours à la fois. Les trains entrent dans les tunnels avec des utilisateurs mobiles à bord. Pour toute demande donnée (comme cela a parfois été reconnu dans toute cette discussion), la demande peut tomber dans l'eau sur son chemin, ou la réponse peut tomber dans l'eau sur le chemin du retour. Dans ces conditions, émettre des demandes PUT, POST et DELETE directement contre des ressources substantielles m'a toujours paru un peu brutal et naïf.

HTTP ne fait rien pour assurer une exécution fiable de la demande-réponse, et c'est très bien car c'est bien le travail des applications réseau. En développant une telle application, vous pouvez sauter à travers les cercles pour utiliser PUT au lieu de POST, puis plus de cercles pour donner un certain type d'erreur sur le serveur si vous détectez des demandes en double. De retour chez le client, vous devez ensuite sauter à travers des cerceaux pour interpréter ces erreurs, récupérer, revalider et republier.

Ou vous pouvez le faire : considérez vos demandes dangereuses comme des ressources éphémères pour un seul utilisateur (appelons-les actions). Les clients demandent une nouvelle "action" sur une ressource substantielle avec un POST vide à la ressource. POST ne sera utilisé que pour cela. Une fois en possession de l'URI de l'action fraîchement émise, le client transmet la demande non sécurisée à l'URI de l'action, et non à la ressource cible . La résolution de l'action et la mise à jour de la "vraie" ressource est correctement l'affaire de votre API, et est ici découplée du réseau peu fiable.

Le serveur fait l'affaire, renvoie la réponse et la stocke par rapport à l'URI d'action convenu . Si quelque chose ne va pas, le client répète la requête (comportement naturel!), Et si le serveur l'a déjà vue, il répète la réponse stockée et ne fait rien d'autre .

Vous remarquerez rapidement la similitude avec les promesses: nous créons et renvoyons l'espace réservé pour le résultat avant de faire quoi que ce soit. Comme une promesse, une action peut réussir ou échouer une seule fois, mais son résultat peut être récupéré à plusieurs reprises.

Mieux encore, nous donnons aux demandes d'envoi et de réception la possibilité de lier l'action identifiée de manière unique à l'unicité de leurs environnements respectifs. Et nous pouvons commencer à exiger et à appliquer !, un comportement responsable de la part des clients: répétez vos demandes autant que vous le souhaitez, mais ne générez pas de nouvelle action tant que vous n'êtes pas en possession d'un résultat définitif de l'action existante.

Ainsi, de nombreux problèmes épineux disparaissent. Les demandes d'insertion répétées ne créeront pas de doublons, et nous ne créons pas la véritable ressource tant que nous ne sommes pas en possession des données. (les colonnes de la base de données peuvent rester non nulles). Les demandes de mise à jour répétées n'atteindront pas les états incompatibles et n'écraseront pas les modifications ultérieures. Les clients peuvent (re) récupérer et traiter de manière transparente la confirmation d'origine pour une raison quelconque (le client est tombé en panne, la réponse a disparu, etc.).

Les demandes de suppression successives peuvent voir et traiter la confirmation d'origine, sans générer d'erreur 404. Si les choses prennent plus de temps que prévu, nous pouvons répondre provisoirement et nous avons un endroit où le client peut vérifier le résultat définitif. La plus belle partie de ce modèle est sa propriété Kung-Fu (Panda). Nous prenons une faiblesse, la propension des clients à répéter une demande chaque fois qu'ils ne comprennent pas la réponse, et la transformons en force :-)

Avant de me dire que ce n'est pas RESTful, veuillez considérer les nombreuses façons dont les principes REST sont respectés. Les clients ne construisent pas d'URL. L'API reste découvrable, mais avec un petit changement de sémantique. Les verbes HTTP sont utilisés de manière appropriée. Si vous pensez que c'est un énorme changement à mettre en œuvre, je peux vous dire par expérience que ce n'est pas le cas.

Si vous pensez que vous aurez d'énormes quantités de données à stocker, parlons de volumes: une confirmation de mise à jour typique est une fraction de kilo-octet. HTTP vous donne actuellement une minute ou deux pour répondre définitivement. Même si vous ne stockez les actions que pendant une semaine, les clients ont amplement l'occasion de se rattraper. Si vous avez des volumes très élevés, vous souhaiterez peut-être un magasin de valeurs de clés conforme à l'acide dédié ou une solution en mémoire.

bbsimonbb
la source
1
Ne stockez-vous pas la réponse comme si vous mainteniez une session? Ce qui entraînerait des problèmes de mise à l'échelle (horizontale).
Saurabh Harwande
17

En plus des différences suggérées par d'autres, je veux en ajouter une de plus.

Dans la méthode POST , vous pouvez envoyer des paramètres de corps dansform-data

Dans la méthode PUT , vous devez envoyer les paramètres du corps dansx-www-form-urlencoded

Entête Content-Type:application/x-www-form-urlencoded

Selon cela, vous ne pouvez pas envoyer de fichiers ou de données en plusieurs parties dans la méthode PUT

ÉDITER

Le type de contenu "application / x-www-form-urlencoded" est inefficace pour envoyer de grandes quantités de données binaires ou de texte contenant des caractères non ASCII. Le type de contenu "multipart / form-data" doit être utilisé pour soumettre des formulaires contenant des fichiers, des données non ASCII et des données binaires.

Ce qui signifie que si vous devez soumettre

fichiers, données non ASCII et données binaires

vous devez utiliser la méthode POST

Rohit Dhiman
la source
3
Pourquoi cela n'a-t-il pas été voté? Si c'est vrai, c'est une distinction critique, n'est-ce pas?
Iofacture
2
Je l'ai rencontré lors de la mise en œuvre de l'API pour la mise à jour du profil, qui comprend le téléchargement de photos de profil utilisateur. Ensuite, je l'ai testé avec le facteur, Ajax, PHP curl et laravel 5.6 comme backend.
Rohit Dhiman
14

Il semble toujours y avoir une certaine confusion quant au moment d'utiliser HTTP POST par rapport à la méthode HTTP PUT pour les services REST. La plupart des développeurs essaieront d'associer les opérations CRUD directement aux méthodes HTTP. Je soutiendrai que ce n'est pas correct et que l'on ne peut pas simplement associer les concepts CRUD aux méthodes HTTP. C'est:

Create => HTTP PUT
Retrieve => HTTP GET
Update => HTTP POST
Delete => HTTP DELETE

Il est vrai que le R (etrieve) et le D (elete) des opérations CRUD peuvent être mappés directement aux méthodes HTTP GET et DELETE respectivement. Cependant, la confusion réside dans les opérations C (reate) et U (update). Dans certains cas, on peut utiliser le PUT pour une création tandis que dans d'autres cas, un POST sera nécessaire. L'ambiguïté réside dans la définition d'une méthode HTTP PUT par rapport à une méthode HTTP POST.

Selon les spécifications HTTP 1.1, les méthodes GET, HEAD, DELETE et PUT doivent être idempotentes et la méthode POST n'est pas idempotente. C'est-à-dire qu'une opération est idempotente si elle peut être effectuée sur une ressource une ou plusieurs fois et toujours retourner le même état de cette ressource. Alors qu'une opération non idempotente peut renvoyer un état modifié de la ressource d'une requête à l'autre. Par conséquent, dans une opération non idempotente, rien ne garantit que l'on recevra le même état d'une ressource.

Sur la base de la définition idempotente ci-dessus, mon point de vue sur l'utilisation de la méthode HTTP PUT par rapport à l'utilisation de la méthode HTTP POST pour les services REST est: Utilisez la méthode HTTP PUT lorsque:

The client includes all aspect of the resource including the unique identifier to uniquely identify the resource. Example: creating a new employee.
The client provides all the information for a resource to be able to modify that resource.This implies that the server side does not update any aspect of the resource (such as an update date).

Dans les deux cas, ces opérations peuvent être effectuées plusieurs fois avec les mêmes résultats. Autrement dit, la ressource ne sera pas modifiée en demandant l'opération plus d'une fois. D'où une véritable opération idempotente. Utilisez la méthode HTTP POST lorsque:

The server will provide some information concerning the newly created resource. For example, take a logging system. A new entry in the log will most likely have a numbering scheme which is determined on the server side. Upon creating a new log entry, the new sequence number will be determined by the server and not by the client.
On a modification of a resource, the server will provide such information as a resource state or an update date. Again in this case not all information was provided by the client and the resource will be changing from one modification request to the next. Hence a non idempotent operation.

Conclusion

Ne corrélez pas et ne mappez pas directement les opérations CRUD aux méthodes HTTP pour les services REST. L'utilisation d'une méthode HTTP PUT par rapport à une méthode HTTP POST doit être basée sur l'aspect idempotent de cette opération. Autrement dit, si l'opération est idempotente, utilisez la méthode HTTP PUT. Si l'opération n'est pas idempotente, utilisez la méthode HTTP POST.

Burhan
la source
2
Mise à jour => HTTP POST: POST n'est pas à mettre à jour
Premraj
@premraj Vous avez fait l'hypothèse que Burhan vous dit de ne pas faire; à savoir, vous associez CRUD, REST et HTTP. Si vous lisez RFC 7231, où ces choses sont définies, vous constaterez que dans le protocole HTTP, la définition de POST permet certainement la mise à jour. Seules les contraintes de REST disent le contraire.
IAM_AL_X
13

le serveur d'origine peut créer la ressource avec cet URI

Vous utilisez donc POST et probablement, mais pas nécessaire PUT pour la création de ressources. Vous n'avez pas à supporter les deux. Pour moi, POST est parfaitement suffisant. C'est donc une décision de conception.

Comme votre citation l'a mentionné, vous utilisez PUT pour la création d'aucune ressource affectée à un IRI, et vous voulez quand même créer une ressource. Par exemple, PUT /users/123/passwordremplace généralement l'ancien mot de passe par un nouveau, mais vous pouvez l'utiliser pour créer un mot de passe s'il n'existe pas déjà (par exemple, par des utilisateurs fraîchement enregistrés ou en restaurant des utilisateurs interdits).

inf3rno
la source
Je pense que vous avez réussi à fournir l'un des rares bons exemples d'utilisation de PUT, bravo.
thecoshman
12

Je vais atterrir avec ce qui suit:

PUT fait référence à une ressource, identifiée par l'URI. Dans ce cas, vous le mettez à jour. C'est la partie des trois verbes se référant aux ressources - supprimer et devenir les deux autres.

POST est essentiellement un message de forme libre, sa signification étant définie «hors bande». Si le message peut être interprété comme l'ajout d'une ressource à un répertoire, ce serait OK, mais fondamentalement, vous devez comprendre le message que vous envoyez (publier) pour savoir ce qui se passera avec la ressource.


Parce que PUT et GET et DELETE font référence à une ressource, ils sont également par définition idempotents.

POST peut effectuer les trois autres fonctions, mais alors la sémantique de la demande sera perdue sur les intermédiaires tels que les caches et les proxys. Cela s'applique également à la sécurité de la ressource, car l'URI d'un article n'indique pas nécessairement la ressource à laquelle il s'applique (il peut cependant).

Un PUT n'a pas besoin d'être une création; le service peut générer une erreur si la ressource n'est pas déjà créée, mais sinon la mettre à jour. Ou vice versa - il peut créer la ressource, mais ne pas autoriser les mises à jour. La seule chose requise à propos de PUT est qu'il pointe vers une ressource spécifique, et sa charge utile est la représentation de cette ressource. Un PUT réussi signifie (sauf interférence) qu'un GET récupérerait la même ressource.


Edit: Encore une chose - un PUT peut créer, mais si c'est le cas, l'ID doit être un ID naturel - AKA une adresse e-mail. De cette façon, lorsque vous mettez deux fois, le deuxième put est une mise à jour du premier. Cela le rend idempotent .

Si l'ID est généré (un nouvel ID d'employé, par exemple), le deuxième PUT avec la même URL créerait un nouvel enregistrement, ce qui viole la règle idempotente. Dans ce cas, le verbe serait POST et le message (pas une ressource) serait de créer une ressource en utilisant les valeurs définies dans ce message.

Gerard ONeill
la source
9

La sémantique est supposée être différente, dans la mesure où "PUT", comme "GET" est censé être idempotent - ce qui signifie que vous pouvez répéter la même demande PUT exacte plusieurs fois et le résultat sera comme si vous ne l'aviez exécuté qu'une seule fois.

Je décrirai les conventions qui, selon moi, sont les plus utilisées et les plus utiles:

Lorsque vous METTEZ une ressource sur une URL particulière, ce qui se passe, c'est qu'elle doit être enregistrée sur cette URL, ou quelque chose du genre.

Lorsque vous publiez sur une ressource à une URL particulière, vous publiez souvent une information associée à cette URL. Cela implique que la ressource à l'URL existe déjà.

Par exemple, lorsque vous souhaitez créer un nouveau flux, vous pouvez le METTRE vers une URL. Mais lorsque vous souhaitez POSTER un message sur un flux existant, vous POSTEZ sur son URL.

Quant à la modification des propriétés du flux, vous pouvez le faire avec PUT ou POST. Fondamentalement, utilisez uniquement "PUT" lorsque l'opération est idempotente - sinon utilisez POST.

Notez cependant que tous les navigateurs modernes ne prennent pas en charge les verbes HTTP autres que GET ou POST.

Gregory Magarshak
la source
Ce que vous décrivez comme POST est en fait comment PATCH devrait se comporter. POST est censé signifier quelque chose de plus semblable à "ajouter" comme dans "poster à la liste de diffusion".
Alexander Torstling
8

La plupart du temps, vous les utiliserez comme ceci:

  • POSTER une ressource dans une collection
  • METTRE une ressource identifiée par collection /: id

Par exemple:

  • POST / articles
  • PUT / items / 1234

Dans les deux cas, le corps de la demande contient les données de la ressource à créer ou à mettre à jour. Il devrait être évident d'après les noms de route que POST n'est pas idempotent (si vous l'appelez 3 fois cela créera 3 objets), mais PUT est idempotent (si vous l'appelez 3 fois le résultat est le même). PUT est souvent utilisé pour une opération "upsert" (création ou mise à jour), mais vous pouvez toujours renvoyer une erreur 404 si vous ne souhaitez l'utiliser que pour le modifier.

Notez que POST "crée" un nouvel élément dans la collection et PUT "remplace" un élément à une URL donnée, mais il est très courant d'utiliser PUT pour des modifications partielles, c'est-à-dire de ne l'utiliser que pour mettre à jour les ressources existantes et modifier uniquement les champs inclus dans le corps (en ignorant les autres champs). Ceci est techniquement incorrect, si vous voulez être puriste REST, PUT doit remplacer la ressource entière et vous devez utiliser PATCH pour la mise à jour partielle. Personnellement, je ne m'inquiète pas tant que le comportement est clair et cohérent sur tous vos points de terminaison API.

N'oubliez pas que REST est un ensemble de conventions et de directives pour garder votre API simple. Si vous vous retrouvez avec un contournement compliqué juste pour cocher la case "RESTfull" alors vous allez à l'encontre du but;)

tothemario
la source
7

Bien qu'il existe probablement une façon agnostique de les décrire, cela semble être en conflit avec diverses déclarations provenant des réponses aux sites Web.

Soyons très clairs et directs ici. Si vous êtes un développeur .NET travaillant avec l'API Web, les faits sont (à partir de la documentation de l'API Microsoft), http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web -api-that-supports-crud-operations :

1. PUT = UPDATE (/api/products/id)
2. MCSD Exams 2014 -  UPDATE = PUT, there are **NO** multiple answers for that question period.

Bien sûr, vous "pouvez" utiliser "POST" pour effectuer la mise à jour, mais suivez simplement les conventions qui vous sont proposées avec votre framework donné. Dans mon cas, c'est .NET / Web API, donc PUT est pour UPDATE il n'y a pas de débat.

J'espère que cela aidera tous les développeurs Microsoft qui liront tous les commentaires avec des liens vers des sites Web Amazon et Sun / Java.

Tom Stickel
la source
7

Voici une règle simple:

PUT vers une URL doit être utilisé pour mettre à jour ou créer la ressource qui peut se trouver sur cette URL.

POST vers une URL doit être utilisé pour mettre à jour ou créer une ressource qui se trouve sur une autre URL ("subordonnée"), ou qui n'est pas localisable via HTTP.

Adam Griffiths
la source
1
PUT n'est pas à mettre à jour, c'est à remplacer, notez que pour créer vous ne remplacez rien par quelque chose. POST n'est absolument pas destiné à être mis à jour sous quelque forme que ce soit.
thecoshman
2
La spécification http le dit-elle? Ou basez-vous votre commentaire sur autre chose?
Adam Griffiths
C'est juste du bon sens, comment mettre à jour quelque chose quand on ne sait pas ce que l'on met à jour? POST sert à créer une nouvelle ressource.
thecoshman
2
thecoshman - vous abusez de la sémantique ici - un remplacement peut être une mise à jour s'il s'agit de la même ressource avec quelques différences. Un remplacement n'est valide pour put que si replace est utilisé pour changer la même ressource. Le remplacement par une ressource nouvelle et différente n'est pas valide (supprimer l'ancienne et en ajouter une nouvelle?), Surtout si la «nouvelle» ressource n'a pas d'ID naturel. POST, OTOH, est quelque chose qui peut créer, mettre à jour, remplacer et supprimer - l'utilisation de post dépend de la présence ou non d'un message à interpréter, tel que `` appliquer la remise '', qui peut ou non changer la ressource en fonction de logique.
Gerard ONeill
Quant à votre deuxième commentaire - que diriez-vous d'obtenir la ressource, de modifier les champs dont vous avez besoin, puis de la remettre? Ou que diriez-vous si la ressource provient d'une source différente mais utilise un ID naturel (l'ID externe) - put mettrait naturellement à jour la ressource à l'URL lorsque les données d'origine ont changé.
Gerard ONeill
6

Si vous connaissez les opérations de base de données, il existe

  1. Sélectionner
  2. Insérer
  3. Mise à jour
  4. Supprimer
  5. Fusionner (mettre à jour s'il existe déjà, sinon insérer)

J'utilise PUTpour la fusion et la mise à jour comme des opérations et j'utilise POSTpour les insertions.

Rajan
la source
5

En pratique, POST fonctionne bien pour créer des ressources. L'URL de la ressource nouvellement créée doit être renvoyée dans l'en-tête de réponse Emplacement. PUT doit être utilisé pour mettre à jour une ressource complètement. Veuillez comprendre qu'il s'agit des meilleures pratiques lors de la conception d'une API RESTful. La spécification HTTP en tant que telle ne restreint pas l'utilisation de PUT / POST avec quelques restrictions pour la création / mise à jour des ressources. Jetez un œil à http://techoctave.com/c7/posts/71-twitter-rest-api-dissected qui résume les meilleures pratiques.

java_geek
la source
Pour la plupart, de la lecture de tout ce bruit, vous semblez sur la balle. Je dirais cependant que nous devrions nous référer à PUT comme méthode de remplacement, plutôt qu'à create / update. Je pense qu'il décrit mieux en un seul ce qu'il fait.
thecoshman