¿Cuál es el punto con HATEOAS en el lado del cliente?

35

Como entiendo actualmente, HATEOAS se trata básicamente de enviar junto con cada respuesta enlaces con información sobre qué hacer a continuación. Un ejemplo simple se encuentra fácilmente en Internet: un sistema bancario junto con un recurso de cuenta. El ejemplo muestra esta respuesta después de una solicitud GET a un recurso de cuenta

GET /account/12345 HTTP/1.1 HTTP/1.1 200 OK 
<?xml version="1.0"?> 
<account> 
    <account_number>12345</account_number> 
    <balance currency="usd">100.00</balance> 
    <link rel="deposit" href="/account/12345/deposit" /> 
    <link rel="withdraw" href="/account/12345/withdraw" /> 
    <link rel="transfer" href="/account/12345/transfer" /> 
    <link rel="close" href="/account/12345/close" /> 
</account>

Junto con los datos, hay enlaces que indican qué se puede hacer a continuación. Si el saldo es negativo tenemos

GET /account/12345 HTTP/1.1 HTTP/1.1 200 OK 
<?xml version="1.0"?> 
<account> 
    <account_number>12345</account_number> 
    <balance currency="usd">-25.00</balance> 
    <link rel="deposit" href="/account/12345/deposit" /> 
</account>

Para que solo podamos depositar. Eso está bien, si estamos usando Fiddler o haciendo solicitudes con el navegador, podemos ver fácilmente qué se puede hacer. Este tipo de información es útil para que descubramos las capacidades de la API y el servidor se desacople del cliente.

El punto, sin embargo, es que cuando creamos un cliente, como un SPA con Javascript, o una aplicación de Android o muchas otras cosas, no puedo ver cómo HATEOAS sigue siendo relevante. Lo que quiero decir es lo siguiente: cuando estoy codificando el SPA en JavaScript, debo saber qué se puede hacer en la API para escribir el código.

Por lo tanto, necesito conocer los recursos, los métodos admitidos, lo que esperan recibir y lo que devuelven para escribir las llamadas ajax en el servidor e incluso para construir la interfaz de usuario. Cuando construyo la IU, debo saber que después de solicitar la cuenta, uno puede, por ejemplo, depositar en ella, o no podré proporcionar esta opción en la IU. Además, necesitaré conocer el URI para hacer el depósito para construir la llamada ajax.

Lo que quiero decir es que, cuando hacemos solicitudes a la API, los enlaces nos permiten descubrir y usar la API mejor, pero cuando creamos un cliente, la aplicación que estamos construyendo no solo mirará los enlaces y luego se renderizará la interfaz de usuario correcta y hacer las llamadas correctas ajax.

Entonces, ¿cómo es importante HATEOAS para los clientes? ¿Por qué nos molestamos con HATEOAS de todos modos?

usuario1620696
fuente
1
Tienes razón, pero ese no es el punto. HATEOAS evita que tenga que construir los URI para los enlaces en la página del cliente.
James McLeod

Respuestas:

24

la aplicación que estamos construyendo no solo mirará los enlaces y, por sí sola, representará la IU correcta y realizará las llamadas ajax correctas

De hecho, esto es exactamente lo que HATEOAS le dará a la interfaz de usuario. No es lo que es posible, sino cuándo es posible. Un HATEOAS formal como HAL , como dice la pregunta, proporciona enlaces que indican lo que es posible. Pero cuando aparecen esos enlaces depende del estado de la aplicación. Por lo tanto, los enlaces pueden cambiar en el recurso con el tiempo (en función de las acciones que ya se han realizado).

Esto nos permite construir una interfaz de usuario que contenga todos los estados posibles , pero no nos preocupemos cuando esos estados se activen. Por ejemplo, la presencia de rel="deposit"puede indicar directamente a la interfaz de usuario cuándo está bien procesar el make depositformulario. Lo que luego le permite al usuario ingresar un valor y enviarlo usando el enlace.

Davin Tryon
fuente
2
Entonces, al construir la interfaz de usuario, aún necesitamos saber todo lo que ofrece la API, y luego, al mirar esos enlaces, ¿podemos saber en qué estado se encuentra la información en el servidor? Entonces, por ejemplo, la interfaz de usuario sabe que es posible depositar, retirar, transferir o cerrar (conoce los posibles recursos reales), y luego verifica qué regresó para ver el estado.
user1620696
1
Si, podria. Una vez más, depende de qué tan dinámico quiera tomarlo. Como otros han mencionado, la capacidad de cambiar enlaces en el servidor (y no romper clientes) es otra ventaja. Y esto se vuelve muy interesante una vez que su API tiene un iPhone, Android, Windows Phone, Web móvil y clientes web que todos lo usan (sin mencionar si su API se publica para que otros desarrollen clientes).
Davin Tryon
@ user1620696 Debería saber todo esto de todos modos a través del cliente y el servidor, entendiendo el tipo de contenido si el recurso. El tipo de contenido es mucho más que XML tonto o Json. Debería tener algún tipo de contenido de "depósito bancario" con el que el cliente entienda cómo trabajar
Cormac Mulhall
1
@Nik echa un vistazo a HAL para ver un ejemplo de cómo se proporcionan los enlaces en la respuesta.
Davin Tryon
1
Sí, aún tiene problemas de compatibilidad con versiones anteriores. Esto se puede resolver mediante la inclusión de un encabezado de versión o versión en la url. Pero, diría que estás entendiendo correctamente.
Davin Tryon
3

Como entiendo actualmente, HATEOAS se trata básicamente de enviar junto con cada respuesta enlaces con información sobre qué hacer a continuación

HATEOAS es mucho más que solo enlaces. Es "hipermedia" como motor del estado de la aplicación.

Lo que se pierde en su descripción es el tipo de contenido, la definición formal del hipermedio que se pasa entre el cliente y el servidor.

HTML es un ejemplo de los medios de comunicación hiper, y un ejemplo de por qué funciona HATEOS. La página HTML en sí es el motor que permite al cliente (es decir, el usuario) se mueva a través del sitio. Un navegador con sólo una capacidad de representar HTML presente al usuario una página web totalmente navegable. No es simplemente que pase enlaces a otras páginas, pero los pasa de una manera significativa que da contexto a los enlaces y de una manera que permite que el navegador para la construcción de un sitio navegable.

Y lo más importante, el navegador puede hacer esto con cero hasta la comprensión frente a la propia página web. El navegador sólo sabe HTTP y HTML. Sobre la base de ese simple comprensión de que puede presentar el New York Times para el usuario a través de navegar.

Esto se aplica incluso si el "usuario" es otro programa de computadora. Los propios medios hiper deben definir el contexto de la navegación.

Cormac Mulhall
fuente
1
¿No significa esto que se debe construir un cliente tan complejo (y error propenso) como un navegador? Flexibilidad a menudo viene con la complejidad como un costo ...
Andres F.
@AndresF. esto no significa que usted debe o debería hacerlo, simplemente le da la opción de hacerlo de forma dinámica si lo desea o lo necesita.
Peteris
2
@nik Claro. Fuera de mi cabeza imagina que tienes un servicio que proporciona información de ascendencia a través de una API relajante. Tiene un tipo de contenido que define el formato de un recurso 'Persona' que tiene información diversa sobre ellos, pero también define cómo se ven las relaciones, digamos 'hermano' o 'hermana' o 'madre', etc. Debido a que esto es hipermedia, esas relaciones simplemente tener un URI para otro recurso de persona. Un cliente bastante simple que utiliza los verbos HTTP y comprende este tipo de contenido 'Persona' puede navegar a través de esta API. Digamos que quieres encontrar a todos los descendientes directos de una persona en particular.
Cormac Mulhall
2
@nik Este cliente necesita comprender simplemente el tipo de contenido del recurso al que ha accedido y los verbos HTTP (GET, PUT, DELETE, etc.) y puede navegar a través de esta API buscando y actualizando recursos. Y, lo que es más importante, cualquier cliente que entienda el tipo de contenido puede saltar, a través de un URI, a otro servidor por completo y continuar como estaban. No les importa con qué servidor están hablando, solo les importa el tipo de contenido del recurso, lo entienden o no.
Cormac Mulhall
1
@Nik Entonces, en tal situación, tiene un servidor que comprende el tipo de contenido original (por ejemplo, Persona v1) y el nuevo tipo de contenido (Persona v2). El cliente solo entiende la Persona v1. El cliente le dice al servidor qué tipos de contenido entiende a través del encabezado Aceptar en HTTP. Mediante la negociación de contenido, el servidor determina si enviará lo que el cliente admite, en cuyo caso devolverá el recurso utilizando el tipo de contenido Persona v1. Ahora es posible que simplemente desee dejar de admitir este tipo de contenido antiguo y enviar al cliente un error 406. Sin embargo, es mejor intentar y apoyar todo lo que pueda.
Cormac Mulhall
2

No tiene que construir una interfaz generada dinámicamente. Aunque podría ser agradable, no es obligatorio. Si no puede construir una interfaz dinámica, simplemente use los enlaces y listo. La desventaja es que nuevamente está vinculado al backend y se bloqueará si algo cambia.

Usar el diseño dinámico puede ser bastante simple por cierto:

links.forEach(function(link) {

  switch(link.rel) {

    case 'deposit':
      showDepositButton();
      break;

    case 'withdraw':
      loadWithdrawForm(link.href);
      showWithdrawButton();
      break;
  }

});

Te ahorra en tu código de cliente como:

if (balance <= 0 && negativeBalanceAllowed === false) {
  showWithdrawButton();
}

Puede implementar una posición negativa permitida (tomando dinero prestado, por ejemplo) sin cambiar su cliente.

Luc Franken
fuente
Como un ejemplo ligeramente más fuerte, el banco puede ofrecer límites de sobregiro variables en sus cuentas, sin tener que decirle al cliente cuál es el límite en cada cuenta.
Bart van Ingen Schenau
Correcto, puede tomar la decisión de los límites de equilibrio tan complejos como desee y aún así no tiene que hacer cambios en el cliente. Si lleva esto más allá con las partes REST como el tipo de contenido, puede mostrar diferentes vistas. Por ejemplo, una cuenta se ve diferente de una transacción. También es interesante el código bajo demanda (aunque no está muy implementado). Eso podría usarse, por ejemplo, para un estimador de préstamos. Puede proporcionar a la interfaz una función de calculadora simple, por lo que el cliente solo necesita implementar las entradas para el cálculo. Se mantendrá actualizado desde el back-end.
Luc Franken
2
Pero, por lo general, el cliente necesita saber POR QUÉ no se puede retirar, por lo que aún debemos enviar un ENUM o una Cadena en un campo separado al cliente con reason. Y si todavía necesitamos esto, ¿por qué no simplemente enviarle otro campo booleano en canWithdrawlugar de un enlace a la acción? Otra ventaja es la capacidad de cambiar la URL de una acción sin tocar al cliente. Pero ... ¿qué razón para cambiar la URL? En la mayoría de los casos, también hay algún cambio en la semántica o en los parámetros o en la forma de solicitud / respuesta, etc. Por lo tanto, de todos modos necesitamos cambiar el cliente. Entonces, todavía no lo entiendo, ¿qué sentido tiene HATEOAS?
Ruslan Stelmachenko