¿Por qué el método PATCH no es idempotente?

48

Me preguntaba acerca de esto.

Supongamos que tengo un userrecurso con idy namecampos. Si quiero actualizar un campo, podría hacer una solicitud PATCH al recurso como este

PATCH /users/42
{"name": "john doe"} 

Y luego la aplicación actualizará el nombre del usuario 42.

Pero, ¿por qué si repito esta solicitud, el resultado sería diferente?

De acuerdo con RFC 5789

PATCH no es seguro ni idempotente

mattecapu
fuente
¿Qué pasa si entre invocaciones otra persona hace una solicitud para actualizar el usuario 42?{"name": "bendjamin franklin"}
Gnat
@gnat, ¿no es válido un argumento similar también para el método PUT, que en cambio se considera idempotente? (ver goo.gl/t24ZSJ )
mattecapu
"PUT tiene una semántica idempotente y, por lo tanto, se puede usar de forma segura para actualizaciones absolutas (es decir, enviamos el estado completo del recurso al servidor), pero no también para actualizaciones relativas (es decir, enviamos solo cambios al estado del recurso) , ya que eso violaría su semántica ... "( solicitudes POST y PUT - ¿es solo la convención? )
mosquito
1
Obviamente ... Pero se podría decir que PUT no es idempotente porque entre dos solicitudes iguales un segundo cliente podría hacer una tercera solicitud entre las dos. Pero como no nos interesan los datos anteriores, eso no es un problema. El mismo argumento es válido para las solicitudes PATCH.
mattecapu
2
Me tomé la libertad de agregar una referencia a la especificación relevante, ya que creo que es muy relevante en el contexto de esta pregunta.
Pete

Respuestas:

34

Una solicitud de PARCHE puede ser idempotente, pero no es obligatorio que lo sea. Esa es la razón por la que se caracteriza como no idempotente.

Si PATCH puede ser idempotente o no, depende en gran medida de cómo se comunican los cambios requeridos.
Por ejemplo, si el formato del parche tiene la forma de {change: 'Name' from: 'benjamin franklin' to: 'john doe'}, entonces cualquier solicitud de PATCH después de la primera tendría un efecto diferente (una respuesta de falla) que la primera solicitud.
Otra razón para la no idempotencia puede ser que la aplicación de la modificación en algo más que el recurso original puede invalidar el recurso. Este también sería el caso si aplica el cambio varias veces.

Bart van Ingen Schenau
fuente
3
No entiendo el último párrafo, ¿puede dar un ejemplo de cómo "la aplicación de la modificación en algo más que el recurso original puede invalidar el recurso", y cómo esto se relaciona con la aplicación de un cambio varias veces al mismo recurso?
Robin Green
3
@RobinGreen: suponga que el recurso está representado en XML con el requisito de que exista como máximo un <name>elemento. Si el PATCH agrega un <name>elemento a un recurso que originalmente no contenía uno, entonces aplicar el PATCH dos veces (o aplicarlo a un recurso que ya contiene a <name>) invalida el recurso, porque de repente contendría dos <name>elementos que no están permitidos por tales recursos.
Bart van Ingen Schenau
13
El primer ejemplo que diste no es relevante en mi humilde opinión, ya que es idempotente. Ejemplo con DELETE que es idempotente, primera solicitud: el recurso existió pero se ha eliminado (devuelve 2xx), segunda solicitud: el recurso no existe y aún no existe después de la solicitud, devuelve 4xx. El estado del servidor no ha cambiado, por lo tanto, la idempotencia. En su ejemplo, primera solicitud: PATCH de BenFra a JohDoe, el nombre del recurso era BenFra pero ahora es JohDoe (devuelve 2xx), segunda solicitud: PATCH de BenFra a JohDoe, el nombre del recurso era JohDoe y todavía es JohDoe (devuelve 4xx). Por lo tanto, esto no muestra que PATCH puede ser noidempotente.
sp00m
Más detalles aquí: stackoverflow.com/q/4088350/1225328
sp00m
8

Creo que la respuesta clara cuando PATCH no es idempotente es este párrafo de RFC 5789:

También hay casos en los que los formatos de parche no necesitan operar desde un punto base conocido (por ejemplo, agregar líneas de texto a archivos de registro o filas no colisionantes a las tablas de la base de datos), en cuyo caso no se necesita el mismo cuidado en las solicitudes del cliente .

Como RFC especifica que el parche contiene algunos "cambios generales" en el recurso, deberíamos mirar más allá del reemplazo de campo típico. Si el recurso es para un contador, entonces el parche puede solicitar su incremento, lo que claramente no es idempotet.

Ivan
fuente
2

PATCHlas solicitudes describen un conjunto de operaciones que se aplicarán a un recurso; si aplica el mismo conjunto de operaciones dos veces al mismo recurso, el resultado puede no ser el mismo. Esto se debe a que definir las operaciones depende de usted. En otras palabras, debe definir las reglas de fusión .

Recuerde que una PATCHsolicitud podría usarse para parchear recursos en muchos formatos diferentes, no solo JSON.

Por lo tanto, una PATCHsolicitud puede ser idempotente si define las reglas de fusión como idempotentes .

Ejemplo idempotente:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  age: 33
}

// New resource
{
  name: 'Tito',
  age: 33
}

Ejemplo no idempotente:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  $increment: 'age'
}

// New resource
{
  name: 'Tito',
  age: 33
}

En el segundo ejemplo utilicé una sintaxis "Mongo like" que inventé para incrementar un atributo. Claramente, esto no es idempotente, ya que enviar la misma solicitud varias veces daría como resultado resultados diferentes cada vez.

Ahora puede que se pregunte si el uso de una sintaxis inventada es válida. Según las normas , es:

La diferencia entre las solicitudes PUT y PATCH se refleja en la forma en que el servidor procesa la entidad adjunta para modificar el recurso identificado por el URI de solicitud. En una solicitud PUT, la entidad adjunta se considera una versión modificada del recurso almacenado en el servidor de origen, y el cliente solicita que se reemplace la versión almacenada. Sin embargo, con PATCH, la entidad adjunta contiene un conjunto de instrucciones que describen cómo se debe modificar un recurso que actualmente reside en el servidor de origen para producir una nueva versión.

Y es posible que también se pregunte si es tranquilo usar las PATCHsolicitudes de esta manera, y muchas personas consideran que no, aquí hay una buena respuesta con muchos comentarios sobre el tema.

Jbm
fuente