spinner

Cómo utilizar PUT y PATCH al diseñar API RESTful

La idea de este post es aprender a diferenciar entre los métodos PUT y PATCH  al diseñar las API RESTful de manera más amigable. Por eso, a lo largo de este texto, procuraremos ir dando algunas claves para que esta tarea resulte sencilla y útil.

¡Ojo! A lo largo del texto hay referencias a los métodos que define el protocolo HTTP y a términos técnicos como “Estándar RFC…”. Pero no te preocupes si nada de esto te suena de entrada. Si te interesa el tema te dejo algunos artículos para que puedas leer acerca de qué es una API REST, qué es HTTP y qué es un RFC. No hay prisa, puedo esperar… ¿Listo? ¡Vamos!

Al inicio, sólo estaban los métodos GET y POST

Si trabajas en el mundo del desarrollo web, seguramente estás familiarizado con APIs y Web Services (además, si nos sigues, en el blog de BBVA Next Technologies ya hemos publicado algún artículo sobre cómo diseñar APIs!). Si ya eres un desarrollador veterano es probable que estés demasiado familiarizado con los métodos GET y POST de HTTP. A pesar de que el estándar RFC2616 (y a partir de 2014, el estándar RFC7231) define claramente la semántica para ocho métodos HTTP, por mucho tiempo el mundo decidió utilizar solo POST y la mitad de GET.

Aquí algunos ejemplos que pueden resultar familiares:

  • ¿Consultas un recurso? GET
  • ¿Consultas otro recurso? POST
  • ¿Creas un nuevo recurso? POST
  • ¿Modificaciones? Dale un POST.
  • ¿Eliminar? También POST
  • ¿Operaciones seguras? ¡POST! It’s always POST, yeah baby!
gif joey friends

Fuente: Giphy.com

 

Pero las cosas han cambiado…

Con el auge del paradigma REST en el diseño de APIs, la situación ha mejorado un poco. Seguro que a estas alturas ya sabes de memoria que hay una relación directa entre las operaciones CRUD y algunos métodos HTTP.

Create – POST
Read – GET
Update – PUT/PATCH
Delete – DELETE (¡Oh sorpresa!)

¡Genial! No más aberraciones como POST /deleteUserById. Esta nueva relación entre operaciones y métodos HTTP es el primer paso para cumplir la restricción de interfaz uniforme del paradigma REST.

No obstante, aún existen puntos de confusión. Uno en específico es sobre las operaciones tipo Update, para las que se puede utilizar tanto PUT como PATCH (definido en el RFC5789). ¿Cuál utilizar entonces? ¿PATCH es sólo un alias para PUT? ¿Realmente hay más de un mecanismo para actualizar entidades? Pareciera que es cierto que a los desarrolladores a veces nos gusta complicarnos la vida para “impresionar” al mundo (!). Afortunadamente, el estándar del PATCH dedica una sección a explicar esta diferencia.

La diferencia, versión oficial

El RFC5789 dice:

«The difference between the PUT and PATCH requests is reflected in the way the server processes the enclosed entity to modify the resource identified by the Request-URI. In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the origin server, and the client is requesting that the stored version be replaced.

With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version».

Más claro, ni el agua. Esto significa que la diferencia se reduce a que PUT debería ser un método «idempotente». Pero, un momento…¿Qué es eso de «idempotente»? ¿No me estarás insultando? ¡No!

Fuente: Giphy.com

 

¿Qué es la idempotencia?

Ahora mismo explico con un ejemplo lo que significa la idempotencia: si digo que PUT debe ser implementado de forma idempotente, quiere decir que el resultado de hacer sólo una llamada PUT /users/R2-D2 debe ser el mismo que hacer la misma llamada tres mil veces consecutivas. De la lista de métodos HTTP relacionados a CRUD, también son idempotentes por definición GET, PUT y DELETE. Esto es idempotencia.

Volvemos a la parte relativa a PUT en la cita del RFC:

…In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the origin server…

Si quisieras modificar sólo el email del usuario, por ejemplo, R2-D2 usando PUT, para garantizar idempotencia tendrías que enviar en en el payload de la solicitud HTTP una representación completa del usuario, así sean 100 atributos. El flujo de tu aplicación para esta operación sería más o menos así:

1. GET /users/R2-D2 – Obtener un objeto con la representación completa del usuario.
2. Cambiar el valor del campo email en el objeto.
3. PUT /users/R2-D2 – Enviar el objeto completo con la nueva representación.

..and the client is requesting that the stored version be replaced.

Si otro usuario modifica los datos de R2-D2 después de ejecutar el paso 1, pero antes del paso 3, terminarás sobreescribiendo los cambios que hizo el otro usuario. Y por si fuera poco, mientras más atributos tenga el objeto, se vuelve drásticamente menos práctico utilizar este enfoque.

Es aquí donde entra PATCH

…With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version.”

PATCH, por su parte, ofrece mayor flexibilidad con respecto a lo que puede viajar en el payload, ya sea una representación de R2-D2 que contenga solo el atributo email o un conjunto de instrucciones que indiquen al servidor cómo transformar los datos del usuario. La única restricción es utilizar alguna sintaxis previamente definida, como JSON Patch (RFC6902) o JSON Merge (RFC7386). Como imaginarás, la flexibilidad del PATCH viene a costa de la idempotencia. Si el servidor recibe peticiones PATCH duplicadas, el recurso podría terminar en un estado incoherente.

¿Y entonces, qué? Conclusión!

PUT requiere enviar una representación completa del recurso que se está modificando, se debe implementar de forma idempotente y es adecuado para situaciones en las que una aplicación debe asegurarse que el estado final del recurso será idéntica a la que envía.

PATCH es adecuado para hacer modificaciones parciales, o para enviar un conjunto de instrucciones en lugar del resultado final. La estructura del mensaje debe de seguir la sintaxis de JSON Patch (RFC6902) o JSON Merge (RFC7386) y por definición no es idempotente.

Pues bien. Yo creo que tras leer este post ya cuentas con las herramientas para diseñar APIs más amigables y apegadas a lo que tus consumidores esperan. ¡Gracias por tu atención! Te dejo algunos recursos más por si quieres seguir ahondando en el tema, ¡espero te sirvan y que les puedas sacar provecho!

Las opiniones vertidas por el autor son enteramente suyas y no siempre representan la opinión de BBVA Next Technologies.

¿Quieres saber que más cosas hacemos en BBVA Next Technologies?