PUT vs. POST en REST

5373

De acuerdo con la especificación HTTP / 1.1:

El POSTmétodo se utiliza para solicitar que el servidor de origen acepta la entidad incluida en la solicitud como una nueva subordinado del recurso identificado por el Request-URIen elRequest-Line

En otras palabras, POSTse usa para crear .

El PUTmétodo solicita que la entidad adjunta se almacene bajo el suministrado Request-URI. Si se Request-URIrefiere a un recurso ya existente, la entidad adjunta DEBE considerarse como una versión modificada de la que reside en el servidor de origen. Si el Request-URIno apunta a un recurso existente, y ese URI es capaz de ser definido como un nuevo recurso por el agente de usuario solicitante, el servidor de origen puede crear el recurso con ese URI ".

Es decir, PUTse usa para crear o reemplazar .

Entonces, ¿cuál debería usarse para crear un recurso? ¿O uno necesita apoyar a ambos?

alex
fuente
56
Puede ser útil usar las definiciones en HTTPbis. Roy hizo una buena cantidad de trabajo para aclararlas. Ver: tools.ietf.org/html/…
Mark Nottingham el
16
Solo para llevar el comentario de @ MarkNottingham a la última revisión, aquí hay POST y PUT , como se define en HTTPbis.
Marius Butuc
37
Me parece que este debate surgió de la práctica común de simplificar en exceso REST al describir los métodos HTTP en términos de operaciones CRUD.
Stuporman
55
Desafortunadamente, las primeras respuestas son incorrectas sobre POST. Consulte mi respuesta para obtener una mejor explicación de las diferencias: stackoverflow.com/a/18243587/2458234
7hi4g0
23
PUT y POST son métodos inseguros. Sin embargo, PUT es idempotente, mientras que POST no lo es. - Ver más en: restcookbook.com/HTTP%20Methods/put-vs-post/…
Dinesh Saini

Respuestas:

4239

En general:

Tanto PUT como POST pueden usarse para crear.

Tienes que preguntar "¿para qué estás realizando la acción?" para distinguir lo que deberías estar usando. Supongamos que está diseñando una API para hacer preguntas. Si desea utilizar POST, debe hacerlo en una lista de preguntas. Si desea usar PUT, entonces lo haría a una pregunta en particular.

Se pueden usar ambos excelentes, así que ¿cuál debo usar en mi diseño RESTful?

No necesita admitir tanto PUT como POST.

Lo que se usa se deja a usted. Pero solo recuerde usar el correcto según el objeto al que hace referencia en la solicitud.

Algunas consideraciones

  • ¿Nombra los objetos de URL que crea explícitamente o deja que el servidor decida? Si los nombra, use PUT. Si deja que el servidor decida, use POST.
  • PUT es idempotente, por lo que si PONES un objeto dos veces, no tiene efecto. Esta es una buena propiedad, por lo que usaría PUT cuando sea posible.
  • Puede actualizar o crear un recurso con PUT con la misma URL de objeto
  • Con POST puede recibir 2 solicitudes al mismo tiempo que realizan modificaciones en una URL, y pueden actualizar diferentes partes del objeto.

Un ejemplo:

Escribí lo siguiente como parte de otra respuesta en SO con respecto a esto :

ENVIAR:

Se usa para modificar y actualizar un recurso

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

Tenga en cuenta que lo siguiente es un error:

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

Si la URL aún no se ha creado, no debe usar POST para crearla mientras especifica el nombre. Esto debería dar como resultado un error de "recurso no encontrado" porque <new_question>aún no existe. <new_question> Primero debe PONER el recurso en el servidor.

Sin embargo, podría hacer algo como esto para crear recursos utilizando POST:

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

Tenga en cuenta que en este caso no se especifica el nombre del recurso, se le devolverá la ruta URL de los nuevos objetos.

PONER:

Se usa para crear un recurso o sobrescribirlo. Mientras especifica los recursos nueva URL.

Para un nuevo recurso:

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

Para sobrescribir un recurso existente:

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

Además, y de manera un poco más concisa, RFC 7231 Sección 4.3.4 Estados PUT (énfasis agregado),

4.3.4. PONER

El método PUT solicita que el estado del recurso de destino sea createdo replacedcon el estado definido por la representación incluida en la carga útil del mensaje de solicitud.

Brian R. Bondy
fuente
1026
Creo que no se puede enfatizar lo suficiente el hecho de que PUT es idempotente: si la red está fallada y el cliente no está seguro de si su solicitud se realizó, solo puede enviarla por segunda vez (o centésima) vez, y está garantizado por el HTTP especifica que esto tiene exactamente el mismo efecto que enviar una vez.
Jörg W Mittag
77
@ Jörg W Mittag: No es necesario. La segunda vez podría devolver 409 Conflict o algo así si la solicitud ha sido modificada mientras tanto (por algún otro usuario o la primera solicitud en sí, que pasó).
Mitar
632
Si no me equivoco, lo que deberíamos enfatizar es que PUT se define como idempotente. Todavía tiene que escribir su servidor de tal manera que PUT se comporte correctamente, ¿sí? Quizás sea mejor decir "PUT hace que el transporte asuma idempotencia, lo que puede afectar el comportamiento del transporte, por ejemplo, el almacenamiento en caché".
Ian Ni-Lewis
150
@ JörgWMittag Idempotence eslogan? Qué tal "Enviar y enviar y enviar a mi amigo, al final no hay diferencia".
James Beninger
39
Piensa en ellos como: PUT = insertar o actualizar; POST = insertar. Entonces, cuando haces dos PUT, obtienes un nuevo registro, cuando haces dos POST, obtienes dos nuevos registros.
Eugen Konkov
2218

Puede encontrar afirmaciones en la web que dicen

Ninguno de los dos tiene razón.


Mejor es elegir entre PUT y POST basado en la idempotencia de la acción.

PUT implica poner un recurso, reemplazar completamente lo que esté disponible en la URL dada con una cosa diferente. Por definición, un PUT es idempotente. Hazlo tantas veces como quieras, y el resultado es el mismo. x=5es idempotente ¡Puede PONER un recurso si ya existe o no (por ejemplo, para Crear o para Actualizar)!

POST actualiza un recurso, agrega un recurso subsidiario o provoca un cambio. Un POST no es idempotente, de la misma manera que x++no lo es.


Con este argumento, PUT es para crear cuando conoce la URL de la cosa que va a crear. POST se puede usar para crear cuando conoce la URL de la "fábrica" ​​o el administrador de la categoría de cosas que desea crear.

entonces:

POST /expense-report

o:

PUT  /expense-report/10929
Cheeso
fuente
72
Estoy de acuerdo, en lo que respecta a la idempotencia, debería superar cualquier otra preocupación, ya que equivocarse puede causar muchos errores inesperados.
Josh
16
Si POST puede actualizar un recurso, ¿cómo es que no es idempotente? Si cambio la edad de un estudiante usando PUT y lo hago 10 veces más, la edad de los estudiantes es la misma si lo hiciera una vez.
Jack Ukleja
28
@Schneider, en este caso su servidor está haciendo un esfuerzo adicional para garantizar la idempotencia, pero no lo está anunciando. Los navegadores seguirán advirtiendo al usuario si intentan volver a cargar dicha solicitud POST.
Tobu
47
@Schneider POST puede crear un recurso subsidiario; por lo tanto, puede enviar POST a la recopilación, como POST / informes de gastos, y crearía tantas entidades (informes de gastos) en su servidor como la cantidad de solicitudes que ha enviado, incluso si son completamente similares. Piense en ello como insertar la misma fila en la tabla de base de datos (/ gasto-informes) con clave primaria auto-incrementada. Los datos siguen siendo los mismos, la clave (URI en este caso) es generada por el servidor y es diferente para cada otra inserción (solicitud). Entonces, el efecto POST puede ser idempotente, pero también puede no serlo . Por lo tanto, POST no es idempotente.
Snifff
11
Digamos que tenemos entidades que pueden tener dos propiedades, namey date. Si tenemos una entidad con un existente namey date, pero luego le solicitamos que especifique solo a name, el comportamiento correcto de PUT sería eliminar el datede la entidad, mientras que POST puede actualizar solo las propiedades especificadas, dejando las propiedades no especificadas como estaban antes de que se hiciera la solicitud. ¿Suena correcto / razonable, o es un uso incorrecto de PUT (vi referencias a PATCH , que parece ser más apropiado, pero aún no existe)?
Jon z
707
  • POST a una URL crea un recurso hijo en una URL definida por el servidor .
  • PUT a una URL crea / reemplaza el recurso en su totalidad en la URL definida por el cliente .
  • PATCH a una URL actualiza parte del recurso en esa URL definida por el cliente.

La especificación relevante para PUT y POST es RFC 2616 §9.5ff.

POST crea un recurso hijo , por lo que POST /itemscrea un recurso que vive debajo del /itemsrecurso. P.ej. /items/1. Enviar el mismo paquete postal dos veces creará dos recursos.

PUT es para crear o reemplazar un recurso en una URL conocida por el cliente .

Por lo tanto: PUT es solo un candidato para CREATE donde el cliente ya conoce la URL antes de que se cree el recurso. P.ej. /blogs/nigel/entry/when_to_use_post_vs_putya que el título se usa como clave de recurso

PUT reemplaza el recurso en la URL conocida si ya existe, por lo que enviar la misma solicitud dos veces no tiene ningún efecto. En otras palabras, las llamadas a PUT son idempotentes .

El RFC dice así:

La diferencia fundamental entre las solicitudes POST y PUT se refleja en el significado diferente del Request-URI. El URI en una solicitud POST identifica el recurso que manejará la entidad adjunta. Ese recurso podría ser un proceso de aceptación de datos, una puerta de enlace a algún otro protocolo o una entidad separada que acepte anotaciones. Por el contrario, el URI en una solicitud PUT identifica la entidad adjunta a la solicitud: el agente de usuario sabe a qué se destina el URI y el servidor NO DEBE intentar aplicar la solicitud a otro recurso. Si el servidor desea que la solicitud se aplique a un URI diferente,

Nota: PUT se ha utilizado principalmente para actualizar recursos (reemplazándolos en su totalidad), pero recientemente se ha avanzado hacia el uso de PATCH para actualizar los recursos existentes, ya que PUT especifica que reemplaza todo el recurso. RFC 5789.

Actualización 2018 : hay un caso que se puede hacer para evitar PUT. Consulte "DESCANSO sin PUT"

Con la técnica "REST sin PUT", la idea es que los consumidores se vean obligados a publicar nuevos recursos de solicitud 'no anunciados'. Como se discutió anteriormente, cambiar la dirección postal de un cliente es una POST a un nuevo recurso "ChangeOfAddress", no un PUT de un recurso "Cliente" con un valor de campo de dirección postal diferente.

tomado de REST API Design - Modelado de recursos por Prakash Subramaniam de Thoughtworks

Esto obliga a la API a evitar problemas de transición de estado con múltiples clientes que actualizan un solo recurso, y coincide mejor con el abastecimiento de eventos y CQRS. Cuando el trabajo se realiza de forma asíncrona, parece POSTALAR la transformación y esperar a que se aplique.

Nigel Thorne
fuente
53
O desde el otro lado de la cerca: PUT si el cliente determina la dirección del recurso resultante, POST si el servidor lo hace.
DanMan el
3
Creo que esta respuesta debería editarse para que quede más claro lo que @DanMan señaló de una manera muy simple. Lo que encuentro más valioso aquí es la nota al final, indicando que un PUT debe usarse solo para reemplazar todo el recurso.
Hermes
3
PATCH no es una opción realista durante al menos algunos años, pero estoy de acuerdo con la ideología.
aplastado
44
Estoy tratando de entender, pero usar PUT para crear algo solo tendría sentido si el cliente sabe con certeza que el recurso aún no existe, ¿verdad? Siguiendo el ejemplo del blog, digamos que ha creado cientos de publicaciones en un par de años, luego, accidentalmente, elija el mismo título que hizo para una publicación hace dos años. Ahora te has ido y reemplazado esa publicación, que no estaba destinada. Entonces, usar PUT para crear requeriría que el cliente rastree lo que se tomó y lo que no, y podría provocar accidentes y efectos secundarios no deseados, además de tener rutas que hagan dos cosas completamente diferentes.
galaxyAbstractor
55
Estás en lo correcto. PONER una publicación de blog en la misma URL que una existente provocaría una actualización de esa publicación existente (aunque obviamente podría verificar primero con un GET). Esto indica por qué sería una mala idea usar solo el título como URL. Sin embargo, funcionaría en cualquier lugar donde hubiera una clave natural en los datos ... que en mi experiencia es rara. O si usó GUID
Nigel Thorne
221

Resumen:

Crear:

Se puede realizar con PUT o POST de la siguiente manera:

PONER

Crea EL nuevo recurso con newResourceId como identificador, bajo el / URI / colección .

PUT /resources/<newResourceId> HTTP/1.1 

ENVIAR

Crea un nuevo recurso en el / resources URI, o colección . Por lo general, el servidor devuelve el identificador.

POST /resources HTTP/1.1

Actualizar:

Puede solamente ser realizado con PUT de la siguiente manera:

PONER

Actualiza el recurso con existenteResourceId como identificador, bajo el / URI de recursos, o colección .

PUT /resources/<existingResourceId> HTTP/1.1

Explicación:

Cuando se trata de REST y URI como general, tiene genérico a la izquierda y específico a la derecha . Los genéricos generalmente se denominan colecciones y los elementos más específicos se pueden llamar recurso . Tenga en cuenta que un recurso puede contener una colección .

Ejemplos:

<- genérico - específico ->

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

Cuando usa POST siempre se refiere a una colección , así que cada vez que dice:

POST /users HTTP/1.1

Está publicando un nuevo usuario en la colección de usuarios .

Si continúas e intentas algo como esto:

POST /users/john HTTP/1.1

funcionará, pero semánticamente está diciendo que desea agregar un recurso a la colección de John en la colección de usuarios .

Una vez que está utilizando PUT, se está refiriendo a un recurso o elemento individual, posiblemente dentro de una colección . Entonces cuando dices:

PUT /users/john HTTP/1.1

le está diciendo a la actualización del servidor, o crea, si no existe, el recurso john en la colección de usuarios .

Especificaciones:

Permítanme resaltar algunas partes importantes de la especificación:

ENVIAR

El método POST se utiliza para solicitar que el servidor de origen acepte la entidad incluida en la solicitud como un nuevo subordinado del recurso identificado por el URI de solicitud en la línea de solicitud

Por lo tanto, crea un nuevo recurso en una colección .

PONER

El método PUT solicita que la entidad adjunta se almacene bajo el URI de solicitud proporcionado. Si el URI de solicitud se refiere a un recurso ya existente , la entidad adjunta DEBE considerarse como una versión modificada de la que reside en el servidor de origen. Si el Request-URI no apunta a una ya existente de recursos, y que URI es capaz de ser definido como un nuevo recurso por el agente de usuario que solicita, el servidor de origen puede crear el recurso con que URI ".

Por lo tanto, cree o actualice según la existencia del recurso .

Referencia:

7hi4g0
fuente
11
Esta publicación fue útil para mí al comprender que POST agrega "algo" como niño a la colección dada (URI), mientras que PUT define explícitamente el "algo" en la ubicación de URI dada.
kwah
3
Esta es la mejor respuesta, creo que aquí: ninguna de estas tonterías de "POST puede actualizar un recurso". Me gusta su afirmación, "La actualización solo se puede realizar con PUT".
Thomas
44
No, PUT no es para actualizar o crear. Es para reemplazar. Tenga en cuenta que no puede reemplazar nada con algo por el efecto de crear.
thecoshman
2
@ 7hi4g0 PUT es para actualizar con un reemplazo completo, en otras palabras, reemplaza. No reemplazas nada con algo, o algo con algo completamente nuevo. PUT no es para hacer un cambio menor (a menos que el cliente haga ese cambio menor y proporcione la nueva versión completa, incluso lo que sigue siendo el mismo). Para una modificación parcial, PATCH es el método de elección.
thecoshman
1
@thecoshman Podrías, pero no estaría demasiado claro que crear también está cubierto allí. En este caso, es mejor ser explícito.
7hi4g0
175

POST significa "crear nuevo" como en "Aquí está la entrada para crear un usuario, créelo por mí".

PUT significa "insertar, reemplazar si ya existe" como en "Aquí están los datos para el usuario 5".

Usted POSTa example.com/users ya que no conoce la URLdel usuario, sin embargo, desea que el servidor para crearlo.

Usted PUTa example.com/users/id~~V~~singular~~2nd ya que desea reemplazar / crear un determinado usuario.

PUBLICAR dos veces con los mismos datos significa crear dos usuarios idénticos con diferentes identificadores. PONER dos veces con los mismos datos crea al usuario el primero y lo actualiza al mismo estado la segunda vez (sin cambios). Como terminas con el mismo estado después de un, PUTno importa cuántas veces lo realices, se dice que es "igualmente potente" cada vez, idempotente. Esto es útil para volver a intentar automáticamente las solicitudes. No más '¿estás seguro de que deseas reenviar' cuando presionas el botón Atrás en el navegador?

Un consejo general es usar POSTcuando necesite que el servidor controle la URLgeneración de sus recursos. Use lo PUTcontrario. Prefiero PUT sobre POST.

Alexander Torstling
fuente
12
El descuido puede haber causado que se enseñe comúnmente que solo necesitas dos verbos: GET y POST. OBTENER para obtener, POST para cambiar. Incluso PUT y DELETE se realizaron usando POST. Preguntar qué significa PUT realmente 25 años después puede ser una señal de que al principio lo aprendimos mal. La popularidad de REST llevó a las personas a lo básico, donde ahora debemos desaprender los errores del pasado. POST fue usado en exceso y ahora comúnmente se enseña incorrectamente. La mejor parte: "PUBLICAR dos veces con los mismos datos significa crear dos [recursos] idénticos". Gran punto!
maxpolk
1
¿Cómo puede usar PUT para crear un registro por ID, como en su ejemplo user 5si aún no existe? No quiere decir update, replace if already exists? o algo así
Luke
@Coulton: quise decir lo que escribí. Inserta el usuario 5 si PONE a / users / 5 y el # 5 aún no existe.
Alexander Torstling
@Coulton: Y PUTtambién se puede usar para reemplazar el valor de un recurso existente en su totalidad.
DavidRR
1
"Prefiero PONER sobre POST" ... ¿te importa justificar eso?
thecoshman
173

Me gustaría agregar mi consejo "pragmático". Use PUT cuando sepa la "id" por la cual se puede recuperar el objeto que está guardando. El uso de PUT no funcionará demasiado bien si necesita, por ejemplo, una identificación generada en la base de datos que se devolverá para que realice futuras búsquedas o actualizaciones.

Entonces: Para guardar un usuario existente, o uno donde el cliente genera la identificación y se ha verificado que la identificación es única:

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

De lo contrario, use POST para crear inicialmente el objeto y PUT para actualizar el objeto:

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
fuente
17
En realidad, debería ser POST /users. (Tenga en cuenta que /userses plural.) Esto tiene el efecto de crear un nuevo usuario y convertirlo en un recurso secundario de la /userscolección.
DavidRR
66
@DavidRR para ser justos, cómo manejar grupos es otro debate por completo. GET /userstiene sentido, se lee como quieras, pero estaría de acuerdo con GET /user/<id>o POST /user(con la carga útil para dicho nuevo usuario) porque lee correctamente 'get me users 5' es extraño, pero 'get me user 5' es más natural. Sin embargo, probablemente aún caería del lado de la pluralización :)
thecoshman
126

Use POST para crear y PUT para actualizar. Así es como Ruby on Rails lo está haciendo, de todos modos.

PUT    /items/1      #=> update
POST   /items        #=> create
Tim Sullivan
fuente
44
POST /itemsagrega un nuevo elemento a un recurso ya definido ('elemento'). No, como dice la respuesta, "crea un grupo". No entiendo por qué esto tiene 12 votos.
David J.
Fuera de la caja, Rails no admite 'crear un grupo' a través de REST. Para 'crear un grupo' con lo que quiero decir 'crear un recurso' tienes que hacerlo a través del código fuente.
David J.
8
Esta es una directriz justa, pero una simplificación excesiva. Como mencionan las otras respuestas, cualquiera de los dos métodos podría usarse para crear y actualizar.
Brad Koch
2
Estoy de acuerdo con la respuesta con una ligera modificación. Use POST para crear y PUT para actualizar el recurso por completo. Para actualizaciones parciales, podemos usar PUT o PATCH. Digamos que queremos actualizar el estado de un grupo. Podemos usar PUT / groups / 1 / status con el estado de la carga útil de la solicitud o PATCH / groups / 1 con los detalles sobre la acción en la carga útil
java_geek
2
También debe quedar claro que PUT /items/42también es válido para crear un recurso, pero solo si el cliente tiene el privilegio de nombrar el recurso . (¿Rails permite a un cliente este privilegio de nomenclatura?)
DavidRR
123

Ambos se utilizan para la transmisión de datos entre el cliente al servidor, pero existen diferencias sutiles entre ellos, que son:

Ingrese la descripción de la imagen aquí

Analogía:

  • PONER, es decir, tomar y poner donde estaba.
  • PUBLICAR como enviar correo en la oficina de correos.

ingrese la descripción de la imagen aquí

Analogía de redes sociales / redes:

  • Publicar en las redes sociales: cuando publicamos un mensaje, se crea una nueva publicación.
  • Ponga (es decir, edite) el mensaje que ya publicamos.
Premraj
fuente
21
@MobileMon No, los métodos REST no son CRUDOS.
jlr
1
Yo diría PONER POR UPSERTS
Hola Soy Edu Feliz Navidad
@MobileMon no: POST cuando crea un nuevo recurso y no conoce el punto final para obtenerlo. PONER para otros casos.
Portekoi
67

REST es un concepto de muy alto nivel. De hecho, ¡ni siquiera menciona HTTP en absoluto!

Si tiene dudas sobre cómo implementar REST en HTTP, siempre puede consultar la especificación del Protocolo de publicación Atom (AtomPub) . AtomPub es un estándar para escribir servicios web RESTful con HTTP que fue desarrollado por muchas luminarias HTTP y REST, con algunos aportes de Roy Fielding, el inventor de REST y (co) inventor del propio HTTP.

De hecho, incluso podría usar AtomPub directamente. Si bien surgió de la comunidad de blogs, de ninguna manera se limita a los blogs: es un protocolo genérico para interactuar RESTAMENTE con colecciones arbitrarias (anidadas) de recursos arbitrarios a través de HTTP. Si puede representar su aplicación como una colección anidada de recursos, entonces puede usar AtomPub y no preocuparse por usar PUT o POST, qué códigos de estado HTTP devolver y todos esos detalles.

Esto es lo que AtomPub tiene que decir sobre la creación de recursos (sección 9.2):

Para agregar miembros a una Colección, los clientes envían solicitudes POST al URI de la Colección.

Jörg W Mittag
fuente
8
No hay nada de malo en permitir que PUT cree recursos. Solo tenga en cuenta que significa que el cliente proporciona la URL.
Julian Reschke
55
Hay algo muy malo en permitir que PUT cree recursos: el cliente proporciona la URL. Ese es el trabajo del servidor!
Joshcodes
@Joshcodes No siempre es el caso del trabajo del servidor crear identificadores de cliente. Cada vez más he visto diseños que permiten a los clientes generar algún tipo de UUID como la identificación del recurso. Este diseño se presta en particular para aumentar la escala.
Justin Ohms
@JustinOhms Estoy de acuerdo con su punto sobre las ID generadas por el cliente (nota al margen: todos los sistemas diseñados por mí desde alrededor de 2008 requieren que el cliente cree la ID como UUID / Guid). Eso no significa que el cliente deba especificar la URL.
Joshcodes
1
Sí, si el recurso ya existe, use PUT. Sin embargo, en casi todos los casos, los recursos deben crearse con POST y el cliente no debe proporcionar la URL. Roy Fielding está de acuerdo con esta declaración FWIW: roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
Joshcodes
61

La decisión de usar PUT o POST para crear un recurso en un servidor con una API HTTP + REST se basa en quién posee la estructura de URL. Hacer que el cliente sepa o participe en la definición, la estructura de URL es un acoplamiento innecesario similar a los acoplamientos indeseables que surgieron de SOA. Escapar de los tipos de acoplamientos es la razón por la cual REST es tan popular. Por lo tanto, el método apropiado para usar es POST. Hay excepciones a esta regla y ocurren cuando el cliente desea retener el control sobre la estructura de ubicación de los recursos que implementa. Esto es raro y probablemente significa que algo más está mal.

En este punto, algunas personas argumentarán que si se usan RESTful-URL , el cliente conoce la URL del recurso y, por lo tanto, un PUT es aceptable. Después de todo, esta es la razón por la cual las URL canónicas, normalizadas, Ruby on Rails, Django son importantes, mira la API de Twitter ... bla, bla, bla. Esas personas deben comprender que no existe una URL de reposo y que el propio Roy Fielding afirma que :

Una API REST no debe definir nombres de recursos fijos o jerarquías (un acoplamiento obvio de cliente y servidor). Los servidores deben tener la libertad de controlar su propio espacio de nombres. En cambio, permita que los servidores instruyan a los clientes sobre cómo construir los URI apropiados, como se hace en formularios HTML y plantillas de URI, definiendo esas instrucciones dentro de los tipos de medios y las relaciones de enlace. [La falla aquí implica que los clientes están asumiendo una estructura de recursos debido a la información fuera de banda, como un estándar específico de dominio, que es el equivalente orientado a datos al acoplamiento funcional de RPC].

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

La idea de una URL RESTful es en realidad una violación de REST ya que el servidor está a cargo de la estructura de la URL y debe ser libre de decidir cómo usarla para evitar el acoplamiento. Si esto le confunde, lea acerca de la importancia del autodescubrimiento en el diseño de API.

El uso de POST para crear recursos viene con una consideración de diseño porque POST no es idempotente. Esto significa que repetir una POST varias veces no garantiza el mismo comportamiento cada vez. Esto asusta a las personas a usar PUT para crear recursos cuando no deberían. Saben que está mal (POST es para CREATE) pero lo hacen de todos modos porque no saben cómo resolver este problema. Esta preocupación se demuestra en la siguiente situación:

  1. El cliente POST un nuevo recurso al servidor.
  2. El servidor procesa la solicitud y envía una respuesta.
  3. El cliente nunca recibe la respuesta.
  4. El servidor no sabe que el cliente no ha recibido la respuesta.
  5. El cliente no tiene una URL para el recurso (por lo tanto, PUT no es una opción) y repite la POST.
  6. POST no es idempotente y el servidor ...

El paso 6 es donde las personas comúnmente se confunden acerca de qué hacer. Sin embargo, no hay razón para crear un error para resolver este problema. En cambio, HTTP se puede usar como se especifica en RFC 2616 y el servidor responde:

10.4.10 409 Conflicto

La solicitud no se pudo completar debido a un conflicto con el estado actual del recurso. Este código solo se permite en situaciones en las que se espera que el usuario pueda resolver el conflicto y volver a enviar la solicitud. El cuerpo de respuesta DEBE incluir suficiente

información para que el usuario reconozca la fuente del conflicto. Idealmente, la entidad de respuesta incluiría suficiente información para que el usuario o agente de usuario solucione el problema; sin embargo, eso podría no ser posible y no es obligatorio.

Es más probable que ocurran conflictos en respuesta a una solicitud PUT. Por ejemplo, si se usaban versiones y la entidad que se PUT incluía cambios en un recurso que entran en conflicto con los realizados por una solicitud anterior (de terceros), el servidor podría usar la respuesta 409 para indicar que no puede completar la solicitud . En este caso, la entidad de respuesta probablemente contendría una lista de las diferencias entre las dos versiones en un formato definido por el Tipo de contenido de respuesta.

Responder con un código de estado de 409 Conflict es el recurso correcto porque :

  • Realizar una POST de datos que tiene una ID que coincide con un recurso que ya está en el sistema es "un conflicto con el estado actual del recurso".
  • Dado que la parte importante es que el cliente comprenda que el servidor tiene el recurso y que tome las medidas apropiadas. Esta es una "situación (es) en la que se espera que el usuario pueda resolver el conflicto y volver a enviar la solicitud".
  • Una respuesta que contiene la URL del recurso con la ID en conflicto y las condiciones previas apropiadas para el recurso proporcionaría "información suficiente para que el usuario o agente de usuario solucione el problema", que es el caso ideal según RFC 2616.

Actualización basada en el lanzamiento de RFC 7231 para reemplazar 2616

RFC 7231 está diseñado para reemplazar 2616 y en la Sección 4.3.3 describe la siguiente respuesta posible para un POST

Si el resultado del procesamiento de una POST sería equivalente a una representación de un recurso existente, un servidor de origen PUEDE redirigir al agente de usuario a ese recurso enviando una respuesta 303 (Ver Otros) con el identificador del recurso existente en el campo Ubicación. Esto tiene los beneficios de proporcionar al agente de usuario un identificador de recursos y transferir la representación a través de un método más adecuado para el almacenamiento en caché compartido, aunque a costa de una solicitud adicional si el agente de usuario aún no tiene la representación en caché.

Ahora puede ser tentador simplemente devolver un 303 en caso de que se repita un POST. Sin embargo, lo opuesto es verdadero. Devolver un 303 solo tendría sentido si varias solicitudes de creación (creación de diferentes recursos) devuelven el mismo contenido. Un ejemplo sería un "gracias por enviar su mensaje de solicitud" que el cliente no necesita volver a descargar cada vez. RFC 7231 aún mantiene en la sección 4.2.2 que POST no debe ser idempotente y continúa manteniendo que POST debe usarse para crear.

Para obtener más información sobre esto, lea este artículo .

Joshcodes
fuente
¿Sería una respuesta al conflicto 409 el código apropiado para algo como intentar crear una nueva cuenta con un nombre de usuario que ya existe? He estado usando 409 para conflictos de versiones específicamente, pero después de leer su respuesta, me pregunto si no debería usarse para ninguna solicitud "duplicada".
Eric B.
@EricB. Sí, en la situación que describe "debido a un conflicto con el estado actual del recurso", la operación falla. Además, es razonable esperar que el usuario pueda resolver el conflicto y el cuerpo del mensaje solo necesita informarle que el nombre de usuario ya existe.
Joshcodes
@Joshcodes, ¿puedes decir más sobre el proceso de resolución de conflictos? En este caso, si el nombre de usuario ya existe, ¿se espera que el cliente solicite al usuario final un nombre de usuario diferente? ¿Qué sucede si el cliente realmente está tratando de usar POST para cambiar el nombre de usuario? ¿Deberían utilizarse las solicitudes PUT para actualizar los parámetros, mientras que la POST se utiliza para crear objetos, ya sea uno a la vez o varios? Gracias.
BFar
@ BFar2 si el nombre de usuario ya existe, entonces el cliente debe avisar al usuario. Para cambiar el nombre de usuario, suponiendo que el nombre de usuario es parte de un recurso ya creado que necesita ser modificado, PUT se usaría porque está en lo correcto, POST se usa para crear, siempre y PUT para actualizaciones.
Joshcodes
explicar cosas usando un lenguaje corto y efectivo también es una habilidad deseable
Junchen Liu
53

Me gusta este consejo, de la definición de PUT del RFC 2616 :

La diferencia fundamental entre las solicitudes POST y PUT se refleja en el significado diferente del Request-URI. El URI en una solicitud POST identifica el recurso que manejará la entidad adjunta. Ese recurso podría ser un proceso de aceptación de datos, una puerta de enlace a algún otro protocolo o una entidad separada que acepte anotaciones. Por el contrario, el URI en una solicitud PUT identifica la entidad adjunta a la solicitud: el agente de usuario sabe a qué se destina el URI y el servidor NO DEBE intentar aplicar la solicitud a otro recurso.

Esto concuerda con el otro consejo aquí, que PUT se aplica mejor a los recursos que ya tienen un nombre, y POST es bueno para crear un nuevo objeto bajo un recurso existente (y dejar que el servidor lo nombre).

Interpreto que esto y los requisitos de idempotencia en PUT significan que:

  • POST es bueno para crear nuevos objetos bajo una colección (y crear no necesita ser idempotente)
  • PUT es bueno para actualizar objetos existentes (y la actualización debe ser idempotente)
  • POST también se puede usar para actualizaciones no idempotentes a objetos existentes (especialmente, cambiar parte de un objeto sin especificar todo; si lo piensa, crear un nuevo miembro de una colección es realmente un caso especial de este tipo de actualización, desde la perspectiva de la colección)
  • PUT también se puede usar para crear si y solo si permite que el cliente nombre el recurso. Pero dado que no se supone que los clientes REST hagan suposiciones sobre la estructura de URL, esto es menos en el espíritu de las cosas.
metamatt
fuente
3
"POST también se puede usar para actualizaciones no idempotentes de objetos existentes (especialmente, cambiar parte de un objeto sin especificar todo". Para eso está PATCH
Snuggs,
48

En breve:

PUT es idempotente, donde el estado del recurso será el mismo si la misma operación se ejecuta una o varias veces.

POST no es idempotente, donde el estado del recurso puede ser diferente si la operación se ejecuta varias veces en comparación con la ejecución de una sola vez.

Analogía con consulta de base de datos

PUT Puede pensar en algo similar a "ACTUALIZAR SET DE ESTUDIANTE address =" abc "donde id =" 123 ";

POST Puede pensar en algo como "INSERTAR EN EL ESTUDIANTE (nombre, dirección) VALORES (" abc "," xyzzz ");

La identificación del estudiante se genera automáticamente.

Con PUT, si la misma consulta se ejecuta varias veces o una vez, el estado de la tabla ESTUDIANTE permanece igual.

En el caso de POST, si la misma consulta se ejecuta varias veces, se crean múltiples registros de Estudiantes en la base de datos y el estado de la base de datos cambia en cada ejecución de una consulta "INSERTAR".

NOTA: PUT necesita una ubicación de recursos (ya-resource) en la que debe realizarse la actualización, mientras que POST no lo requiere. Por lo tanto, intuitivamente POST está destinado a la creación de un nuevo recurso, mientras que PUT es necesario para actualizar el recurso ya existente.

Algunos pueden pensar que las actualizaciones se pueden realizar con POST. No hay una regla estricta sobre cuál usar para las actualizaciones o cuál usar para crear. Nuevamente, estas son convenciones, e intuitivamente me inclino por el razonamiento mencionado anteriormente y lo sigo.

bharatj
fuente
66
para PUT es similar a INSERT o UPDATE consulta
Eugen Konkov
1
en realidad PONER Puede pensar en algo similar a "ACTUALIZAR SET SET DE ESTUDIANTE =" abc "donde id =" 123 "; sería una declaración para PATCH." ACTUALIZAR SET SET DE ESTUDIANTE address = "abc", name = "newname" donde id = " 123 "sería una analogía correcta para PUT
mko
Put también podría usarse para INSERTAR. Por ejemplo, si su servidor detectó que intentaba cargar el mismo archivo varias veces, su solicitud sería idempotente. (No se realizan nuevas cargas de archivos).
kiwicomb123
43

POST es como publicar una carta en un buzón o publicar un correo electrónico en una cola de correo electrónico. PUT es como cuando pones un objeto en un agujero de cubículo o en un lugar en un estante (tiene una dirección conocida).

Con POST, estás publicando en la dirección de la COLA o COLECCIÓN. Con PUT, está ingresando a la dirección del ARTÍCULO.

PUT es idempotente. Puede enviar la solicitud 100 veces y no importará. POST no es idempotente. Si envía la solicitud 100 veces, recibirá 100 correos electrónicos o 100 cartas en su casilla postal.

Una regla general: si conoce la identificación o el nombre del artículo, use PUT. Si desea que la parte receptora asigne la identificación o el nombre del artículo, use POST.

POST versus PUT

Homero6
fuente
1
No, PUT implica que conoce la URL. Si solo conoce la ID, POSTE con esa ID para obtener la URL.
Joshcodes
66
La identificación es parte de la URL, así que sí, use PUT si conoce la URL (que incluye la identificación).
Homer6
No, el servidor determina la URL y la ID no es necesariamente parte de la URL. Roy Fielding te diría lo mismo o podrías leer su tesis .
Joshcodes
@Joshcodes, ¿es eso asumiendo REST? En una arquitectura RESTful, la identificación del elemento es definitivamente parte de la URL, como en: / people / 123. Me gusta este sitio para REST: microformats.org/wiki/rest/urls
Beez
1
@Beez el enlace mircoformats sugiere una buena manera para que los servidores estructuran sus URL, pero el servidor determina la URL. El cliente casi nunca lo hace. Vea mi respuesta o artículo asociado si no entiende esto.
Joshcodes
39

Nueva respuesta (ahora que entiendo REST mejor):

PUT es simplemente una declaración de qué contenido debe usar el servicio, de ahora en adelante, para representar el recurso identificado por el cliente; POST es una declaración de qué contenido debe contener el servicio, de ahora en adelante, (posiblemente duplicado), pero depende del servidor cómo identificar ese contenido.

PUT x(si xidentifica un recurso ): "Reemplace el contenido del recurso identificado por xcon mi contenido".

PUT x(si xno identifica un recurso): "Crear un nuevo recurso que contenga mi contenido y utilizarlo xpara identificarlo".

POST x: "Almacenar mi contenido y darme un identificador que pueda usar para identificar un recurso (antiguo o nuevo) que contenga dicho contenido (posiblemente mezclado con otro contenido). Dicho recurso debe ser idéntico o subordinado al que xidentifica". " Y 's de recursos está subordinada a x ' recurso s" es típicamente, pero no necesariamente implementado por hacer y una subruta de x (por ejemplo, x = /fooy y = /foo/bar) y la modificación de la representación (s) de x recurso 's para reflejar la existencia de un nuevo recurso, por ejemplo, con un hipervínculo a yEl recurso y algunos metadatos. Solo esto último es realmente esencial para un buen diseño, ya que las URL son opacas en REST: se supone que debe usar hipermedia en lugar de la construcción de URL del lado del cliente para atravesar el servicio de todos modos.

En REST, no existe un recurso que contenga "contenido". Me refiero como "contenido" a los datos que el servicio utiliza para representar representaciones de manera consistente. Por lo general, consta de algunas filas relacionadas en una base de datos o un archivo (por ejemplo, un archivo de imagen). Depende del servicio convertir el contenido del usuario en algo que el servicio pueda usar, por ejemplo, convertir una carga útil JSON en declaraciones SQL.

Respuesta original (podría ser más fácil de leer) :

PUT /something(si /somethingya existe): "Toma lo que tengas /somethingy reemplázalo con lo que te doy".

PUT /something(si /somethingaún no existe): "Toma lo que te doy y ponlo en /something".

POST /something: "Toma lo que te doy y ponlo donde quieras /something, siempre que me des su URL cuando hayas terminado".

Jordán
fuente
Pero, ¿cómo puede usar PUT para crear un nuevo recurso si no existe, mientras su método de generación de ID está en Incremento automático? Por lo general, ORM genera automáticamente la ID para usted, como la forma en que desea que esté en una POST, por ejemplo. ¿Significa que si desea implementar PUT de la manera correcta, debe cambiar su generación automática de id? Esto es incómodo si la respuesta es sí.
Roni Axelrad
1
@RoniAxelrad: PUT es como una declaración de la base de datos "INSERTAR O ACTUALIZAR" en la que se incluye la clave en la declaración, por lo que solo es aplicable donde no se pueden garantizar colisiones. p.ej. su dominio tiene una 'clave natural' o usa un guid. POST es como insertar en una tabla con una clave de incremento automático. La base de datos debe indicarle qué ID obtuvo después de que se haya insertado. Tenga en cuenta que su "INSERTAR O ACTUALIZAR" reemplazará los datos anteriores si existieran.
Nigel Thorne
@NigelThorne Gracias por tu respuesta. Entonces, si por ejemplo estoy tratando de PONER un id de libro 10 con un URI: PUT books / 10. Si la identificación del libro 10 no existe, debería crear un libro con la identificación 10 ¿verdad? pero no puedo controlar el numerador de ID de creación, porque es un incremento automático. ¿Qué debo hacer en esa situación?
Roni Axelrad
1
@RoniAxelrad REST PUT a una ID que no existe es una solicitud al servidor para crear un recurso. Todavía depende del servidor decidir si quiere permitir eso. El servidor está a cargo. Puede responder con "No. No voy a hacer eso". Ya lo haces si el usuario no tiene suficientes permisos ... etc. Está bien que el servidor diga "No". REST es una convención que nos permite definir el significado de varios tipos de solicitud ... su servidor decide qué hacer con esas solicitudes en función de su lógica empresarial :) Incluso si dice "no", sigue siguiendo REST :)
Nigel Thorne
38

Respuesta corta:

Regla simple: use POST para crear, use PUT para actualizar.

Respuesta larga:

ENVIAR:

  • POST se utiliza para enviar datos al servidor.
  • Útil cuando la URL del recurso es desconocida

PONER:

  • PUT se usa para transferir el estado al servidor
  • Útil cuando se conoce la URL de un recurso

Respuesta larga:

Para entenderlo, debemos preguntarnos por qué se requirió PUT, cuáles fueron los problemas que PUT estaba tratando de resolver que POST no pudo.

Desde el punto de vista de una arquitectura REST, no hay nada que importe. Podríamos haber vivido sin PUT también. Pero desde el punto de vista del desarrollador de un cliente, hizo su vida mucho más simple.

Antes de PUT, los clientes no podían conocer directamente la URL que generó el servidor o si todo lo que había generado o si los datos que se enviarán al servidor ya están actualizados o no. PUT alivió al desarrollador de todos estos dolores de cabeza. PUT es idempotente, PUT maneja las condiciones de carrera y PUT le permite al cliente elegir la URL.

ishandutta2007
fuente
3
Su respuesta corta podría estar MUY equivocada. HTTP PUT es libre de ser repetido por proxies HTTP. Y así, si PUT realmente está haciendo SQL INSERT, podría fallar la segunda vez, lo que significa que devolvería un resultado diferente y, por lo tanto, no sería IDEMPOTENTE (que es la diferencia entre PUT y POST)
Kamil Tomšík
36

Ruby on Rails 4.0 utilizará el método 'PATCH' en lugar de PUT para realizar actualizaciones parciales.

RFC 5789 dice acerca de PATCH (desde 1995):

Es necesario un nuevo método para mejorar la interoperabilidad y evitar errores. El método PUT ya está definido para sobrescribir un recurso con un cuerpo completamente nuevo, y no se puede reutilizar para realizar cambios parciales. De lo contrario, los servidores proxy y las memorias caché, e incluso los clientes y servidores, pueden confundirse con el resultado de la operación. POST ya se usa, pero sin una amplia interoperabilidad (por ejemplo, no hay una forma estándar de descubrir el soporte de formato de parche). PATCH se mencionó en especificaciones HTTP anteriores, pero no está completamente definido.

" Edge Rails: PATCH es el nuevo método HTTP primario para las actualizaciones ", lo explica.

germanlinux
fuente
27

A riesgo de repetir lo que ya se ha dicho, parece importante recordar que PUT implica que el cliente controla lo que la URL terminará siendo, al crear un recurso. Por lo tanto, parte de la elección entre PUT y POST será sobre cuánto puede confiar en el cliente para proporcionar una URL correcta y normalizada que sea coherente con cualquier esquema de URL.

Cuando no puede confiar plenamente en que el cliente haga lo correcto, sería más apropiado usar POST para crear un nuevo elemento y luego enviar la URL de vuelta al cliente en la respuesta.

ladrón de sartén
fuente
2
Llegué un poco tarde a esto, pero alguien que dijo algo similar en otro sitio web hizo que hiciera clic por mí. Si está creando un recurso y está utilizando una ID de incremento automático ya que es "identificador" en lugar de un nombre asignado por el usuario, debe ser una POST.
Ixmatus
2
Esto no es del todo bien - PUT todavía puede crear un recurso refiriéndose a ella con un nombre no canónica, siempre y cuando en la respuesta, el servidor devuelve un Locationencabezado que no contiene el nombre del recurso canónico.
Ether
1
@Joshcodes no olvide que puede tener muchos URI que hagan referencia al mismo recurso subyacente. Entonces, ¿qué Éter dijo es un buen consejo, el cliente puede poner en un enlace (que podría ser más semántica, al igual que PUT /X-files/series/4/episodes/max) y responde el servidor con un URI que proporciona un enlace corto canónica única para ese nuevo recurso (es decir /X-Ffiles/episodes/91)
thecoshman
@thecoshman el problema es que la estructura de URL no le concierne al cliente. Leer sobre el autodescubrimiento (también parte de REST) ​​puede ayudar a aclarar esto.
Joshcodes
@Joshcodes, según esa lógica, un cliente nunca debe usar PUT para crear, ya que no debe preocuparse por proporcionar la URL. Bueno ... a menos que el servidor proporcione una URL para PUT si el cliente quiere ponerlo ... algo como "PUT / comments / new" y el servidor podría responder "204 / comments / 234532" pero eso parece un poco RPC para mí, el cliente debería simplemente
PUBLICAR
24

De una manera muy simple, estoy tomando el ejemplo de la línea de tiempo de Facebook.

Caso 1: cuando publica algo en su línea de tiempo, es una nueva entrada nueva. Entonces, en este caso, usan el método POST porque el método POST no es idempotente.

Caso 2: si su amigo comenta su publicación la primera vez, eso también creará una nueva entrada en la base de datos para que se utilice el método POST.

Caso 3: si su amigo edita su comentario, en este caso, tenía una identificación de comentario, por lo que actualizará un comentario existente en lugar de crear una nueva entrada en la base de datos. Por lo tanto, para este tipo de operación, utilice el método PUT porque es idempotente. *

En una sola línea, use POST para agregar una nueva entrada en la base de datos y PUT para actualizar algo en la base de datos.

UniCoder
fuente
44
Si el comentario es un objeto con propiedades como ID de usuario, fecha de creación, mensaje de comentario, etc., y en el momento de la edición solo se actualiza el mensaje de comentario, ¿se debe hacer PATCH aquí?
Habeeb Perwad
FB usa PUT para actualizar el comentario porque se está actualizando un recurso existente, y eso es lo que hace PUT (actualiza un recurso). PUT pasa a ser idempotente, en contraste con POST. Un verbo HTTP que sea idempotente afecta el manejo de errores pero no dicta el uso. Vea mi respuesta para obtener una explicación más detallada: stackoverflow.com/questions/630453/put-vs-post-in-rest/…
Joshcodes
21

La consideración más importante es la fiabilidad . Si se pierde un mensaje POST, el estado del sistema no está definido. La recuperación automática es imposible. Para los mensajes PUT, el estado no está definido hasta el primer reintento exitoso.

Por ejemplo, puede que no sea una buena idea crear transacciones con tarjeta de crédito con POST.

Si tiene URI generados automáticamente en su recurso, aún puede usar PUT pasando un URI generado (señalando un recurso vacío) al cliente.

Algunas otras consideraciones:

  • POST invalida copias en caché de todo el recurso que contiene (mejor consistencia)
  • Las respuestas PUT no se pueden almacenar en caché mientras que las POST sí (Requerir ubicación de contenido y caducidad)
  • PUT es menos compatible con, por ejemplo, Java ME, navegadores antiguos, firewalls
Hans Malherbe
fuente
Esto es incorrecto. Para la POST, el Estado también está definido solamente hasta el primer reintento éxito. Luego, el servidor acepta la POST (el mensaje nunca llegó), arroja un conflicto 409 por una ID duplicada (mensaje recibido, la respuesta se perdió) o cualquier otra respuesta válida.
Joshcodes
En general, un agente de uso no podría volver a intentar la operación POST de forma segura, ya que la operación POST no garantiza que dos operaciones tengan el mismo efecto que una. El término "ID" no tiene nada que ver con HTTP. El URI identifica el recurso.
Hans Malherbe
Un agente de uso puede volver a intentar "con seguridad" una operación POST tantas veces como lo desee. Solo recibirá un error de ID duplicado (suponiendo que el recurso tenga una ID) o un error de datos duplicados (suponiendo que sea un problema y que el recurso no tenga ID).
Joshcodes
Golpea la cabeza contra la pared. HTTP no tiene solución para el problema de la confiabilidad, y esto no se entiende bien, no se discute mucho y simplemente no se atiende en la gran mayoría de las aplicaciones web. @Joshcodes Tengo una respuesta a esta pregunta. Estoy esencialmente de acuerdo con Hans. Hay un problema.
bbsimonbb
@bbsimonbb, HTTP tiene un conjunto robusto y bien documentado de respuestas de error. Mi respuesta a esta pregunta ( stackoverflow.com/questions/630453/put-vs-post-in-rest/… ) cubre cómo usar http de acuerdo con las especificaciones para lograr consistencia.
Joshcodes
17

Los lectores nuevos en este tema se sorprenderán con la discusión interminable sobre lo que debe hacer y la relativa ausencia de lecciones de la experiencia. El hecho de que REST sea "preferido" sobre SOAP es, supongo, un aprendizaje de alto nivel de la experiencia, pero ¿Dios debe haber progresado desde allí? Es 2016. La tesis de Roy fue en 2000. ¿Qué hemos desarrollado? ¿Fue divertido? ¿Fue fácil integrarse? ¿Apoyar? ¿Manejará el auge de los teléfonos inteligentes y las conexiones móviles inestables?

Según ME, las redes de la vida real no son confiables. Solicitudes de tiempo de espera. Se restablecen las conexiones. Las redes se caen durante horas o días a la vez. Los trenes van a túneles con usuarios móviles a bordo. Para cualquier solicitud dada (como se reconoce ocasionalmente en toda esta discusión), la solicitud puede caer en el agua en su camino, o la respuesta puede caer en el agua en su camino de regreso. En estas condiciones, emitir solicitudes PUT, POST y DELETE directamente contra recursos sustantivos siempre me ha parecido un poco brutal e ingenuo.

HTTP no hace nada para garantizar la finalización confiable de la solicitud-respuesta, y eso está bien porque este es adecuadamente el trabajo de las aplicaciones conscientes de la red. Al desarrollar una aplicación de este tipo, puede saltar a través de los aros para usar PUT en lugar de POST, luego más aros para dar un cierto tipo de error en el servidor si detecta solicitudes duplicadas. De vuelta en el cliente, debe saltar por los aros para interpretar estos errores, volver a buscar, revalidar y volver a publicar.

O puede hacer esto : considere sus solicitudes inseguras como recursos efímeros de un solo usuario (llamémoslas acciones). Los clientes solicitan una nueva "acción" en un recurso sustantivo con una POST vacía al recurso. POST se usará solo para esto. Una vez que posee de forma segura el URI de la acción recién emitida, el cliente PONE la solicitud insegura al URI de acción, no el recurso objetivo . Resolver la acción y actualizar el recurso "real" es adecuadamente el trabajo de su API, y aquí se desacopla de la red no confiable.

El servidor hace el negocio, devuelve la respuesta y la almacena contra el URI de acción acordado . Si algo sale mal, el cliente repite la solicitud (¡comportamiento natural!), Y si el servidor ya lo ha visto, repite la respuesta almacenada y no hace nada más .

Rápidamente detectará la similitud con las promesas: creamos y devolvemos el marcador de posición para el resultado antes de hacer nada. También como una promesa, una acción puede tener éxito o fracasar una vez, pero su resultado se puede obtener repetidamente.

Lo mejor de todo es que brindamos a las aplicaciones de envío y recepción la oportunidad de vincular la acción identificada de forma única con la unicidad en sus respectivos entornos. ¡Y podemos comenzar a exigir y hacer cumplir !, un comportamiento responsable de los clientes: repita sus solicitudes tanto como desee, pero no vaya a generar una nueva acción hasta que esté en posesión de un resultado definitivo de la existente.

Como tal, numerosos problemas espinosos desaparecen. Las solicitudes de inserción repetidas no crearán duplicados, y no creamos el recurso real hasta que tengamos los datos. (las columnas de la base de datos pueden permanecer no anulables). Las solicitudes de actualización repetidas no afectarán a los estados incompatibles y no sobrescribirán los cambios posteriores. Los clientes pueden (re) buscar y procesar sin problemas la confirmación original por cualquier motivo (el cliente se bloqueó, la respuesta se perdió, etc.).

Las solicitudes de eliminación sucesivas pueden ver y procesar la confirmación original, sin dar con un error 404. Si las cosas tardan más de lo esperado, podemos responder provisionalmente, y tenemos un lugar donde el cliente puede verificar el resultado definitivo. La mejor parte de este patrón es su propiedad Kung-Fu (Panda). Tomamos una debilidad, la propensión a que los clientes repitan una solicitud cada vez que no entienden la respuesta, y la convertimos en una fortaleza :-)

Antes de decirme que esto no es RESTful, considere las numerosas formas en que se respetan los principios REST. Los clientes no construyen URL. La API permanece reconocible, aunque con un pequeño cambio en la semántica. Los verbos HTTP se usan apropiadamente. Si cree que este es un gran cambio para implementar, puedo decirle por experiencia que no lo es.

Si cree que tendrá grandes cantidades de datos para almacenar, hablemos de volúmenes: una confirmación de actualización típica es una fracción de kilobyte. HTTP actualmente le da un minuto o dos para responder definitivamente. Incluso si solo almacena acciones durante una semana, los clientes tienen muchas posibilidades de ponerse al día. Si tiene volúmenes muy altos, es posible que desee un almacén de valores clave dedicado que cumpla con el ácido o una solución en memoria.

bbsimonbb
fuente
1
¿No almacenar la respuesta será como mantener una sesión? Lo que causaría problemas de escalamiento (horizontal).
Saurabh Harwande
17

Además de las diferencias sugeridas por otros, quiero agregar una más.

En el método POST puede enviar parámetros del cuerpo enform-data

En el método PUT , debe enviar parámetros del cuerpo enx-www-form-urlencoded

Encabezamiento Content-Type:application/x-www-form-urlencoded

De acuerdo con esto, no puede enviar archivos o datos multiparte en el método PUT

EDITAR

El tipo de contenido "application / x-www-form-urlencoded" es ineficiente para enviar grandes cantidades de datos binarios o texto que contenga caracteres no ASCII. El tipo de contenido "multipart / form-data" debe usarse para enviar formularios que contienen archivos, datos no ASCII y datos binarios.

Lo que significa que si tiene que enviar

archivos, datos no ASCII y datos binarios

deberías usar el método POST

Rohit Dhiman
fuente
3
¿Por qué esto no fue votado? Si es verdad, esta es una distinción crítica, ¿no es así?
Iofacture
2
Lo enfrenté al implementar la API para la actualización del perfil, que incluye la carga de imágenes de perfil de usuario. Luego lo probé con el cartero, Ajax, PHP curl y laravel 5.6 como backend.
Rohit Dhiman
14

Parece que siempre hay cierta confusión sobre cuándo usar HTTP POST versus el método HTTP PUT para los servicios REST. La mayoría de los desarrolladores tratarán de asociar las operaciones CRUD directamente a los métodos HTTP. Argumentaré que esto no es correcto y que uno no puede simplemente asociar los conceptos CRUD a los métodos HTTP. Es decir:

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

Es cierto que R (etrieve) y D (elete) de las operaciones CRUD se pueden asignar directamente a los métodos HTTP GET y DELETE respectivamente. Sin embargo, la confusión radica en las operaciones C (reate) y U (actualización). En algunos casos, se puede usar PUT para crear, mientras que en otros casos se requerirá una POST. La ambigüedad radica en la definición de un método HTTP PUT versus un método HTTP POST.

De acuerdo con las especificaciones HTTP 1.1, los métodos GET, HEAD, DELETE y PUT deben ser idempotentes, y el método POST no es idempotente. Es decir que una operación es idempotente si se puede realizar en un recurso una o varias veces y siempre devuelve el mismo estado de ese recurso. Mientras que una operación no idempotente puede devolver un estado modificado del recurso de una solicitud a otra. Por lo tanto, en una operación no idempotente, no hay garantía de que uno reciba el mismo estado de un recurso.

Según la definición idempotente anterior, mi opinión sobre el uso del método HTTP PUT frente al uso del método HTTP POST para los servicios REST es: Use el método HTTP PUT cuando:

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).

En ambos casos, estas operaciones se pueden realizar varias veces con los mismos resultados. Es decir, el recurso no se cambiará solicitando la operación más de una vez. Por lo tanto, una verdadera operación idempotente. Utilice el método HTTP POST cuando:

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.

Conclusión

No correlacione y asigne directamente operaciones CRUD a métodos HTTP para servicios REST. El uso de un método HTTP PUT versus un método HTTP POST debe basarse en el aspecto idempotente de esa operación. Es decir, si la operación es idempotente, utilice el método HTTP PUT. Si la operación no es idempotente, utilice el método HTTP POST.

Burhan
fuente
2
Actualización => HTTP POST: POST no es para actualizar
Premraj
@premraj Has asumido que Burhan te está diciendo que no hagas; a saber, está combinando CRUD, REST y HTTP. Si lee RFC 7231, donde se definen estas cosas, encontrará que en el protocolo HTTP, la definición de POST ciertamente permite la actualización. Son solo las restricciones de REST las que dicen lo contrario.
IAM_AL_X
13

el servidor de origen puede crear el recurso con ese URI

Entonces usa POST y probablemente, pero no es necesario PUT para la creación de recursos. No tienes que apoyar a ambos. Para mí POST es perfectamente suficiente. Por lo tanto, es una decisión de diseño.

Como se mencionó en su cotización, usted usa PUT para crear un recurso no asignado a un IRI, y de todos modos desea crear un recurso. Por ejemplo, PUT /users/123/passwordgeneralmente reemplaza la contraseña anterior por una nueva, pero puede usarla para crear una contraseña si aún no existe (por ejemplo, por usuarios recién registrados o restaurando usuarios prohibidos).

inf3rno
fuente
Creo que ha logrado proporcionar uno de los pocos buenos ejemplos de cómo usar PUT, bien hecho.
thecoshman
12

Voy a aterrizar con lo siguiente:

PUT se refiere a un recurso, identificado por el URI. En este caso, lo está actualizando. Es la parte de los tres verbos que se refieren a los recursos: eliminar y obtener los otros dos.

POST es básicamente un mensaje de forma libre, cuyo significado se define "fuera de banda". Si se puede interpretar que el mensaje agrega un recurso a un directorio, estaría bien, pero básicamente debe comprender el mensaje que envía (publicar) para saber qué sucederá con el recurso.


Debido a que PUT y GET y DELETE se refieren a un recurso, también son, por definición, idempotentes.

POST puede realizar las otras tres funciones, pero luego la semántica de la solicitud se perderá en los intermediarios como cachés y servidores proxy. Esto también se aplica a proporcionar seguridad en el recurso, ya que el URI de una publicación no necesariamente indica el recurso al que se aplica (aunque puede).

Un PUT no necesita ser una creación; el servicio podría producir un error si el recurso aún no se ha creado, pero de lo contrario, actualícelo. O viceversa: puede crear el recurso, pero no permitir actualizaciones. Lo único que se requiere sobre PUT es que apunta a un recurso específico y su carga útil es la representación de ese recurso. Un PUT exitoso significa (salvo interferencia) que un GET recuperaría el mismo recurso.


Editar: Una cosa más: un PUT puede crear, pero si lo hace, la ID debe ser una ID natural, también conocida como una dirección de correo electrónico. De esa manera, cuando PUT dos veces, el segundo puesto es una actualización del primero. Esto lo hace idempotente .

Si se genera la ID (una nueva ID de empleado, por ejemplo), el segundo PUT con la misma URL crearía un nuevo registro, lo que viola la regla idempotente. En este caso, el verbo sería POST y el mensaje (no recurso) sería crear un recurso utilizando los valores definidos en este mensaje.

Gerard ONeill
fuente
9

Se supone que la semántica es diferente, ya que se supone que "PUT", como "GET", es idempotente, lo que significa que puede hacer la misma solicitud PUT exacta varias veces y el resultado será como si la hubiera ejecutado solo una vez.

Describiré las convenciones que creo son las más utilizadas y las más útiles:

Cuando pone un recurso en una URL particular, lo que sucede es que debe guardarse en esa URL, o algo por el estilo.

Cuando PUBLICA en un recurso en una URL en particular, a menudo publica una información relacionada en esa URL. Esto implica que el recurso en la URL ya existe.

Por ejemplo, cuando desea crear una nueva transmisión, puede PONERLA en alguna URL. Pero cuando desea PUBLICAR un mensaje en una secuencia existente, PUBLICA en su URL.

En cuanto a la modificación de las propiedades de la secuencia, puede hacerlo con PUT o POST. Básicamente, solo use "PUT" cuando la operación sea idempotente; de ​​lo contrario, use POST.

Sin embargo, tenga en cuenta que no todos los navegadores modernos admiten verbos HTTP que no sean GET o POST.

Gregory Magarshak
fuente
Lo que usted describe como POST es cómo debería comportarse PATCH. Se supone que POST significa algo más parecido a "agregar" como en "publicar en la lista de correo".
Alexander Torstling
8

La mayoría de las veces, los usará así:

  • ENVIAR un recurso en una colección
  • PONER un recurso identificado por colección /: id

Por ejemplo:

  • POST / artículos
  • PUT / artículos / 1234

En ambos casos, el cuerpo de la solicitud contiene los datos del recurso que se creará o actualizará. Debe ser obvio por los nombres de ruta que POST no es idempotente (si lo llama 3 veces, creará 3 objetos), pero PUT es idempotente (si lo llama 3 veces, el resultado es el mismo). PUT se usa a menudo para la operación "upsert" (crear o actualizar), pero siempre puede devolver un error 404 si solo desea usarlo para modificar.

Tenga en cuenta que POST "crea" un nuevo elemento en la colección, y PUT "reemplaza" un elemento en una URL dada, pero es una práctica muy común usar PUT para modificaciones parciales, es decir, usarlo solo para actualizar los recursos existentes y solo modifique los campos incluidos en el cuerpo (ignorando los otros campos). Esto es técnicamente incorrecto, si quiere ser REST-purist, PUT debe reemplazar todo el recurso y debe usar PATCH para la actualización parcial. Personalmente, no me importa mucho en la medida en que el comportamiento sea claro y consistente en todos sus puntos finales API.

Recuerde, REST es un conjunto de convenciones y pautas para mantener su API simple. Si termina con una solución complicada solo para marcar la casilla "RESTfull", entonces está frustrando el propósito;)

tothemario
fuente
7

Si bien es probable que haya una forma agnóstica de describirlos, parece estar en conflicto con varias declaraciones de respuestas a sitios web.

Seamos muy claros y directos aquí. Si usted es un desarrollador de .NET que trabaja con API web, los hechos son (de la documentación de la API de Microsoft), http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web -api-that-soporta-crud-operations :

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

Seguro que "puede" usar "POST" para actualizar, pero solo siga las convenciones establecidas para usted con su marco dado. En mi caso es .NET / Web API, por lo que PUT es para ACTUALIZAR no hay debate.

Espero que esto ayude a cualquier desarrollador de Microsoft que lea todos los comentarios con enlaces a sitios web de Amazon y Sun / Java.

Tom Stickel
fuente
7

Aquí hay una regla simple:

PONER a una URL debe usarse para actualizar o crear el recurso que se puede ubicar en esa URL.

La POST a una URL debe usarse para actualizar o crear un recurso que se encuentra en otra URL ("subordinada") o que no se puede localizar a través de HTTP.

Adam Griffiths
fuente
1
PUT no es para actualizar, es para reemplazar, tenga en cuenta que para crear no está reemplazando nada con algo. POST no es para actualizar en ninguna forma.
thecoshman
2
¿La especificación http dice eso? ¿O estás basando tu comentario en otra cosa?
Adam Griffiths
Es solo sentido común, ¿cómo actualizas algo cuando no sabes qué es lo que estás actualizando? POST es para crear un nuevo recurso.
thecoshman
2
thecoshman: está abusando de la semántica aquí, un reemplazo puede ser una actualización si es el mismo recurso con algunas diferencias. Un reemplazo solo es válido para poner si se usa reemplazar para cambiar el mismo recurso. Reemplazar con un recurso nuevo y diferente no es válido (¿eliminar antiguo y agregar nuevo?), Especialmente si el recurso 'nuevo' no tiene una identificación natural. POST, OTOH, es algo que puede crear, actualizar, reemplazar y eliminar: el uso de la publicación depende de si hay o no un mensaje para interpretar, como 'aplicar el descuento', que puede o no cambiar el recurso dependiendo de lógica.
Gerard ONeill
En cuanto a su segundo comentario, ¿qué tal si 'obtiene' el recurso, modifica los campos que necesita y luego lo vuelve a colocar? O qué tal si el recurso proviene de una fuente diferente pero usa una ID natural (la ID externa), puesto que naturalmente actualizaría el recurso en la URL cuando cambiaran los datos originales.
Gerard ONeill
6

Si está familiarizado con las operaciones de la base de datos, hay

  1. Seleccione
  2. Insertar
  3. Actualizar
  4. Eliminar
  5. Fusionar (Actualizar si ya existe, de lo contrario insertar)

Lo uso PUTpara Fusionar y actualizar como operaciones y lo uso POSTpara Inserciones.

Rajan
fuente
5

En la práctica, POST funciona bien para crear recursos. La URL del recurso recién creado debe devolverse en el encabezado de respuesta de Ubicación. PUT debe usarse para actualizar un recurso por completo. Por favor, comprenda que estas son las mejores prácticas al diseñar una API RESTful. La especificación HTTP como tal no restringe el uso de PUT / POST con algunas restricciones para crear / actualizar recursos. Eche un vistazo a http://techoctave.com/c7/posts/71-twitter-rest-api-dissected que resume las mejores prácticas.

java_geek
fuente
En su mayor parte, al leer todo este ruido, pareces estar en la pelota. Sin embargo, diría que deberíamos referirnos a PUT como el método de reemplazo, en lugar de crear / actualizar. Creo que describe mejor en uno lo que hace.
thecoshman