jueves, 25 de julio de 2013

HTTP: diferencia entre POST y PUT

El protocolo HTTP define una serie de peticiones posibles entre cliente y servidor ( GET, POST, PUT, DELETE, HEAD, etc ). POST y PUT son muy similares y hay bastante confusión respecto a su uso y sus diferencias. Las dos pueden utilizarse para crear y para actualizar un recurso, pero en situaciones diferentes.

Hasta hace unos años se utilizaba casi exclusivamente GET y POST. La interacción con el servidor era básicamente por medio de formularios HTML, que no permiten otros métodos (ni siquiera en HTML5).

En las aplicaciones actuales, la mayor parte de la comunicación con el servidor se realiza mediante AJAX, que sí permite el uso de otras peticiones HTTP. Además, la popularización de los interfaces REST implica el uso de los métodos GET, POST, PUT y DELETE para interactuar con el servidor.

En algunas páginas sobre REST encontramos la siguiente definición de los métodos (ejemplo):

  • GET para obtener un recurso del servidor
  • POST para crear un recurso del servidor
  • PUT para actualizar un recurso del servidor
  • DELETE para eliminar un recurso del servidor

Y en algunas otras encontraremos exactamente lo contrario (ejemplo):

  • GET para obtener un recurso del servidor del servidor
  • POST para actualizar un recurso del servidor
  • PUT para crear un recurso del servidor
  • DELETE para eliminar un recurso del servidor

En realidad estas definiciones son incorrectas. La diferencia no es que uno se utilice para crear y otro para actualizar. Los dos métodos pueden crear un recurso y los dos métodos pueden actualizarlo.

La diferencia no es que uno se utilice para crear y otro para actualizar, esto es incorrecto

PUT se utiliza para poner un recurso en un lugar especificado (la URL). POST es mucho más general. POST simplemente envía una información al servidor para que éste la trate como considere oportuno. Puede crear un recurso nuevo, devolver una información, puede guardarlo en la base de datos, borrarlo, duplicarlo o modificarlo, puede crear 10 recursos de un tipo y dos de otro o puede no hacer absolutamente nada.

  • PUT pone un recurso en la dirección especificada en la URL. Exactamente en esa dirección. Si no existe, lo crea, si existe lo reemplaza.
  • POST envía datos a una URL para que el recurso en esa URI los maneje.

La diferencia principal, tal como se explica en la RFC 2016 que define el protocolo HTTP 1.1, es el significado que se da a la URL de la petición:

"La diferencia fundamental entre las peticiones POST y PUT se refleja en el diferente significado de la URI de la petición. La URI en un POST identifica el recurso que manejará la entidad que se incluye (los datos). [...]. En cambio, la URI en un PUT identifica la entidad incluida con la petición -- el user agent sabe que URI debe emplearse y el servidor NO DEBE intentar aplicar la petición a un recurso diferente."

Es decir, PUT sólo debe emplearse para crear o reemplazar un recurso (que se incluye en el cuerpo de la petición) en una URL conocida. En terminos REST, conocemos la ID del objeto que vamos a crear/reemplazar y ese objeto (entidad) se incluye en el cuerpo de la petición. Por ejemplo:

PUT a la URL: myServer.com/user/1134

Crea o reemplaza el usuario con ID 1134. Exclusivamente ese. Si queremos crear un usuario nuevo, sin saber su ID, la operación correcta sería POST:

POST a la URL: myServer.com/user

El servidor crearía un nuevo objeto user y le asignaría una ID. Crearía, por ejemplo, el objeto:

myServer.com/user/1235

Esto nos lleva a otro concepto importante: idempotencia. PUT es idempotente, POST no lo es.

Idempotente significa que produce el mismo resultado sin importar cuantas veces se realice la operación.

En el ejemplo que veíamos antes, con el método PUT:

PUT a la URL: myServer.com/user/1134

Estamos definiendo una operación idempotente sobre un recurso concreto. No importa cuantas veces la lancemos, el resultado será siempre el mismo: el recurso identificado como "myServer.com/user/1134" existirá con los datos que se han pasado en la petición. Si no existía se creará. Si ya existía se reemplazará de nuevo. No afecta a nada más.

La operación POST que veíamos antes no es idempotente. Cada vez que se lance la petición al servidor creará un recurso nuevo, asignandole una nueva ID.

POST a la URL: myServer.com/user

Despues de 4 peticiones tendriamos los recursos:

  • myServer.com/user/1235
  • myServer.com/user/1236
  • myServer.com/user/1237
  • myServer.com/user/1238

Resumen

Estos son los puntos más importantes que debemos tener en cuenta:

  • Una petición PUT a una URL afecta únicamente a esa URL. Un POST a una URL puede tener cualquier efecto.
  • En una petición PUT, los datos incluidos en el cuerpo de la petición se toman como una entidad que quedará accesible en la dirección URL de la petición.
  • Solo debemos utilizar PUT cuando sabemos exactamente la url correspondiente al recurso que vamos a crear (o actualizar).
  • PUT es idempotente, POST no es idempotente.

Fuentes:
StackOverflow: PUT vs POST in REST
PUT or POST: The REST of the Story
POST vs. PUT
StackOverflow: What's the difference between a POST and a PUT HTTP REQUEST?

12 comentarios:

  1. Muchas gracias, con el uso del termino idempotente logre entender la diferencia entre PUT y POST.

    ResponderEliminar
  2. Muy claro los conceptos, muchas gracias.

    ResponderEliminar
  3. Muy buena explicación, entendible y suficiente para salir de la duda, el ejemplo de IDEMPOTENTE, entre las peticiones de PUT y POST es GENIAL.

    ResponderEliminar
  4. Muy buena explicación.

    ResponderEliminar
  5. Muchas gracias, un trabajo muy muy bueno

    ResponderEliminar
  6. Buena explicación! un detalle, PUT a la URL: myServer.com/user/1134 debería ser PUT a la URI: myServer.com/user/1134

    ResponderEliminar
  7. Excelente explicación, GRacias!!!!

    ResponderEliminar
  8. la verdad es que he leido bastantes explicaciones REST y esta es probablemente la más clara... gracias

    ResponderEliminar
  9. Hola, buenas noches, gracias por la explicacion, pero sigo sin entender o necesito ejemplos mas concretos.

    ResponderEliminar