Cuando el conocimiento crece, la oportunidad aparece.

Hace días estuve hablando con unos compañeros sobre el impacto que podría tener un mal diseño de un API. De dicha conversación surgió la pregunta de ¿cómo podríamos saber si un servicio web no cumple con un diseño adecuado?. Pues para responder esta incognita 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

Empecemos hablando de esta palabrita 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, y que devuelvan la información en formato JSON o XML. Sin embargo, el hecho de que el servicio web haga un buen uso de las URIs y devuelva la información en un formato determinado no necesariamente lo hace RESTful.

Para entender esto mejor, echemos un vistazo a un escenario típico que involucra un servicio web para administrar un perfil de usuario:

HTTP GET: 
    /api/getAllProfiles
    /api/getProfile?id=2
    
HTTP POST:
    /api/createProfile
    
HTTP PATCH
    /api/updateProfile?name=Jeffrey
    
HTTP DELETE
    /api/removeProfile?id=4

Aquí hay algunos endpoints para realizar operaciones básicas de creación, lectura, modificación y eliminación (CRUD) de datos en un perfil, que devuelven los resultados en formato XML. Estos endpoints no lucen mal ¿cierto?. Los primeros dos /api/getAllProfile y /api/getProfile?id=2, obtienen todos los perfiles y un perfil específico con el número 2 como id. El siguiente endpoint /api/createProfile es responsable de crear un nuevo perfil y, como ya habrás adivinado, los dos últimos, /api/deleteProfile?id=4 y /api/updateProfile?name=Jeffrey, eliminan y actualizan un perfil específico.

Después de algún tiempo con este servicio web en producción, la empresa que mantiene ha solicitado agregar algunas nuevas funciones, 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 funcionalidades de manera rápida y sucia al agregar dos endpoints más, lo que da como resultado que la siguinte versión del servicio web tenga el siguiente aspecto:

HTTP GET: 
    /api/getAllProfiles
    /api/getProfile?id=2
    /api/getProfileByName?name=Alexis
    /api/getProfileFriends?id=2
    
HTTP POST:
    /api/createProfile
    
HTTP PATCH
    /api/updateProfile?name=Jeffrey
    
HTTP DELETE
    /api/removeProfile?id=4

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 próxima versión del servicio web, la empresa solicita además que se admitan las respuestas en formato JSON en algunos de los endpoints 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 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.

Te has suscrito correctamente a Refactoring Blog
¡Bienvenido! Has iniciado sesión correctamente.
¡Bien! Te has registrado correctamente.
¡Éxito! Su correo electrónico se actualiza.
Tu enlace ha caducado
¡Éxito! Revisa tu correo electrónico en busca de un enlace mágico para iniciar sesión.