RESTO punto final para mostrar una vista previa antes de publicar

17

Estoy diseñando una nueva aplicación web que funciona con un backend REST y una interfaz HTML + JS.

Hay un método POST para cambiar una entidad (llamemos a Config), que tiene varios efectos secundarios en el estado de muchos elementos de la aplicación. Supongamos que la POST se realiza de esta manera:

POST /api/config BODY {config: ....}

Debido a esto, me gustaría mostrar una vista previa antes de que se realicen esos cambios, para que el usuario final pueda darse cuenta de lo que va a cambiar.

Lo primero que pensé fue hacer un punto final GET para la vista previa, enviando el cuerpo del nuevo estado de la entidad. De esta manera:

GET /api/preview/items BODY {config: ....}

Puede mostrar el nuevo estado de los elementos con la nueva configuración.

GET /api/preview/sales BODY {config: ....}

Podría mostrar el nuevo estado de las ventas con la nueva configuración.

Parece una buena idea usar el verbo GET ya que no estoy alterando el estado de la aplicación. Sin embargo, se desaconseja el uso de un cuerpo de solicitud con solicitudes GET .

¿Hay alguna buena práctica sobre esto? Otra opción podría ser almacenar la configuración como un borrador con un método y mostrar los resultados con otros, pero requeriría un paso adicional y tener que administrar los borradores en el servidor:

POST /api/preview/config BODY {config: ....}

GET /api/preview/items?idPreviewConfig=1
Xtreme Biker reinstala a Monica
fuente
¿Qué podría ser exactamente esta configuración y cómo afecta a la itemso sales? ¿Afecta la representación de la entidad devuelta?
Andy
Supongamos que los artículos y las ventas se ven afectados por los cambios que realiza en la configuración.
Xtreme Biker reinstala a Monica el
¿Pero qué significan los cambios? ¿Cambia el conjunto de entidades devueltas? ¿Cambia la estructura devuelta?
Andy
En realidad, cambia los valores para itemsy sales(no la estructura), dependiendo de la configuración que PUBLICES.
Xtreme Biker reinstala a Monica el
¿Y qué tan grande es exactamente la configuración? ¿Puede crecer hasta varios cientos de kilobytes o incluso más?
Andy

Respuestas:

27

Esto es demasiado específico del dominio para tener un soporte nativo en HTTP.

En su lugar, puede hacer uno de los siguientes:

  1. Tener un POST /api/config/preview. En el lado del servidor, la aplicación sabrá que no debe modificar la configuración real, sino que combinará la real con la que publicó y devolverá el resultado que indica lo que se modificó.

    Más tarde, si el usuario está satisfecho con el resultado, realizará una que POST /api/configcontenga la misma carga útil que en la solicitud anterior. Esto sobrescribirá efectivamente la configuración.

    El beneficio de este enfoque es que no está realizando cambios importantes en la API actual. Los clientes que no necesitan la función de vista previa aún podrán actualizar las entradas como lo hacían antes.

    El inconveniente es que cuando el cuerpo es grande, significaría que sería necesario enviarlo dos veces al servidor. Si este es su caso, puede utilizar el siguiente enfoque.

  2. Tenga un POST /api/config/prepareque recuerde lo que se envió en un registro temporal y devuelva dos cosas: la ID del registro temporal (por ejemplo 12345) y la vista previa de los cambios.

    Si el usuario está satisfecho con el resultado, realizará una POST /api/config/commit/12345para almacenar definitivamente los cambios. De lo contrario, el registro temporal puede conservarse durante un tiempo y luego descartarse mediante un trabajo cron.

    El beneficio es que, aquí nuevamente, puede mantener el original POST /api/configintacto, y los clientes que no necesitan una vista previa no se romperán.

    Los inconvenientes son que (1) manejar la eliminación de registros temporales puede ser complicado (¿qué te hace pensar que una hora es suficiente? ¿Qué pasa si diez minutos después, te quedas sin memoria? ¿Cómo manejan los clientes un HTTP 404 cuando hacen un commit de un registro que expiró?) y que (2) la presentación en dos pasos de un registro puede ser más complicado de lo necesario.

  3. Mueva la lógica de vista previa en el lado del cliente.

Arseni Mourzenko
fuente
¿Qué pasa con el envío de un encabezado que dice "no persista esto, solo muéstreme qué pasa si"? Lo editaré en la respuesta si te parece bien @ArseniMourzenko
marstato
1
@marstato: personalmente, no soy particularmente aficionado a los encabezados HTTP para ese uso. Aunque puede tener sentido para otras personas, entonces estoy bien si editas mi respuesta. Tenga en cuenta que también puede publicar su propia respuesta, lo que permitiría a otros votarla (y le dará puntos de reputación).
Arseni Mourzenko
Supongo que la opción 1 se adapta mejor a mi caso. Entonces, PUBLICA la configuración de vista previa y tiene los cambios en el resultado, en lugar de tener que definir puntos finales de vista previa para cada una de las entidades definidas. Parece razonable. Lo único es que está utilizando una POST para no hacer cambios en el servidor, técnicamente hablando. La opción 3 no es viable en mi caso.
Xtreme Biker reinstala a Monica el
1
@PedroWerneck ¿Puedes ampliar eso? Me parece que la opción 2 define otra entidad (un borrador de configuración) y proporciona formas sin estado para interactuar con ellas.
Andrew dice Reinstate Monica
1
@PedroWerneck Tiene estado de la misma manera que el almacenamiento de una configuración en el servidor tiene estado. Por lo tanto, la aplicación ya tiene estado desde su perspectiva y también lo son todas las opciones para agregar esta función.
jpmc26
10

El punto de usar verbos HTTP específicos para diferentes llamadas de API en REST es aprovechar la mecánica y las expectativas HTTP existentes.

Usar un GET en este caso parece ir en contra de ambos.

A. ¿El cliente necesita incluir un cuerpo con un GET? inesperado

B. ¿El servidor devuelve una respuesta diferente a un get dependiendo del cuerpo? rompe las especificaciones y la mecánica de almacenamiento en caché

Si estás luchando con preguntas RESTful, mi regla es preguntarme.

"¿Cómo es esto mejor que simplemente usar POST para todo?"

A menos que haya un beneficio inmediato y obvio, vaya con la estrategia Just Use POST Stupid (JUPS)

Ewan
fuente
Jajaja buena captura
Xtreme Biker reincorpora a Mónica
@Ewan ... independientemente de si este es un enfoque pragmático o no ... si está utilizando POST para todo, debe tenerse en cuenta que en realidad no es RESTful.
Allenph
1
bueno, a menos que POST sea la opción adecuada para todos sus métodos. Y no es que haya una regla objetiva que pueda aplicar, solo estaríamos discutiendo nuestras interpretaciones subjetivas de lo que es poco más que una guía.
Ewan
6

Puede enviar un encabezado que indique al servidor "no insista en esto, solo muéstreme cuál sería el resultado si lo hiciera". P.ej

POST /api/config HTTP/1.1
Host: api.mysite.com
Content-Type: application/json
Persistence-Options: simulate

{
   "config": {
      "key": "value"
   }
}

A lo que el servidor podría responder:

HTTP/1.1 200 OK
Persistence-Options: simulated
Content-Type: application/json

-- preview --

Tenga en cuenta que, si utiliza una O / RM basada en la Unidad de trabajo y / o transacciones por solicitud con su base de datos, puede implementar fácilmente esta funcionalidad para todos sus puntos finales sin necesidad de trabajar en ningún punto final particular: si una solicitud llega con esa opción , revierta la transacción / unidad de trabajo en lugar de confirmarla.

marstato
fuente
@PeterRader buen punto, eliminado elX-
marstato
De nada. ¿Diría que una entidad bajo simulación debería representarse como "bajo simulación"?
Peter Rader
No; ese es el punto de una simulación, ¿no? El valor del encabezado también podría ser, nonepero eso, para mi gusto, contradiría demasiado la naturaleza del POSTmétodo.
marstato
2

Sugeriría tratar esto de la misma manera que trata las búsquedas. Establecería un punto final POST en el /api/config/previewque CREA una nueva vista previa. Luego, configuraría un punto final PUT o PATCH api/configdependiendo de si tiene la intención de editar la configuración actual, o simplemente reemplazar toda la configuración (presumiblemente en el primer caso estaría enviando la vista previa que acaba de crear).

Allenph
fuente
0

Junto con las otras buenas respuestas, otra opción podría ser publicar la configuración como se mencionó, y tener un proceso de reversión disponible también. Creo que, al igual que la metodología Agile, es mejor tener menos miedo a los cambios al tener procedimientos más granulares, repetibles y probados, y esto le daría una copia de seguridad cuando la necesite, reduciendo el riesgo a poco o nada, dependiendo de la aplicación .

Por otra parte, si puede tener errores de configuración que afecten a todo el sistema, le gustaría manejarlo más activamente, y si ese es el caso, ¿por qué no simplemente hacer un esfuerzo para obtener una vista previa de los cambios en ese punto, desde la perspectiva de un servidor o cliente? Aunque, puedo ver cómo esta característica de vista previa podría ser más costosa de desarrollar, en los casos de uso tienen su propio conjunto de pasos dispares para seguir y probar.

Pisis
fuente
0

RFC6648 desprecia nuevoX- construcciones, así que debo votar en contra de la idea de enviar un nuevo campo de encabezado. REST es un estilo de arquitectura, de lo que hablamos es RESTful, pero ignoremos eso por el momento.

Debido a que REST es representativo (y una simulación no tiene representación en la realidad) y con estado (y una simulación no es un estado hasta su compromiso) debemos tener un nuevo alcance, como un alcance de simulación. Pero debemos llamarlo emulación en lugar de simulación porque la simulación incluye el proceso de simulación, pero con estado significa que tenemos un estado permanente, una solución ideal de una simulación: una emulación. Por lo tanto, debemos llamarlo emulación en la URL. Esto también podría ser una buena solución:

GET  /api/emulation - 200 OK {first:1, last:123}
POST /api/emulation/124 - 200 OK
GET  /api/emulation/124/config - 200 OK {config:{tax:8}}
PUT  /api/emulation/124/config {config:{tax:16}} - 200 OK {config:{tax:16}}
GET  /api/emulation/124/items - 200 OK [first:1, last: 3000]
GET  /api/emulation/124/items/1 - 200 OK {price:1.79, name:'Cup'}
--- show emulation ---
--- commit emulation ---
PUT /api/config {config:{tax:16}}
DELETE /api/emulation/124 - 200 OK

Hay otro enfoque ... es posible que haya notado que muchas solicitudes del cliente HTML / JavaScript pueden producir demasiadas solicitudes , lo que alcanza el límite de aproximadamente 17 solicitudes al mismo tiempo (eche un vistazo a esta página ). Puede intercambiar el uso de REST y, en lugar de entregar estados de objeto poco convincentes, puede entregar estados de página específicos de usuario enriquecidos. Ejemplo:

GET /user/123/config - 200 OK {user:'Tim', date:3298347239847, currentItem:123, 
                  roles:['Admin','Customer'], config:{tax:16}, unsavedChanges:true, ...}

Saludos cordiales

Peter Rader
fuente