rest logging audit put

rest - ¿Debo usar el método PUT para actualizar, si también actualizo un atributo de marca de tiempo?



logging audit (4)

Ser más preciso:

De acuerdo con el estilo de reposo, generalmente se asume que los métodos POST, GET, PUT y DELETE http deben utilizarse para las operaciones CREATE, READ, UPDATE y DELETE (CRUD).

De hecho, si nos atenemos a la definición de los métodos http, la cosa podría no ser tan clara.

En este artículo se explica que:

En pocas palabras: use PUT si y solo si conoce tanto la URL donde vivirá el recurso como la totalidad del contenido del recurso. De lo contrario, utilice POST.

Principalmente porque

PUT es un verbo mucho más restrictivo. Toma un recurso completo y lo almacena en la URL dada. Si había un recurso allí anteriormente, se reemplaza; Si no, se crea uno nuevo. Estas propiedades admiten idempotence, que una operación ingenua de creación o actualización podría no tener. Sospecho que esta puede ser la razón por la que PUT se define como es; es una operación idempotente que le permite al cliente enviar información al servidor.

En mi caso, generalmente emito actualizaciones que pasan todos los datos de recursos, por lo que podría usar PUT para las actualizaciones, pero cada vez que emito una actualización guardo las columnas LastUser y LastUpdate, con el ID de usuario que realizó la modificación y la hora de la operación.

Así que me gustaría saber su opinión, porque estrictamente hablando, estas dos columnas no son parte del recurso, pero sí evitan que la operación sea idempotente.

saludos

sas


Como LastUser y LastUpdate no son modificables por el cliente, los eliminaría de la representación de su recurso por completo. Déjame explicarte mi razonamiento con un ejemplo.

Digamos que nuestra API de ejemplo típica devolverá la siguiente representación al cliente cuando se le pida que proporcione un solo recurso:

GET /example/123 <?xml version="1.0" encoding="UTF-8" ?> <example> <id>123</id> <lorem>ipsum</lorem> <dolor>sit amet</dolor> <lastUser uri="/user/321">321</lastUser> <lastUpdate>2011-04-16 20:00:00 GMT</lastUpdate> </example>

Si un cliente desea modificar el recurso, presumiblemente tomaría toda la representación y la enviaría de vuelta a la API.

PUT /example/123 <?xml version="1.0" encoding="UTF-8" ?> <example> <id>123</id> <lorem>foobar</lorem> <dolor>foobaz</dolor> <lastUser>322</lastUser> <lastUpdate>2011-04-16 20:46:15 GMT+2</lastUpdate> </example>

Dado que la API genera valores para lastUser y lastUpdate automáticamente y no puede aceptar los datos proporcionados por el cliente, la respuesta más adecuada sería 400 Bad Request o 403 Forbidden (ya que el cliente no puede modificar estos valores).

Si queremos cumplir con REST y enviar una representación completa del recurso al realizar una solicitud PUT, debemos eliminar lastUser y lastUpdate de la representación del recurso. Esto permitirá a los clientes enviar la entidad completa a través de PUT:

PUT /example/123 <?xml version="1.0" encoding="UTF-8" ?> <example> <id>123</id> <lorem>foobar</lorem> <dolor>foobaz</dolor> </example>

El servidor aceptaría una representación completa ahora que no contiene lastUpdate y lastUser .

La pregunta que queda es cómo proporcionar a los clientes acceso a lastUpdate y lastUser . Si no lo necesitan (y estos campos son requeridos solo internamente por la API), estamos bien y nuestra solución es perfectamente REST. Sin embargo, si los clientes necesitan acceso a estos datos, el enfoque más limpio sería utilizar encabezados HTTP:

GET /example/123 ... Last-Modified: Sat, 16 Apr 2011 18:46:15 GMT X-Last-User: /user/322 ... <?xml version="1.0" encoding="UTF-8" ?> <example> <id>123</id> <lorem>foobar</lorem> <dolor>foobaz</dolor> </example>

El uso de un encabezado HTTP personalizado no es ideal porque los agentes de usuario deben aprender a leerlos. Si queremos brindarles a los clientes acceso a los mismos datos de una manera más fácil, lo único que podemos hacer es poner los datos en la representación, y estamos enfrentando el mismo problema que en su pregunta original. Al menos trataría de mitigarlo de alguna manera. Si el tipo de contenido utilizado por la API es XML, podemos colocar los datos en atributos de nodo en lugar de exponerlos directamente como valores de nodo, es decir:

GET /example/123 ... Last-Modified: Sat, 16 Apr 2011 18:46:15 GMT ... <?xml version="1.0" encoding="UTF-8" ?> <example last-update="2011-04-16 18:46:15 GMT" last-user="/user/322"> <id>123</id> <lorem>foobar</lorem> <dolor>foobaz</dolor> </example>

De esta manera, al menos evitaremos el problema de que un cliente intente enviar todos los nodos XML en una solicitud PUT de seguimiento. Esto no funcionará con JSON, y la solución todavía está un poco al borde de la idempotencia (ya que la API todavía tendría que ignorar los atributos XML al procesar la solicitud).

Aún mejor, como señaló Jonah en los comentarios, si los clientes necesitan acceso a lastUser y lastUpdate , estos pueden exponerse como un nuevo recurso, vinculado desde el original, por ejemplo, de la siguiente manera:

GET /example/123 <?xml version="1.0" encoding="UTF-8" ?> <example> <id>123</id> <lorem>foobar</lorem> <dolor>foobaz</dolor> <lastUpdateUri>/example/123/last-update</lastUpdateUri> </example>

... y entonces:

GET /example/123/last-update <?xml version="1.0" encoding="UTF-8" ?> <lastUpdate> <resourceUri>/example/123</resourceUri> <updatedBy uri="/user/321">321</updatedBy> <updatedAt>2011-04-16 20:00:00 GMT</updatedAt> </lastUpdate>

(Lo anterior también se puede ampliar muy bien para proporcionar un registro de auditoría completo con cambios individuales, siempre que esté disponible un registro de cambios de recursos).

Tenga en cuenta:
Estoy de acuerdo con la opinión de sobre la pregunta , pero quería proporcionarle un enfoque diferente. Tenga en cuenta que este enfoque no está respaldado por ningún estándar / RFC / etc, es solo una versión diferente del problema.


Ignorando el comentario sobre el estilo REST que asigna CRUD a los métodos HTTP, esta es una excelente pregunta.

La respuesta a su pregunta es, sí, tiene la libertad de usar PUT en este escenario, aunque hay algunos elementos del recurso que el servidor actualiza de manera no identiva. Desafortunadamente, el razonamiento detrás de la respuesta es bastante vago. Lo importante, es entender cuál era la intención de la solicitud del cliente. El cliente pretendía reemplazar completamente el contenido del recurso con los valores pasados. El cliente no es responsable de que el servidor realice otras operaciones y, por lo tanto, no se viola la semántica del método HTTP.

Este es el razonamiento que se utiliza para permitir que un servidor actualice un contador de páginas cuando realiza una operación GET. El cliente no solicitó una actualización, por lo tanto, el GET es seguro a pesar de que el servidor eligió realizar una actualización.

El debate completo, completo sobre recursos frente a recursos parciales, finalmente se explicó en una actualización de la especificación HTTP.

Un servidor de origen DEBERÍA rechazar cualquier solicitud PUT que contenga un campo de encabezado de rango de contenido, ya que podría ser malinterpretado como contenido parcial (o podría ser un contenido parcial que se está PUT erróneamente como una representación completa). Las actualizaciones parciales de contenido son posibles al apuntar a un recurso identificado por separado con un estado que se superpone a una parte del recurso más grande, o al usar un método diferente que se haya definido específicamente para actualizaciones parciales (por ejemplo, el método PATCH definido en [RFC5789]).

Entonces, lo que se supone que debemos hacer ahora está claro. Lo que no está tan claro es por qué existe esta restricción para que solo se le permita enviar respuestas completas. Esa pregunta ha sido formulada y, en mi humilde opinión, sigue sin respuesta en este hilo sobre la discusión en reposo.


La desventaja de usar PUT para crear recursos es que el cliente debe proporcionar la ID única que representa el objeto que está creando. Si bien es posible que el cliente genere este ID único, la mayoría de los diseñadores de aplicaciones prefieren que sus servidores (generalmente a través de sus bases de datos) creen este ID. En la mayoría de los casos, queremos que nuestro servidor controle la generación de ID de recursos. ¿Asi que que hacemos? Podemos cambiar a utilizar POST en lugar de PUT.

Asi que:

Put = ACTUALIZACIÓN

Post = INSERTAR

Con suerte, esto ayuda para su caso específico.


Los métodos HTTP POST y PUT no son el equivalente HTTP de la creación y actualización de CRUD. Ambos sirven a un propósito diferente. Es bastante posible, válido e incluso preferido en algunas ocasiones, usar PUT para crear recursos, o usar POST para actualizar recursos.

Use PUT cuando pueda actualizar un recurso completamente a través de un recurso específico. Por ejemplo, si sabe que un artículo reside en http://example.org/article/1234 , puede PONER una nueva representación de recursos de este artículo directamente a través de un PUT en esta URL.

Si no conoce la ubicación real del recurso, por ejemplo, cuando agrega un nuevo artículo, pero no tiene idea de dónde almacenarlo, puede enviarlo a una URL y dejar que el servidor decida la URL real.