si utilizo el método PUT para la actualización, si también actualizo un atributo timestamp


Para ser más precisos:

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

De hecho, si nos atenemos a la definición de 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 de creación o actualización ingenua podría no admitir. Sospecho que esta puede ser la razón por la que PUT se define como es; es una operación idempotente que permite al cliente enviar información al servidor.

En mi caso suelo emitir actualizaciones pasando todos los datos del recurso, por lo que podría usar PUT para actualizaciones, pero cada vez que emito una actualización guardo una columna LastUser y LastUpdate, con el id de usuario que hizo la modificación y la hora de la operación.

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

Saludos

Sas

Author: opensas, 2011-04-16

4 answers

Ignorando el comentario sobre la asignación de CRUD de estilo REST a los métodos HTTP, esta es una pregunta excelente.

La respuesta a su pregunta es, sí, usted es libre de usar PUESTO en este escenario a pesar de que hay algunos elementos del recurso que son actualizados por el servidor de una manera no idempotente. 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 tenía la intención de reemplace 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 usa para permitir que un servidor actualice un contador de páginas cuando realiza una operación GET. El cliente no pidió una actualización, por lo tanto, el GET es seguro a pesar de que el servidor eligió hacer una actualización.

El debate de recursos completos versus recursos parciales tiene finalmente se ha explicado en una actualización de la especificación HTTP

Un servidor de origen DEBE rechazar cualquier PUT solicitud que contiene un Campo de encabezado Content-Range, ya que puede ser malinterpretado como parcial contenido (o podría ser contenido parcial que se está poniendo erróneamente como un representación plena). Contenido parcial las actualizaciones son posibles al dirigirse a recursos identificados por separado con estado que se superpone a una porción de el recurso más grande, o por usando un método diferente que ha sido específicamente definido para parcial actualizaciones (por ejemplo, el PARCHE método 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 de que solo se le permita enviar respuestas completas. Esa pregunta ha sido formulada y MI Humilde opinión permanece sin respuesta en este hilo en rest-discuss.

 23
Author: Darrel Miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-16 13:54:36

Como LastUser y LastUpdate no son modificables por el cliente, los eliminaría de la representación de su recurso por completo. Permítanme explicar 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 quiere 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 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 ser compatibles con REST y enviar una representación completa del recurso al hacer una solicitud PUT, necesitamos 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 internamente por la API), estamos bien y nuestra solución es perfectamente RESTful. Sin embargo, si los clientes necesitan acceso a estos datos, el enfoque más limpio sería usar 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>

Usar un encabezado HTTP personalizado no es ideal porque los agentes de usuario necesitan que se les enseñe cómo leerlo. Si queremos proporcionar 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 nos enfrentamos al mismo problema que en su pregunta original. Al menos intentaría mitigarlo de alguna manera. Si el tipo de contenido utilizado por la API es XML, podemos poner 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 en el que un cliente intentaría 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 idempotency (ya que la API todavía tendría que ignorar los atributos XML al procesar la solicitud).

Aún mejor, como Jonah señaló 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, como sigue:

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 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 Darrel Miller 's asumir la pregunta , pero yo quería proporcionar un enfoque diferente en la parte superior de la misma. Tenga en cuenta que este enfoque no está respaldado por ningún estándar/RFC/etc, es solo una versión diferente de la problema.

 7
Author: MicE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:10

La desventaja de usar PUT para crear recursos es que el cliente tiene que proporcionar el ID único que representa el objeto que está creando. Si bien generalmente 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. Entonces, ¿qué hacemos? Podemos cambiar a usar POST en lugar de PUT.

Así que:

Poner = UPDATE

Post = INSERTAR

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

 3
Author: Cristian Boariu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-16 13:03:54

Los métodos HTTP POST y PUT no son el equivalente HTTP de create y update de CRUD. Ambos tienen un propósito diferente. Es muy posible, válido e incluso preferido en algunas ocasiones, usar PUT para crear recursos, o usar POST para actualizar recursos.

Use PUT cuando puede 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 PUESTO 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 publicarlo en una URL y dejar que el servidor decida la URL real.

 0
Author: Anil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-09 17:46:09