Me pregunto cómo implementaría el siguiente caso de uso en REST. ¿Es posible hacerlo sin comprometer el modelo conceptual?
Lea o actualice múltiples recursos dentro del alcance de una sola transacción. Por ejemplo, transfiera $ 100 de la cuenta bancaria de Bob a la cuenta de John.
Por lo que puedo decir, la única forma de implementar esto es haciendo trampa. Puede PUBLICAR en el recurso asociado con John o Bob y llevar a cabo toda la operación utilizando una sola transacción. En lo que a mí respecta, esto rompe la arquitectura REST porque esencialmente está haciendo un túnel de una llamada RPC a través de POST en lugar de realmente operar en recursos individuales.
Hay algunos casos importantes que no se responden con esta pregunta, lo que creo que es una lástima, porque tiene una clasificación alta en Google para los términos de búsqueda :-)
Específicamente, una buena propiedad sería: si PUBLICA dos veces (porque algo de caché tiene hipo en el intermedio), no debe transferir la cantidad dos veces.
Para llegar a esto, crea una transacción como un objeto. Esto podría contener todos los datos que ya conoce y poner la transacción en un estado pendiente.
Una vez que tenga esta transacción, puede confirmarla, algo como:
Tenga en cuenta que las posiciones múltiples no importan en este punto; incluso un GET en el txn devolvería el estado actual. Específicamente, el segundo PUT detectaría que el primero ya estaba en el estado apropiado y simplemente lo devolvería, o, si intenta ponerlo en el estado "revertido" después de que ya esté en el estado "comprometido", obtendrá un error, y la transacción confirmada real de vuelta.
Siempre que hable con una sola base de datos, o una base de datos con un monitor de transacciones integrado, este mecanismo realmente funcionará bien. También puede introducir tiempos de espera para las transacciones, que incluso podría expresar utilizando encabezados de Expires si lo desea.
fuente
En términos REST, los recursos son sustantivos sobre los que se puede actuar con verbos CRUD (crear / leer / actualizar / eliminar). Dado que no hay un verbo "transferir dinero", necesitamos definir un recurso de "transacción" que se pueda actuar con CRUD. Aquí hay un ejemplo en HTTP + POX. El primer paso es CREAR (método HTTP POST) una nueva transacción vacía :
Esto devuelve una ID de transacción, por ejemplo, "1234" y según la URL "/ transacción / 1234". Tenga en cuenta que disparar esta POST varias veces no creará la misma transacción con múltiples ID y también evita la introducción de un estado "pendiente". Además, POST no siempre puede ser idempotente (un requisito REST), por lo que generalmente es una buena práctica minimizar los datos en POST.
Puede dejar la generación de un ID de transacción al cliente. En este caso, POST / transacción / 1234 crearía la transacción "1234" y el servidor devolvería un error si ya existía. En la respuesta de error, el servidor podría devolver una ID actualmente no utilizada con una URL apropiada. No es una buena idea consultar al servidor para obtener una nueva ID con un método GET, ya que GET nunca debería alterar el estado del servidor, y crear / reservar una nueva ID alteraría el estado del servidor.
A continuación, ACTUALIZAMOS (método PUT HTTP) la transacción con todos los datos, comprometiéndolos implícitamente:
Si una transacción con ID "1234" ha sido PUT anteriormente, el servidor da una respuesta de error, de lo contrario, una respuesta OK y una URL para ver la transacción completada.
NB: en / account / john, "john" realmente debería ser el número de cuenta único de John.
fuente
Gran pregunta, REST se explica principalmente con ejemplos similares a bases de datos, donde algo se almacena, actualiza, recupera y elimina. Hay pocos ejemplos como este, donde se supone que el servidor procesa los datos de alguna manera. No creo que Roy Fielding haya incluido ninguno en su tesis, que se basó en http después de todo.
Pero sí habla de la "transferencia de estado de representación" como una máquina de estado, con enlaces que se mueven al siguiente estado. De esta manera, los documentos (las representaciones) realizan un seguimiento del estado del cliente, en lugar de que el servidor tenga que hacerlo. De esta manera, no hay estado del cliente, solo el estado en términos de en qué enlace está.
He estado pensando en esto, y me parece razonable que para que el servidor procese algo por usted, cuando carga, el servidor creará automáticamente recursos relacionados y le dará los enlaces a ellos (de hecho, no no es necesario crearlos automáticamente: solo podría decirle los enlaces, y solo los creará cuando y si los sigue: creación perezosa). Y también para darle enlaces para crear nuevos recursos relacionados: un recurso relacionado tiene el mismo URI pero es más largo (agrega un sufijo). Por ejemplo:
/transaction
fallos ocasionarán la creación de múltiples recursos, cada uno con un URI diferente./transaction/1234/proposed
,/transaction/1234/committed
Esto es similar a cómo funcionan las páginas web, con la página final diciendo "¿estás seguro de que quieres hacer esto?" Esa página web final es en sí misma una representación del estado de la transacción, que incluye un enlace para ir al siguiente estado. No solo transacciones financieras; también (por ejemplo) vista previa y luego confirmar en wikipedia. Supongo que la distinción en REST es que cada etapa en la secuencia de estados tiene un nombre explícito (su URI).
En las transacciones / ventas de la vida real, a menudo hay diferentes documentos físicos para las diferentes etapas de una transacción (propuesta, orden de compra, recibo, etc.). Aún más por comprar una casa, con liquidación, etc.
OTOH Esto se siente como jugar con la semántica para mí; Me incomoda la nominalización de convertir verbos en sustantivos para que sea RESTful, "porque usa sustantivos (URI) en lugar de verbos (llamadas RPC)". es decir, el sustantivo "recurso de transacción comprometida" en lugar del verbo "comprometer esta transacción". Supongo que una ventaja de la nominalización es que puede referirse al recurso por su nombre, en lugar de tener que especificarlo de alguna otra manera (como mantener el estado de la sesión, para saber qué es "esta" transacción ...)
Pero la pregunta importante es: ¿Cuáles son los beneficios de este enfoque? es decir, ¿de qué manera es mejor este estilo REST que el estilo RPC? ¿Es una técnica excelente para páginas web también útil para procesar información, más allá de almacenar / recuperar / actualizar / eliminar? Creo que el beneficio clave de REST es la escalabilidad; Un aspecto de esto no es la necesidad de mantener el estado del cliente explícitamente (sino hacerlo implícito en el URI del recurso, y los siguientes estados como enlaces en su representación). En ese sentido, ayuda. ¿Quizás esto también ayuda en la estratificación / canalización? OTOH solo un usuario mirará su transacción específica, por lo que no hay ninguna ventaja en almacenarla en caché para que otros puedan leerla, la gran victoria para http.
fuente
Si retrocede para resumir la discusión aquí, está bastante claro que REST no es apropiado para muchas API, particularmente cuando la interacción cliente-servidor es intrínsecamente dinámica, como lo es con las transacciones no triviales. ¿Por qué pasar por todos los aros sugeridos, tanto para el cliente como para el servidor, a fin de seguir pedantemente algún principio que no se ajuste al problema? Un mejor principio es dar al cliente la forma más fácil, más natural y productiva de componer la aplicación.
En resumen, si realmente está haciendo muchas transacciones (tipos, no instancias) en su aplicación, realmente no debería crear una API RESTful.
fuente
Me he alejado de este tema durante 10 años. Volviendo, no puedo creer la religión que se hace pasar por ciencia en la que te sumerges cuando buscas en Google + confiable. La confusión es mítica.
Yo dividiría esta amplia pregunta en tres:
Esto es importante porque permite que todas las solicitudes posteriores sean totalmente idempotentes, en el sentido de que si se repiten n veces devuelven el mismo resultado y no hacen que suceda nada más. El servidor almacena todas las respuestas contra la identificación de la acción y, si ve la misma solicitud, reproduce la misma respuesta. Un tratamiento más completo del patrón se encuentra en este documento de google . El documento sugiere una implementación que, creo (!), Sigue ampliamente los principios de REST. Los expertos seguramente me dirán cómo viola a otros. Este patrón puede ser útil para cualquier llamada insegura a su servicio web, ya sea que haya o no transacciones posteriores involucradas.
Su requerimiento es fundamental. No dejes que la gente te diga que tu solución no es kosher. Juzgue sus arquitecturas a la luz de qué tan bien y cómo simplemente abordan su problema.
fuente
Tendría que rodar su propio tipo de "identificación de transacción" de gestión de tx. Entonces serían 4 llamadas:
Tendría que manejar el almacenamiento de las acciones en una base de datos (si la carga está equilibrada) o en la memoria o tal, luego manejar la confirmación, la reversión y el tiempo de espera.
No es realmente un día de descanso en el parque.
fuente
Creo que en este caso es totalmente aceptable romper la teoría pura de REST en esta situación. En cualquier caso, no creo que haya nada realmente en REST que diga que no puede tocar objetos dependientes en casos comerciales que lo requieran.
Realmente creo que no vale la pena los aros adicionales por los que pasaría para crear un administrador de transacciones personalizado, cuando simplemente podría aprovechar la base de datos para hacerlo.
fuente
En primer lugar, transferir dinero no es nada que no pueda hacer en una sola llamada de recursos. La acción que quieres hacer es enviar dinero. Entonces agrega un recurso de transferencia de dinero a la cuenta del remitente.
Hecho. No necesita saber que esta es una transacción que debe ser atómica, etc. Simplemente transfiere dinero, también conocido como. enviar dinero de A a B.
Pero para los casos raros aquí una solución general:
Si desea hacer algo muy complejo que involucre muchos recursos en un contexto definido con muchas restricciones que realmente crucen la barrera de qué versus por qué (conocimiento de negocio versus implementación) necesita transferir el estado. Como REST no debería tener estado, usted como cliente debe transferir el estado.
Si transfiere el estado, debe ocultar la información del cliente. El cliente no debe conocer la información interna que solo necesita la implementación, pero no lleva información relevante en términos de negocio. Si esa información no tiene valor comercial, el estado debe estar encriptado y debe usarse una metáfora como token, pase o algo.
De esta manera, se puede pasar el estado interno y usar cifrado y firmar el sistema puede ser seguro y sólido. Encontrar la abstracción correcta para el cliente por qué pasa la información del estado es algo que depende del diseño y la arquitectura.
La verdadera solución:
Recuerde que REST está hablando de HTTP y HTTP viene con el concepto de usar cookies. Esas cookies a menudo se olvidan cuando las personas hablan sobre API REST y flujos de trabajo e interacciones que abarcan múltiples recursos o solicitudes.
Recuerde lo que está escrito en Wikipedia sobre las cookies HTTP:
Básicamente, si necesita pasar el estado, use una cookie. Está diseñado exactamente por la misma razón, es HTTP y, por lo tanto, es compatible con REST por diseño :).
La mejor solución:
Si habla de un cliente que realiza un flujo de trabajo que involucra múltiples solicitudes, generalmente habla del protocolo. Cada forma de protocolo viene con un conjunto de condiciones previas para cada paso potencial, como realizar el paso A antes de poder hacer B.
Esto es natural, pero exponer el protocolo a los clientes hace que todo sea más complejo. Para evitarlo, solo piense en lo que hacemos cuando tenemos que hacer interacciones complejas y cosas en el mundo real ... Usamos un agente.
Usando la metáfora del Agente, puede proporcionar un recurso que puede realizar todos los pasos necesarios para usted y almacenar la asignación / instrucciones reales sobre las que está actuando en su lista (para que podamos usar POST en el agente o una 'agencia').
Un ejemplo complejo:
Comprando una casa:
Debe demostrar su credibilidad (como proporcionar sus registros policiales), debe garantizar los detalles financieros, debe comprar la casa real con un abogado y un tercero de confianza que almacene los fondos, verificar que la casa ahora le pertenece a usted y agregue las cosas de compra a sus registros de impuestos, etc. (solo como ejemplo, algunos pasos pueden ser incorrectos o lo que sea).
Estos pasos pueden tardar varios días en completarse, algunos se pueden hacer en paralelo, etc.
Para hacer esto, solo le da al agente la tarea de comprar una casa como:
Hecho. La agencia le devuelve una referencia que puede usar para ver y rastrear el estado de este trabajo y el resto lo hacen automáticamente los agentes de la agencia.
Piense en un rastreador de errores, por ejemplo. Básicamente, informa el error y puede usar la identificación del error para verificar qué está sucediendo. Incluso puede usar un servicio para escuchar los cambios de este recurso. Misión cumplida.
fuente
No debe usar transacciones del lado del servidor en REST.
Una de las restricciones REST:
La única forma RESTful es crear un registro de rehacer la transacción y ponerlo en el estado del cliente. Con las solicitudes, el cliente envía el registro de rehacer y el servidor rehace la transacción y
Pero quizás sea más simple usar una tecnología basada en sesión de servidor que admita transacciones del lado del servidor.
fuente
Creo que ese sería el caso de usar un identificador único generado en el cliente para garantizar que el problema de conexión no implique una duplicidad guardada por la API.
Creo que usar un campo GUID generado por el cliente junto con el objeto de transferencia y garantizar que el mismo GUID no se reinserte nuevamente sería una solución más simple para el asunto de la transferencia bancaria.
No conozca escenarios más complejos, como la reserva de múltiples boletos aéreos o micro arquitecturas.
Encontré un artículo sobre el tema, relatando las experiencias de tratar con la atomicidad de la transacción en los servicios RESTful .
fuente
En el caso simple (sin recursos distribuidos), podría considerar la transacción como un recurso, donde el acto de crearla alcanza el objetivo final.
Entonces, para transferir entre
<url-base>/account/a
y<url-base>/account/b
, puede publicar lo siguiente en<url-base>/transfer
.Esto crearía un nuevo recurso de transferencia y devolvería la nueva url de la transferencia, por ejemplo
<url-base>/transfer/256
.En el momento de la publicación exitosa, entonces, la transacción 'real' se lleva a cabo en el servidor, y la cantidad se elimina de una cuenta y se agrega a otra.
Sin embargo, esto no cubre una transacción distribuida (si, por ejemplo, 'a' se mantiene en un banco detrás de un servicio, y 'b' se mantiene en otro banco detrás de otro servicio), aparte de decir "intente expresar todo operaciones en formas que no requieren transacciones distribuidas ".
fuente
Supongo que podría incluir el TAN en la URL / recurso:
Solo una idea.
fuente