Aprende, practica, repite.

Hace días estuve hablando con unos compañeros de trabajo sobre el impacto que podría tener un mal diseño de un API. Pero, ¿cómo podríamos saber si un servicio web no cumple con un diseño adecuado? Pues sería necesario conocer alguna arquitectura de diseño e implementación para APIs. En este caso hablaremos de una de las más populares desde sus inicios: REST.

Primero lo primero

Comencemos hablando de una palabra muy utilizada por los desarrolladores: REST. ¿Qué es esto? pues de una manera simple, es un acrónimo de Representational State Transfer, un estilo de arquitectura basado en un conjunto de principios predefinidos que describen cómo se definen y se abordan los recursos a través de un servicio web.

Un servicio web que implementa los principios REST se denomina RESTful. Es común que tenga identificadores de recursos únicos (URIs) limpios y legibles, o que devuelvan la información en formato JSON o XML. Pero el hecho de que el servicio haga un buen uso de las URIs y que devuelva la información en formato determinado no necesariamente lo hace RESTful. Echemos un vistazo a un escenario típico que involucra un servicio web para administrar un perfil de usuario. Aquí hay algunos endpoints para realizar operaciones básicas de creación, lectura, actualización y eliminación (CRUD) en un perfil, que devuelven los resultados en formato XML:

Estos endpoints no lucen mal ¿cierto?. Los primeros dos /getAllProfile y /getProfile?id=2, obtienen todos los perfiles y un perfil específico con el número 2 como id. El siguiente endpoint /createProfile es responsable de crear un nuevo perfil y, como ya habrás adivinado, los dos últimos, /deleteProfile?id=4 y /updateProfile?name=Edgar, eliminan y actualizan un perfil específico.

Después de algún tiempo en producción, la empresa solicitó que se agregaran algunas funciones más, como por ejemplo un endpoint capaz de recuperar información adicional de amigos, así como la capacidad de buscar perfiles por nombre. Normalmente, los desarrolladores tienden a implementar estas capacidades de manera rápida y sucia al agregar dos endpoints más a la colección, lo que da como resultado que la versión 2 del servicio tenga el siguiente aspecto:

Estos endpoints adicionales pueden cumplir con los requerimientos solicitados, pero comienzan a hacer que el código sea muy redundante al devolver el mismo tipo de información con aspectos ligeramente diferentes.

Para la versión 3 del servicio web, se solicita además que admita las respuestas en formato JSON en algunas de las funciones actuales para que sea "RESTful". Manteniendo la coherencia de las convenciones de nombres y para evitar cambios de ruptura, los desarrolladores pueden simplemente agregar más endpoints a la colección:

Como puedes ver, simplemente agregando soporte para un formato adicional, básicamente puedes multiplicar las operaciones de lectura. Seguir adelante con este patrón sería una receta para el desastre, imagínate cuál sería el impacto si la empresa nos hace otras solicitudes.

En el escenario del ejemplo anterior, los servicios web tendían a inclinarse más al estilo RPC (Remote Procedure Call) en lugar de RESTful. Tener un servicio web de estilo RPC no está mal, pero es importante no confundir las características de REST y RPC. En un mundo RPC, los endpoints son meras funciones que se activan de forma remota, mientras que en un mundo REST, los endpoints son entidades, también conocidas como recursos. Diseñar una API de forma adecuada es difícil porque los requisitos tienden a cambiar y debemos adaptarnos a los requerimientos del día a día. La implementación de patrones como REST mejorará la experiencia de nuestros servicios web al hacerlo menos redundantes, más escalable y más fácil de mantener. Bien, ¿y cuáles son esas reglas que debemos seguir entonces para crear excelentes servicios webs? Es aquí donde entran en juego los principios REST.

Principios de REST

Algunas de las preocupaciones más importantes que afecta una arquitectura REST son: el rendimiento, la escalabilidad, la simplicidad, la portabilidad de los componentes y la confiabilidad. Estas y otras más propiedades están encapsuladas por seis principios que guían el diseño de un sistema RESTful.

El primer principio es el de cliente-servidor: impone la separación adecuada de las preocupaciones entre el front-end y el back-end, que en su mayoría contiene las implementaciones de lógica de negocios y almacenamiento de datos. El segundo principio es el sistema de capas: dicta que las capas deben organizarse jerárquicamente, restringiendo el uso de un servicio a las capas por debajo y encima de él. La orquestación de componentes en capas mejora drásticamente la reutilización, haciéndolos más modulares y escalables.

Tercer principio sin estado: describe que una solicitud debe contener toda la información necesaria para que el servidor entienda y cree el contexto.

La característica clave que asocia un sistema con REST es una interfaz uniforme. Este es el cuarto principio y consta de cuatro partes esenciales, que son la identificación de recursos, la manipulación de recursos, las respuestas de autodescripción y la administración del estado. Estos elementos arquitectónicos se implementan directamente a través de URI, verbos HTTP, media types y HATEOAS.

El principio de caché es el quinto y se deriva del principio sin estado y requiere que las respuestas provenientes del servidor se etiqueten explícitamente como cacheables o no cacheables, independientemente de si se definen explícita o implícitamente. Las respuestas que se almacenan en la memoria caché permiten a los clientes reutilizarlos más adelante cuando realizan solicitudes similares, lo que mejora la velocidad y la latencia.

El principio final y opcional es Código en demanda, que permite a un cliente acceder a recursos específicos desde el servidor sin saber cómo procesarlos.

Entonces, siguiendo estos principios es como podemos dar como resultado un servicio web RESTful.