Uso de métodos PUT vs PATCH en escenarios de la vida real de la API REST

740
Dmitry Kudryavtsev 2015-02-12 06:30.

En primer lugar, algunas definiciones:

PUT se define en la Sección 9.6 RFC 2616 :

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

PATCH se define en RFC 5789 :

El método PATCH solicita que un conjunto de cambios descritos en la entidad de solicitud se apliquen al recurso identificado por el Request-URI.

También de acuerdo con RFC 2616 Sección 9.1.2 PUT es Idempotente mientras que PATCH no lo es.

Ahora echemos un vistazo a un ejemplo real. Cuando hago POST /userscon los datos {username: 'skwee357', email: '[email protected]'}y el servidor es capaz de crear un recurso, responderá con 201 y la ubicación del recurso (supongamos /users/1) y cualquier próxima llamada a GET /users/1regresará {id: 1, username: 'skwee357', email: '[email protected]'}.

Ahora digamos que quiero modificar mi correo electrónico. La modificación de correo electrónico se considera "un conjunto de cambios" y, por lo tanto, debería PATCHAR /users/1con " documento de parche ". En mi caso sería el documento JSON: {email: '[email protected]'}. El servidor luego devuelve 200 (asumiendo que los permisos están bien). Esto me lleva a la primera pregunta:

  • PATCH NO es idempotente. Lo decía en RFC 2616 y RFC 5789. Sin embargo, si emito la misma solicitud de PATCH (con mi nuevo correo electrónico), obtendré el mismo estado de recurso (con mi correo electrónico modificado al valor solicitado). ¿Por qué PATCH no es idempotente?

PATCH es un verbo relativamente nuevo (RFC introducido en marzo de 2010), y viene a resolver el problema de "parchear" o modificar un conjunto de campos. Antes de que se introdujera PATCH, todos usaban PUT para actualizar los recursos. Pero después de que se introdujo PATCH, me deja confundido sobre para qué se usa PUT. Y esto me lleva a mi segunda (y principal) pregunta:

  • ¿Cuál es la diferencia real entre PUT y PATCH? He leído en alguna parte que PUT podría usarse para reemplazar la entidad completa bajo un recurso específico, por lo que uno debe enviar la entidad completa (en lugar del conjunto de atributos como con PATCH). ¿Cuál es el uso práctico real para tal caso? ¿Cuándo le gustaría reemplazar / sobrescribir una entidad en un URI de recurso específico y por qué dicha operación no se considera actualizar / parchear la entidad? El único caso de uso práctico que veo para PUT es emitir un PUT en una colección, es decir, /userspara reemplazar la colección completa. Emitir PUT en una entidad específica no tiene sentido después de que se introdujo PATCH. ¿Me equivoco?

10 answers

1012
Dan Lowe 2015-12-22 06:20.

NOTA : Cuando dediqué tiempo a leer por primera vez sobre REST, la idempotencia era un concepto confuso para tratar de acertar. Todavía no lo hice del todo bien en mi respuesta original, como han demostrado otros comentarios (y la respuesta de Jason Hoetger ). Durante un tiempo, me he resistido a actualizar ampliamente esta respuesta, para evitar plagiar efectivamente a Jason, pero la estoy editando ahora porque, bueno, me pidieron (en los comentarios).

Después de leer mi respuesta, le sugiero que lea también la excelente respuesta de Jason Hoetger a esta pregunta, y trataré de mejorar mi respuesta sin simplemente robarle a Jason.

¿Por qué PUT es idempotente?

Como señaló en su cita RFC 2616, PUT se considera idempotente. Cuando PONTE un recurso, estas dos suposiciones están en juego:

  1. Te refieres a una entidad, no a una colección.

  2. La entidad que está suministrando está completa ( toda la entidad).

Veamos uno de sus ejemplos.

{ "username": "skwee357", "email": "[email protected]" }

Si PUBLICA este documento a /users, como sugiere, entonces podría recuperar una entidad como

## /users/1

{
    "username": "skwee357",
    "email": "[email protected]"
}

Si desea modificar esta entidad más tarde, elija entre PUT y PATCH. Un PUT podría verse así:

PUT /users/1
{
    "username": "skwee357",
    "email": "[email protected]"       // new email address
}

Puede lograr lo mismo usando PATCH. Eso podría verse así:

PATCH /users/1
{
    "email": "[email protected]"       // new email address
}

Notarás una diferencia de inmediato entre estos dos. El PUT incluyó todos los parámetros de este usuario, pero PATCH solo incluyó el que se estaba modificando ( email).

Al usar PUT, se asume que está enviando la entidad completa, y esa entidad completa reemplaza cualquier entidad existente en ese URI. En el ejemplo anterior, PUT y PATCH logran el mismo objetivo: ambos cambian la dirección de correo electrónico de este usuario. Pero PUT lo maneja reemplazando toda la entidad, mientras que PATCH solo actualiza los campos que se proporcionaron, dejando los demás en paz.

Dado que las solicitudes PUT incluyen toda la entidad, si emite la misma solicitud repetidamente, siempre debería tener el mismo resultado (los datos que envió ahora son los datos completos de la entidad). Por tanto, PUT es idempotente.

Usando PUT incorrecto

¿Qué sucede si utiliza los datos de PATCH anteriores en una solicitud PUT?

GET /users/1
{
    "username": "skwee357",
    "email": "[email protected]"
}
PUT /users/1
{
    "email": "[email protected]"       // new email address
}

GET /users/1
{
    "email": "[email protected]"      // new email address... and nothing else!
}

(Supongo, a los efectos de esta pregunta, que el servidor no tiene ningún campo obligatorio específico y permitiría que esto suceda ... puede que ese no sea el caso en la realidad).

Como usamos PUT, pero solo suministramos email, ahora eso es lo único en esta entidad. Esto ha provocado la pérdida de datos.

Este ejemplo está aquí con fines ilustrativos; en realidad, nunca haga esto. Esta solicitud PUT es técnicamente idempotente, pero eso no significa que no sea una idea terrible y rota.

¿Cómo puede PATCH ser idempotente?

En el ejemplo anterior, PATCH era idempotente. Hizo un cambio, pero si realizaba el mismo cambio una y otra vez, siempre devolvería el mismo resultado: cambió la dirección de correo electrónico al nuevo valor.

GET /users/1
{
    "username": "skwee357",
    "email": "[email protected]"
}
PATCH /users/1
{
    "email": "[email protected]"       // new email address
}

GET /users/1
{
    "username": "skwee357",
    "email": "[email protected]"       // email address was changed
}
PATCH /users/1
{
    "email": "[email protected]"       // new email address... again
}

GET /users/1
{
    "username": "skwee357",
    "email": "[email protected]"       // nothing changed since last GET
}

Mi ejemplo original, arreglado para mayor precisión

Originalmente tenía ejemplos que pensé que mostraban no idempotencia, pero eran engañosos / incorrectos. Voy a conservar los ejemplos, pero los usaré para ilustrar algo diferente: que múltiples documentos PATCH contra la misma entidad, modificando diferentes atributos, no hacen que los PATCH sean no idempotentes.

Digamos que en algún momento pasado, se agregó un usuario. Este es el estado desde el que está comenzando.

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "10001"
}

Después de un PATCH, tiene una entidad modificada:

PATCH /users/1
{"email": "[email protected]"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",    // the email changed, yay!
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "10001"
}

Si luego aplica repetidamente su PATCH, continuará obteniendo el mismo resultado: el correo electrónico se cambió al nuevo valor. A entra, A sale, por tanto esto es idempotente.

Una hora más tarde, después de que te hayas ido a hacer un café y te tomes un descanso, alguien más viene con su propio PATCH. Parece que la oficina de correos ha estado haciendo algunos cambios.

PATCH /users/1
{"zip": "12345"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",  // still the new email you set
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "12345"                      // and this change as well
}

Dado que este PATCH de la oficina de correos no se refiere al correo electrónico, solo al código postal, si se aplica repetidamente, también obtendrá el mismo resultado: el código postal se establece en el nuevo valor. A entra, A sale, por lo tanto esto también es idempotente.

Al día siguiente, decides enviar tu PATCH nuevamente.

PATCH /users/1
{"email": "[email protected]"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "12345"
}

Su parche tiene el mismo efecto que tuvo ayer: configuró la dirección de correo electrónico. A entró, A salió, por lo tanto, esto también es idempotente.

Lo que hice mal en mi respuesta original

Quiero hacer una distinción importante (algo que hice mal en mi respuesta original). Muchos servidores responderán a sus solicitudes REST devolviendo el estado de la nueva entidad, con sus modificaciones (si las hubiera). Entonces, cuando recibe esta respuesta , es diferente de la que recibió ayer , porque el código postal no es el que recibió la última vez. Sin embargo, su solicitud no se refería al código postal, solo al correo electrónico. Entonces, su documento PATCH sigue siendo idempotente: el correo electrónico que envió en PATCH ahora es la dirección de correo electrónico de la entidad.

Entonces, ¿cuándo PATCH no es idempotente?

Para un tratamiento completo de esta pregunta, nuevamente lo remito a la respuesta de Jason Hoetger . Voy a dejarlo así, porque honestamente no creo que pueda responder esta parte mejor de lo que él ya lo ha hecho.

355
Jason Hoetger 2016-09-06 12:24.

Aunque la excelente respuesta de Dan Lowe respondió muy a fondo la pregunta del OP sobre la diferencia entre PUT y PATCH, su respuesta a la pregunta de por qué PATCH no es idempotente no es del todo correcta.

Para mostrar por qué PATCH no es idempotente, es útil comenzar con la definición de idempotencia (de Wikipedia ):

El término idempotente se usa de manera más amplia para describir una operación que producirá los mismos resultados si se ejecuta una o varias veces [...] Una función idempotente es aquella que tiene la propiedad f (f (x)) = f (x) para cualquier valor x.

En un lenguaje más accesible, un PATCH idempotente podría definirse como: Después de parchear un recurso con un documento de parche, todas las llamadas PATCH posteriores al mismo recurso con el mismo documento de parche no cambiarán el recurso.

Por el contrario, una operación no idempotente es aquella en la que f (f (x))! = F (x), que para PATCH podría expresarse como: Después de parchear un recurso con un documento de parche, las siguientes llamadas de PATCH al mismo recurso con el mismo documento parche de hacer cambiar el recurso.

Para ilustrar un PATCH no idempotente, suponga que hay un recurso / users y suponga que la llamada GET /usersdevuelve una lista de usuarios, actualmente:

[{ "id": 1, "username": "firstuser", "email": "[email protected]" }]

En lugar de PATCHing / users / {id}, como en el ejemplo del OP, suponga que el servidor permite PATCHING / users. Emitamos esta solicitud de PATCH:

PATCH /users
[{ "op": "add", "username": "newuser", "email": "[email protected]" }]

Nuestro documento de parche le indica al servidor que agregue un nuevo usuario llamado newusera la lista de usuarios. Después de llamar a esto por primera vez, GET /usersvolvería:

[{ "id": 1, "username": "firstuser", "email": "[email protected]" },
 { "id": 2, "username": "newuser", "email": "[email protected]" }]

Ahora, si emitimos exactamente la misma solicitud de PATCH que la anterior, ¿qué sucede? (Por el bien de este ejemplo, supongamos que el recurso / users permite nombres de usuario duplicados). La "op" es "agregar", por lo que se agrega un nuevo usuario a la lista y un resultado posterior GET /users:

[{ "id": 1, "username": "firstuser", "email": "[email protected]ample.org" },
 { "id": 2, "username": "newuser", "email": "[email protected]" },
 { "id": 3, "username": "newuser", "email": "[email protected]" }]

El recurso / users ha cambiado de nuevo , aunque publicamos exactamente el mismo PATCH contra el mismo punto final. Si nuestro PATCH es f (x), f (f (x)) no es lo mismo que f (x) y, por lo tanto, este PATCH en particular no es idempotente .

Aunque no se garantiza que PATCH sea ​​idempotente, no hay nada en la especificación PATCH que le impida hacer que todas las operaciones PATCH en su servidor particular sean idempotentes. RFC 5789 incluso anticipa las ventajas de las solicitudes de PATCH idempotentes:

Una solicitud de PATCH se puede emitir de tal manera que sea idempotente, lo que también ayuda a prevenir malos resultados de colisiones entre dos solicitudes de PATCH en el mismo recurso en un período de tiempo similar.

En el ejemplo de Dan, su operación PATCH es, de hecho, idempotente. En ese ejemplo, la entidad / users / 1 cambió entre nuestras solicitudes de PATCH, pero no debido a nuestras solicitudes de PATCH; en realidad, fue el documento de parche diferente de la oficina de correos lo que provocó que el código postal cambiara. El PATCH diferente de la oficina de correos es una operación diferente; si nuestro PATCH es f (x), el PATCH de la oficina de correos es g (x). La idempotencia afirma eso f(f(f(x))) = f(x), pero no da garantías al respecto f(g(f(x))).

77
Kalel Wade 2015-04-11 08:53.

También sentí curiosidad por esto y encontré algunos artículos interesantes. Puede que no responda su pregunta en toda su extensión, pero esto al menos proporciona más información.

http://restful-api-design.readthedocs.org/en/latest/methods.html

La RFC de HTTP especifica que PUT debe tomar una representación de recurso completamente nueva como entidad de solicitud. Esto significa que si, por ejemplo, solo se proporcionan ciertos atributos, estos deben eliminarse (es decir, establecerlos como nulos).

Dado eso, entonces un PUT debería enviar el objeto completo. Por ejemplo,

/users/1
PUT {id: 1, username: 'skwee357', email: '[email protected]'}

Esto actualizaría efectivamente el correo electrónico. La razón por la que PUT puede no ser demasiado eficaz es que su única modificación real de un campo e incluir el nombre de usuario es algo inútil. El siguiente ejemplo muestra la diferencia.

/users/1
PUT {id: 1, email: '[email protected]'}

Ahora, si el PUT se diseñó de acuerdo con la especificación, entonces el PUT establecería el nombre de usuario en nulo y obtendría lo siguiente.

{id: 1, username: null, email: '[email protected]'}

Cuando usa un PATCH, solo actualiza el campo que especifica y deja el resto solo como en su ejemplo.

La siguiente versión del PATCH es un poco diferente a la que nunca había visto antes.

http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/

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 la Request-URI. 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 reside actualmente en el servidor de origen para producir una nueva versión. El método PATCH afecta el recurso identificado por Request-URI, y también PUEDE tener efectos secundarios en otros recursos; es decir, se pueden crear nuevos recursos o modificar los existentes mediante la aplicación de un PATCH.

PATCH /users/123

[
    { "op": "replace", "path": "/email", "value": "[email protected]" }
]

Está tratando más o menos el PATCH como una forma de actualizar un campo. Entonces, en lugar de enviar el objeto parcial, está enviando la operación. es decir, reemplace el correo electrónico con valor.

El artículo termina con esto.

Vale la pena mencionar que PATCH no está realmente diseñado para API REST realmente, ya que la disertación de Fielding no define ninguna forma de modificar parcialmente los recursos. Pero el propio Roy Fielding dijo que PATCH fue algo que [él] creó para la propuesta inicial de HTTP / 1.1 porque PUT parcial nunca es RESTful. Seguro que no está transfiriendo una representación completa, pero REST no requiere que las representaciones estén completas de todos modos.

Ahora bien, no sé si estoy particularmente de acuerdo con el artículo, como señalan muchos comentaristas. Enviar una representación parcial puede ser fácilmente una descripción de los cambios.

Para mí, estoy mezclado en el uso de PATCH. En su mayor parte, trataré PUT como un PATCH, ya que la única diferencia real que he notado hasta ahora es que PUT "debería" establecer los valores faltantes en nulo. Puede que no sea la forma "más correcta" de hacerlo, pero buena suerte con la codificación perfecta.

22
Bijan 2019-10-18 08:55.

TLDR - Versión simplificada

PUT => Establecer todos los atributos nuevos para un recurso existente.

PATCH => Actualizar parcialmente un recurso existente (no se requieren todos los atributos).

20
Bin Ni 2017-05-18 09:01.

La diferencia entre PUT y PATCH es que:

  1. PUT debe ser idempotente. Para lograrlo, debe colocar todo el recurso completo en el cuerpo de la solicitud.
  2. PATCH puede ser no idempotente. Lo que implica que también puede ser idempotente en algunos casos, como los casos que describiste.

PATCH requiere algún "lenguaje de parche" para decirle al servidor cómo modificar el recurso. La persona que llama y el servidor deben definir algunas "operaciones" como "agregar", "reemplazar", "eliminar". Por ejemplo:

GET /contacts/1
{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",
  "state": "NY",
  "zip": "10001"
}

PATCH /contacts/1
{
 [{"operation": "add", "field": "address", "value": "123 main street"},
  {"operation": "replace", "field": "email", "value": "[email protected]"},
  {"operation": "delete", "field": "zip"}]
}

GET /contacts/1
{
  "id": 1,
  "name": "Sam Kwee",
  "email": "[email protected]",
  "state": "NY",
  "address": "123 main street",
}

En lugar de utilizar campos de "operación" explícitos, el lenguaje del parche puede hacerlo implícito definiendo convenciones como:

en el cuerpo de la solicitud PATCH:

  1. La existencia de un campo significa "reemplazar" o "agregar" ese campo.
  2. Si el valor de un campo es nulo, significa eliminar ese campo.

Con la convención anterior, el PATCH en el ejemplo puede tomar la siguiente forma:

PATCH /contacts/1
{
  "address": "123 main street",
  "email": "[email protected]",
  "zip":
}

Que parece más conciso y fácil de usar. Pero los usuarios deben conocer la convención subyacente.

Con las operaciones que mencioné anteriormente, el PATCH sigue siendo idempotente. Pero si define operaciones como: "incrementar" o "agregar", puede ver fácilmente que ya no será idempotente.

3
Rolvernew 2018-11-16 02:51.

Permítanme citar y comentar más de cerca la sección 4.2.2 del RFC 7231 , ya citada en comentarios anteriores:

Un método de solicitud se considera "idempotente" si el efecto previsto en el servidor de múltiples solicitudes idénticas con ese método es el mismo que el efecto de una sola solicitud de este tipo. De los métodos de solicitud definidos por esta especificación, PUT, DELETE y los métodos de solicitud seguros son idempotentes.

(...)

Los métodos idempotentes se distinguen porque la solicitud puede repetirse automáticamente si ocurre una falla en la comunicación antes de que el cliente pueda leer la respuesta del servidor. Por ejemplo, si un cliente envía una solicitud PUT y la conexión subyacente se cierra antes de recibir una respuesta, el cliente puede establecer una nueva conexión y volver a intentar la solicitud idempotente. Sabe que repetir la solicitud tendrá el mismo efecto previsto, incluso si la solicitud original tuvo éxito, aunque la respuesta puede diferir.

Entonces, ¿qué debería ser "igual" después de una repetida solicitud de un método idempotente? No es el estado del servidor ni la respuesta del servidor, sino el efecto deseado . En particular, el método debe ser idempotente "desde el punto de vista del cliente". Ahora, creo que este punto de vista muestra que el último ejemplo en la respuesta de Dan Lowe , que no quiero plagiar aquí, de hecho muestra que una solicitud de PATCH puede ser no idempotente (de una manera más natural que el ejemplo en Respuesta de Jason Hoetger ).

De hecho, hagamos el ejemplo un poco más preciso haciendo explícita una posible intención para el primer cliente. Digamos que este cliente revisa la lista de usuarios con el proyecto para revisar sus correos electrónicos y códigos postales. Comienza con el usuario 1, se da cuenta de que el zip es correcto pero el correo electrónico es incorrecto. Decide corregir esto con una solicitud PATCH, que es completamente legítima y envía solo

PATCH /users/1
{"email": "[email protected]"}

ya que esta es la única corrección. Ahora, la solicitud falla debido a algún problema de red y se vuelve a enviar automáticamente un par de horas después. Mientras tanto, otro cliente ha modificado (erróneamente) el zip del usuario 1. Entonces, enviar la misma solicitud de PATCH por segunda vez no logra el efecto deseado del cliente, ya que terminamos con un zip incorrecto. Por tanto, el método no es idempotente en el sentido del RFC.

Si, en cambio, el cliente utiliza una solicitud PUT para corregir el correo electrónico, enviando al servidor todas las propiedades del usuario 1 junto con el correo electrónico, se logrará el efecto deseado incluso si la solicitud tiene que ser reenviada más tarde y el usuario 1 ha sido modificado. mientras tanto --- dado que la segunda solicitud PUT sobrescribirá todos los cambios desde la primera solicitud.

3
Zbigniew Szczęsny 2019-09-20 13:25.

En mi humilde opinión, idempotencia significa:

  • PONER:

Envío una definición de recurso completa, entonces, el estado del recurso resultante es exactamente como lo definen los parámetros PUT. Cada vez que actualizo el recurso con los mismos parámetros PUT, el estado resultante es exactamente el mismo.

  • PARCHE:

Envié solo una parte de la definición del recurso, por lo que puede suceder que otros usuarios estén actualizando OTROS parámetros de este recurso mientras tanto. En consecuencia, los parches consecutivos con los mismos parámetros y sus valores pueden dar como resultado un estado de recurso diferente. Por ejemplo:

Suponga un objeto definido de la siguiente manera:

COCHE: - color: negro, - tipo: sedán, - asientos: 5

Lo parcheo con:

{color rojo'}

El objeto resultante es:

COCHE: - color: rojo, - tipo: sedán, - asientos: 5

Luego, algunos otros usuarios parchean este auto con:

{tipo: 'hatchback'}

entonces, el objeto resultante es:

COCHE: - color: rojo, - tipo: hatchback, - asientos: 5

Ahora, si parcheo este objeto nuevamente con:

{color rojo'}

el objeto resultante es:

COCHE: - color: rojo, - tipo: hatchback, - asientos: 5

¡Qué es DIFERENTE a lo que tengo anteriormente!

Es por eso que PATCH no es idempotente mientras que PUT es idempotente.

1
Mohammad-Ali A'RÂBI 2019-11-01 03:19.

Para concluir la discusión sobre la idempotencia, debo señalar que se puede definir la idempotencia en el contexto REST de dos maneras. Primero formalicemos algunas cosas:

Un recurso es una función cuyo codominio es la clase de cadenas. En otras palabras, un recurso es un subconjunto de String × Any, donde todas las claves son únicas. Llamemos a la clase de los recursos Res.

Una operación REST sobre recursos es una función f(x: Res, y: Res): Res. Dos ejemplos de operaciones REST son:

  • PUT(x: Res, y: Res): Res = xy
  • PATCH(x: Res, y: Res): Res, que funciona como PATCH({a: 2}, {a: 1, b: 3}) == {a: 2, b: 3}.

(Esta definición está diseñada específicamente para discutir sobre PUTy POST, por ejemplo, no tiene mucho sentido sobre GETy POST, ya que no le importa la persistencia).

Ahora, fijando x: Res(hablando informáticamente, usando currying), PUT(x: Res)y PATCH(x: Res)son funciones univariadas de tipo Res → Res.

  1. Una función g: Res → Resse llama a nivel mundial idempotente , cuando g ○ g == g, es decir, para cualquier y: Res, g(g(y)) = g(y).

  2. Deje x: Resun recurso, y k = x.keys. Una función g = f(x)se llama idempotente de izquierda , cuando para cada uno y: Res, tenemos g(g(y))|ₖ == g(y)|ₖ. Básicamente significa que el resultado debería ser el mismo, si miramos las claves aplicadas.

Entonces, PATCH(x)no es idempotente globalmente, sino idempotente de izquierda. Y la idempotencia de la izquierda es lo que importa aquí: si parcheamos algunas claves del recurso, queremos que esas claves sean las mismas si lo parcheamos de nuevo, y no nos importa el resto del recurso.

Y cuando RFC habla de que PATCH no es idempotente, está hablando de idempotencia global. Bueno, es bueno que no sea idempotente a nivel mundial, de lo contrario habría sido una operación rota.


Ahora, la respuesta de Jason Hoetger está tratando de demostrar que PATCH ni siquiera se deja idempotente, pero está rompiendo demasiadas cosas para hacerlo:

  • En primer lugar, PATCH se usa en un conjunto, aunque PATCH está definido para funcionar en mapas / diccionarios / objetos de valor clave.
  • Si alguien realmente quiere aplicar PATCH a los conjuntos, entonces hay una traducción natural que debe usarse:, t: Set<T> → Map<T, Boolean>definida con x in A iff t(A)(x) == True. Usando esta definición, el parcheo queda idempotente.
  • En el ejemplo, esta traducción no se usó, en cambio, el PATCH funciona como un POST. En primer lugar, ¿por qué se genera una identificación para el objeto? ¿Y cuando se genera? Si el objeto se compara primero con los elementos del conjunto, y si no se encuentra un objeto coincidente, entonces se genera la ID, entonces nuevamente el programa debería funcionar de manera diferente ( {id: 1, email: "[email protected]"}debe coincidir con {email: "[email protected]"}, de lo contrario, el programa siempre está roto y el PATCH no puede parche). Si el ID se genera antes de compararlo con el conjunto, nuevamente el programa se rompe.

Se pueden hacer ejemplos de PUT que no es idempotente y rompe la mitad de las cosas que se rompen en este ejemplo:

  • Un ejemplo con características adicionales generadas sería el control de versiones. Se puede llevar un registro del número de cambios en un solo objeto. En este caso, PUT no es idempotente: PUT /user/12 {email: "[email protected]"}resulta {email: "...", version: 1}la primera vez y {email: "...", version: 2}la segunda vez.
  • Jugando con las ID, uno puede generar una nueva ID cada vez que se actualiza el objeto, lo que resulta en un PUT no idempotente.

Todos los ejemplos anteriores son ejemplos naturales que uno puede encontrar.


Mi punto final es que PATCH no debería ser idempotente globalmente , de lo contrario no le dará el efecto deseado. Desea cambiar la dirección de correo electrónico de su usuario, sin tocar el resto de la información, y no desea sobrescribir los cambios de otra parte que accede al mismo recurso.

0
Eric Wood 2020-07-14 11:30.

Todos los demás han respondido el PUT vs PATCH. Solo iba a responder qué parte del título de la pregunta original dice: "... en escenarios de la vida real de la API REST". En el mundo real, esto me sucedió con una aplicación de Internet que tenía un servidor RESTful y una base de datos relacional con una tabla Customer que era "ancha" (alrededor de 40 columnas). Usé PUT por error, pero asumí que era como un comando de Actualización SQL y no había llenado todas las columnas. Problemas: 1) Algunas columnas eran opcionales (por lo que el espacio en blanco era una respuesta válida), 2) muchas columnas rara vez cambiaban, 3) algunas columnas que el usuario no podía cambiar, como la fecha de la última compra, 4) una columna era gratuita -formular la columna "Comentarios" de texto que los usuarios llenaron diligentemente con comentarios de servicios al cliente de media página como el nombre de los cónyuges para preguntar sobre el pedido habitual, 5) Estaba trabajando en una aplicación de Internet en ese momento y me preocupaba el tamaño del paquete.

La desventaja de PUT es que te obliga a enviar un gran paquete de información (todas las columnas, incluida la columna Comentarios, aunque solo cambiaron algunas cosas) Y el problema multiusuario de más de 2 usuarios que editan el mismo cliente simultáneamente (por último uno para presionar Actualizar gana). La desventaja de PATCH es que debe realizar un seguimiento en el lado de la vista / pantalla de lo que cambió y tener cierta inteligencia para enviar solo las partes que cambiaron. El problema multiusuario de Patch se limita a editar las mismas columnas del mismo cliente.

0
harit 2020-10-13 21:07.

Una muy buena explicación está aquí.

https://blog.segunolalive.com/posts/restful-api-design-%E2%80%94-put-vs-patch/#:~:text=RFC%205789,not%20required%20to%20be%20idempotent .

Una carga útil normal- // Casa en la parcela 1 {dirección: 'parcela 1', propietario: 'segun', tipo: 'dúplex', color: 'verde', habitaciones: '5', cocinas: '1', ventanas: 20} PUT para actualización- // PUT solicitud de carga útil para actualizar las ventanas de la casa en la parcela 1 {dirección: 'parcela 1', propietario: 'segun', tipo: 'duplex', color: 'verde', habitaciones: '5' , cocinas: '1', ventanas: 21} Nota: En la carga útil anterior, estamos intentando actualizar las ventanas de la 20 a la 21.

Ahora vea el payload de PATH- // Patch request payload para actualizar Windows en la Casa {windows: 21}

Dado que PATCH no es idempotente, las solicitudes fallidas no se vuelven a intentar automáticamente en la red. Además, si se realiza una solicitud de PATCH a una URL inexistente, por ejemplo, al intentar reemplazar la puerta de entrada de un edificio inexistente, simplemente debería fallar sin crear un nuevo recurso a diferencia de PUT, que crearía uno nuevo usando la carga útil. Ahora que lo pienso, será extraño tener una puerta solitaria en la dirección de una casa.

Related questions

MORE COOL STUFF

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que le diagnosticaron envenenamiento por mercurio y plomo, probablemente debido a su trabajo como manipuladora de casas.

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

Recientemente salió a la luz un informe policial que acusa a la estrella de 'Love Is Blind', Brennon, de violencia doméstica. Ahora, Brennon ha respondido a los reclamos.

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Conozca cómo Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia mientras organizaba la primera celebración de Acción de Gracias desde que murió su madre, Naomi Judd.

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Descubra por qué un destacado experto en lenguaje corporal cree que es fácil trazar "tales paralelismos" entre la princesa Kate Middleton y la princesa Diana.

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los inodoros arrojan columnas de aerosol invisibles con cada descarga. ¿Como sabemos? La prueba fue capturada por láseres de alta potencia.

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

¿Caduca el repelente de insectos?

¿Caduca el repelente de insectos?

¿Sigue siendo efectivo ese lote de repelente de insectos que te quedó del verano pasado? Si es así, ¿por cuánto tiempo?

Estados Unidos podría evitarse el horror del nuevo gran horneado británico

Estados Unidos podría evitarse el horror del nuevo gran horneado británico

Si este tráiler de pesadilla de la temporada más reciente de Great British Bake Off te asustó y te hizo no volver a ver el programa, es posible que tengas suerte: PBS no ha decidido si se transmitirá o no la última temporada en los Estados Unidos. actualización, para aquellos que no siguen sin aliento este tipo de drama de nicho: el presentador Paul Hollywood y la hermosa carpa llena de batidoras de colores pastel y cuadros se trasladaron de la BBC al Canal 4; Mary Berry, Sue Perkins y Mel Giedroyc renunciaron.

Atún como Oh, Hello llega a Netflix

Atún como Oh, Hello llega a Netflix

Foto: Netflix Oh, Hello On Broadway (Netflix): Después de llegar a Broadway el año pasado, los dos locos del Upper West Side interpretados por John Mulaney y Nick Kroll finalmente llegaron a Netflix. El especial consta del espectáculo en el escenario, algunos momentos entre bastidores y un invitado muy especial de “Too Much Tuna”.

Actualice a un Sonicare por tan solo $ 30

Actualice a un Sonicare por tan solo $ 30

¿Quiere probar un cepillo de dientes Sonicare sin gastar mucho dinero en uno de sus modelos favoritos de gama alta? Puede comprar un kit de la Serie 2 o Serie 3 por tan solo $ 30 hoy en Amazon. Haga clic aquí para ver la lista completa de modelos elegibles y tenga en cuenta que se descontarán $ 10 adicionales en su carrito.

Ponle una tapa. En realidad, ponle una tapa a todo. Consigue 12 tapas de cocina elásticas de silicona por $14. [Exclusivo]

Ponle una tapa. En realidad, ponle una tapa a todo. Consigue 12 tapas de cocina elásticas de silicona por $14. [Exclusivo]

Tapas elásticas de silicona de Tomorrow's Kitchen, paquete de 12 | $14 | Amazonas | Código promocional 20OFFKINJALids son básicamente los calcetines de la cocina; siempre perdiéndose, dejando contenedores huérfanos que nunca podrán volver a cerrarse. Pero, ¿y si sus tapas pudieran estirarse y adaptarse a todos los recipientes, ollas, sartenes e incluso frutas en rodajas grandes que sobran? Nunca más tendrás que preocuparte por perder esa tapa tan específica.

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

El equipo está a la espera de las medallas que ganó en los Juegos Olímpicos de Invierno de 2022 en Beijing, ya que se está resolviendo un caso de dopaje que involucra a la patinadora artística rusa Kamila Valieva.

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Miles de compradores de Amazon recomiendan la funda de almohada de seda Mulberry, y está a la venta en este momento. La funda de almohada de seda viene en varios colores y ayuda a mantener el cabello suave y la piel clara. Compre las fundas de almohada de seda mientras tienen hasta un 46 por ciento de descuento en Amazon

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

El jueves se presentó una denuncia de delito menor amenazante agravado contra Joe Mixon.

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

El Departamento de Policía de Lafayette comenzó a investigar a un profesor de la Universidad de Purdue en diciembre después de recibir varias denuncias de un "hombre sospechoso que se acercaba a una mujer".

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Al igual que el mundo que nos rodea, el lenguaje siempre está cambiando. Mientras que en eras anteriores los cambios en el idioma ocurrían durante años o incluso décadas, ahora pueden ocurrir en cuestión de días o incluso horas.

India me está pateando el culo

India me está pateando el culo

Estoy de vuelta por primera vez en seis años. No puedo decirte cuánto tiempo he estado esperando esto.

ℝ

“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.

¿Merrick Garland le ha fallado a Estados Unidos?

Es más de la mitad de la presidencia de Biden. ¿Qué está esperando Merrick Garland?

¿Merrick Garland le ha fallado a Estados Unidos?

Creo, un poco tarde en la vida, en dar oportunidades a la gente. Generosamente.

Language