
Para mi la arquitectura REST ha pasado a convertirse en mi navaja Suiza particular. La puedes encajar en casi cualquier proyecto. Y si no encaja del todo, siempre puedes olvidarte de todas las restricciones arquitectónicas que definen REST y adoptar aquellas que son útiles para tu caso concreto. Antes de continuar, creo que es interesante entender que es una arquitectura tecnológica y que es una arquitectura REST.
¿Que es una arquitectura tecnológica?
Cuando se construye una solución tecnológica, esta requiere de diversos componentes, tantos software como hardware. Dependiendo del tamaño de la solución puede resultar complejo especificarla, diseñarla o simplemente plasmarla para que pueda ser comunicada al resto del equipo. Por eso, los sistemas complejos se descomponen en piezas más pequeñas y manejables y se restringen o estructuran con unos marcos normativos.
Así, en fontanería se trabaja con una serie de diámetros de tubería estándar, cada uno con su propósito y función. En informática se establecen estándares dentro de los equipos de trabajo para limitar las opciones y que el mismo tipo de problemas se resuelva de la misma manera. Una vez sabemos resolver un problema, no volvemos a perder tiempo. Cada vez que encontramos el mismo patrón, aplicamos la misma solución. Este marco normativo es lo que define una arquitectura.
¿Que es una arquitectura REST?
Una arquitectura REST se fundamenta en 6 normas o restricciones de las cuales una es opcional:
Cliente/Servidor
REST es una arquitectura cliente/servidor. Promueve la separación en dos componentes: la lógica de negocio (servidor o backend) y la lógica de presentación (cliente). Esto permite que la capa de presentación, las vistas o pantallas, puedan modificarse independientemente de la lógica de negocio. El resultado es que los costes de mantenimiento del sistema son menores ya que cuando necesito evolucionar o corregir el sistema puedo hacerlo por partes.
Pero con toda ventaja, vienen los inconvenientes. El hecho de mantener separadas la capa de presentación de la lógica de negocio añade un retraso o latencia en las comunicaciones entre los dos componentes. Claro que, dado el nivel de evolución de las redes de comunicación actuales, esta latencia no es un problema en la mayoría de los casos. De hecho, todas las aplicaciones web son cliente/servidor y también la mayoría de las apps para móviles y tablets.
Sin estado
Cuando accedes a una aplicación y haces login con tus credenciales de usuario y contraseña, la aplicación ya no te vuelve a pedir la credenciales. En estos casos, el servidor crea una estructura en memoria, la sesión, donde identifica que tu usuario esta conectado a la aplicación y que ya ha verificado quién eres. Todas las demás llamadas desde el cliente al servidor llevan un identificador de sesión (habitualmente almacenado en una cookie en las aplicaciones web) que permite al servidor acordarse de quién eres y saber que hace un rato ha verificado quién eras y te ha autorizado en el sistema. La aplicación mantiene el estado de la sesión de cada usuario, un contexto de que ha pasado hasta ahora durante la sesión.
REST es una arquitectura sin estado. El servidor, al no mantener ningún tipo de contexto acerca de que ha pasado hasta ahora con cada sesión de usuario conectado a través de un cliente, necesita que el cliente le provea ese contexto en cada llamada. Esto supone que cada llamada debe acarrear información adicional que con una arquitectura con estado no es necesario. ¿Dónde está la ventaja?. La ventaja está en la simplicidad del componente servidor y lo fácil que resulta escalar y hacer crecer el sistema.
Para hacer crecer un sistema cuando crece el número de usuarios podemos instalar la aplicación en una máquina mayor (escalabilidad vertical). Si una máquina no es suficiente o necesitamos que el sistema sea resistente a fallos, hay que disponer dos máquinas, o más, con el componente servidor instalado. Delante de estas máquinas tendremos otra que actúe como balanceador de carga, es decir, que reciba todas las peticiones que llegan a nuestro dominio y las redistribuya a las máquinas del backend. Surge un problema, el balanceador debe mandar todas las peticiones de un mismo cliente al mismo servidor para mantener la afinidad de sesión. Si mandase la petición a otro servidor, este no se «acordaría» de quién es. Otra posibilidad es crear un clúster con las máquinas del backend para que compartan los objetos de sesión, de forma que el balanceador no tiene por que saber a donde enviar cada petición. Ambas soluciones son complejas y añadir máquinas nuevas requiere configuración en el clúster o dotar de cierta inteligencia al balanceador.
Con una arquitectura sin estado basta con añadir una máquina nueva y darla de alta en el balanceador de carga. Además, el balanceador de carga no necesita tener ningún tipo de inteligencia.
Cacheable
Caché en el cliente
Una arquitectura REST es con caché en el cliente, pero nada nos impide utilizar también caches en el servidor. Podemos poner cachés en el cliente o en el servidor. Poniendo cachés en el cliente, nos ahorramos realizar peticiones al servidor. Evitamos la latencia de las comunicaciones así como la necesidad de buscar la información en un mecanismo de almacenamiento. En este caso el ahorro tanto en ancho de banda como en capacidad de procesamiento es alto, pero el cliente se vuelve más complejo.
ETag
Una forma más simple y casi tan efectiva de implementar una caché en el cliente es el uso de ETags. El servidor envía cada respuesta con un hash calculado sobre la respuesta, el ETag. El cliente debe guardarse las respuestas del servidor y estos ETags. El cliente realizará todas las peticiones al servidor con el ETag correspondiente en una cabecera «If-none-match». El servidor calculará la respuesta procesando la petición y accediendo a los mecanismos de persistencia. Si el hash calculado para la nueva respuesta coincide con el enviado por el cliente, el servidor no devuelve el contenido de la respuesta al cliente, sino que le indica al cliente que la respuesta no ha cambiado desde que realizó la última petición. En este caso, tan solo ahorramos ancho de banda y reducimos la latencia en las comunicaciones.
Caché en el servidor
Aunque REST no dice nada de cachés en el servidor, no quiere decir que no podamos usarla. También podemos poner la caché en el servidor. En este caso tan sólo ahorramos capacidad de procesamiento. El cliente pedirá igualmente la información al servidor. El servidor, antes de procesar la petición, comprobará si la respuesta la tiene ya disponible en la caché. En ese caso, devolverá al cliente la respuesta sin necesidad de calcularla. Este mecanismo nos ahorra tener que calcular la respuesta.
ETag y caché en el servidor
El uso combinado de ETags y la caché en el servidor nos permite combinar sus ventajas: ahorramos ancho de banda y latencia con el uso de ETags y capacidad de procesamiento con el uso de la caché de servidor. Además centralizamos toda la lógica en el servidor simplificando el cliente.
Interfaz uniforme
Una arquitectura REST expone a los clientes una interfaz uniforme desde el servidor.
- Todos los recursos del servidor tienen un nombre en forma de URL o hipervínculo
- Toda la información se intercambia a través del protocolo HTTP
Si diseñamos bien nuestras URLs y sobrecargamos de forma correcta el protocolo HTTP, todo ello de forma coherente, será muy sencillo para el desarrollador entender cómo interactuar con nuestro API. El interfaz uniforme, a falta de herramientas de soporte, es la pieza angular sobre la que reside la experiencia del desarrollador (Developer UX).
Hipermedia como el motor del estado de la aplicación (HATEOAS)
Lo creamos o no, un API web funciona de forma muy similar a una aplicación Web. Al fin y al cabo, la arquitectura REST se pensó como una forma de reutilizar el protocolo HTTP y la arquitectura de internet para desarrollar todo tipo de aplicaciones distribuidas. En este sentido, una aplicación Web recibe peticiones y devuelve páginas HTML, y un API recibe peticiones y devuelve representaciones en cualquier formato.
Cuando interactúas con una aplicación Web, no se te ocurre ponerte a adivinar URLs de la aplicación y a escribirlas en la barra de direcciones de tu navegador. Con cada página de respuesta, la aplicación Web incluye botones y enlaces en la forma de hipervínculos que te permiten realizar nuevas acciones dentro de la aplicación Web. No tienes que saber de antemano como moverte a través de ella. Según navegas, te presenta las opciones que tienen sentido.
HATEOAS aplica este principio a los APIs. Se trata de que el API sea navegable y que cada petición presente enlaces a otros recursos relacionados o a otras acciones. De esta forma el API se vuelve navegable y descubrible. A la vez, se introduce un nivel de indirección entre el cliente y el servidor a través de los hipervínculos, lo que reduce el acoplamiento entre ambos y por tanto mejora la mantenibilidad del API.
Código bajo demanda
Este es el único requisito de los 6 que es opcional. El código bajo demanda es la posibilidad de enriquecer el cliente con código ejecutable capaz de interpretar las respuestas del API e interactuar con este. Pensemos en JavaScript y las aplicaciones Web. Cualquier aplicación web que utilice JavaScript está utilizando el patrón de código bajo demanda. El JavaScript se descarga desde el servidor junto con el HTML (la representación) y sirve tanto para enriquecer la representación como para interactuar con el servidor (peticiones AJAX).
Conclusiones
Echando un vistazo a los patrones que componen REST, podemos ver que a pesar de los inconvenientes que tiene algún patrón, como la carencia de estado, que es la que mayor impacto tiene en cuanto a latencia y ancho de banda, estos son de sobra superados por las ventajas:
- REST es modular y autocontenida
- La arquitectura por capas permite reducir el acoplamiento entre componentes y flexibiliza la estructura de la aplicación
- Es la arquitectura cliente/servidor más polivalente
- Utiliza el protocolo más extendido en internet, lo que lo hace ideal para aplicaciones abiertas a la red
- Permite integrar con cualquier otra plataforma y tecnología
- Cualquier problema de latencia o ancho de banda se ve mitigado por el uso de cachés
En definitiva, para nosotros es una navaja suiza con la que abordar multitud de proyectos donde la arquitectura cliente servidor es la adecuada y es necesario que el sistema a construir interactúe con otros.
¿Cuales son tus razones para usar REST?