# Diseño de APIs

Muchas veces nos encontramos con la necesidad de diagramar una API (Application Program Interface) en casi cualquier etapa de los proyectos. Puede darse que esto sea un requerimiento funcional primario del dominio a la hora de realizar el primer relevamiento o que sea una necesidad que surja en etapas avanzadas del proyecto, pero cualquiera que sea el caso, es necesario evaluar algunos aspectos esenciales a la hora de comenzar a programar. El objetivo de este documento es analizar estos aspectos e intentar sacarles el mayor provecho.

## Application Program Interfaces: Análisis conceptual y usos

Una API, como su nombre lo indica, es **una interfaz con la que cuenta un sistema para comunicarse con entes externos.** Todos los sistemas cuentan con una API para poder interactuar con el mundo exterior, de esta forma, otros sistemas pueden hacer uso de las funcionalidades que aportan sistemas más pequeños, y así componerse para formar entes cada vez más grandes. Lo interesante es que **no necesitamos conocer el funcionamiento interno del sistema con el que nos comunicamos para poder utilizarlo**, por lo que tan solo debemos cumplir con el *contrato* que se nos presenta para poder comunicarnos. De esta idea de mantener el comportamiento interno de los sistemas *"oculto"* a los entes externos nace el concepto de **encapsulamiento**.

Tomemos como ejemplo el caso de una máquina expendedora de bebidas. La interfaz que esta nos publica es mínima, ingresar dinero y elegir bebida. Todo el resto del trabajo lo realiza la máquina, y no conocemos qué sucede internamente para que la bebida llegue a nuestras manos. Nosotros tan solo *confiamos* en la interfaz que esta nos propone.

## Diseñando nuestra API

*¡Un momento cerebrito! Estoy programando en Ruby, ¿Para qué me va a servir hablar de máquinas expendedoras?* Bueno, lo interesante de pensar en interfaces de sistemas es que **no estamos atados a una tecnología o circunstancia particular**. Aunque muchas veces generalizamos el término API al caso de *"interacción con una página web"*, la realidad es que todos los sistemas nos presentan una interfaz para poder funcionar. Por ejemplo, en el caso del módulo `ActiveRecord`de Rails, debemos interactuar con la interfaz del mismo y realizar un `:save` a una instancia de `ActiveRecord::Base` para poder sincronizar los valores de nuestro objeto con la base de datos. Asi también, nosotros podemos pensar una API para nuestra aplicación web y publicarla con una herramienta como `Grape`. *¿Y cómo hay que hacer?*

### Estructura general

Lo primero que tenemos que tener en cuenta a la hora de diseñar una interfaz es **la importancia de mantener la modularización de nuestro sistema.** Supongamos que contamos con una plataforma de e-commerce y se suma el requerimiento de lanzar una aplicación mobile. Para ello, decidimos armar una API REST que trabaje sobre JSON para comunicarnos con la web. Fácilmente podría ocurrírsenos incorporar un endpoint para que nuestros usuarios realicen compras:

`POST - http://mywebpage.com/api/users/:id/buy`

Esto no representaría en primera instancia ningún problema para comunicarnos, pero conceptualmente podemos encontrar 3 problemas:

* No estamos respetando el protocolo HTTP y rompemos REST.
* Rompemos el encapsulamiento.
* No estamos manteniendo la modularización.

El primer caso es bastante obvio: HTTP es un protocolo que básicamente se compone de *una combinación de una acción y un recurso sobre el que se realiza esa acción para cada request*. Las acciones realizables son siempre las mismas: `GET`, `POST`, `PUT`, `DELETE` (hay otras, pero en general vamos a trabajar con estas), es decir que **nuestra ruta debe representar el recurso sobre el que se realizan las acciones**. En este caso, nuestra ruta nos indica únicamente que estamos comprando algo, pero claramente no está referenciando un recurso dentro de nuestro sistema. Una solución sencilla, por ejemplo, podría ser modificar la ruta para que indique la creación de órdenes de compra:

`POST - http://mywebpage.com/api/users/:id/order`

Lo interesante de esto es que ahora contamos con una ruta que debería llamarnos la atención: Sabemos que POST representa la creación de un recurso, pero... **¿Es responsabilidad de los usuarios la creación de las órdenes?** *Bueno, bancá un poquito, si te quedaste con ganas de saber algo más de REST, podés chusmear* [*acá*](https://es.wikipedia.org/wiki/Representational_State_Transfer) *o* [*también acá*](http://lmgtfy.com/?q=REST)*.*

Ahora si, nos hacía ruido el hecho de que un usuario era el encargado de crear las órdenes de compra. *Pues claro hombre!* **Estamos rompiendo el encapsulamiento.** Conocemos que **cada entidad tiene la responsabilidad de saber cómo trabajar consigo misma, y no debe depender de entidades externas para poder funcionar, sino que únicamente debe recibir estímulos externos.** Esto implica que nuestras órdenes *deberían saber como crearse a si mismas*.

En general, solemos estar tentados a mantener en nuestras APIs las relaciones que manejamos en nuestras aplicaciones. Por ejemplo, podríamos consultar las órdenes de compra de un usuario mediante `GET - http://mywebpage.com/api/users/:id/orders`, pero la realidad es que nuestro recurso a consultar *poco tiene que interactuar con el usuario, más que manteniendo una referencia al mismo*. Lo que estamos haciendo aca es destruir la modularización del sistema, y desparramar el acceso a las órdenes definiendo responsabilidades inexistentes.

Para ver de forma más clara el problema, supongamos ahora que se nos pide obtener un histórico de compras para un país en particular. *¿Armamos una ruta que sea:* `GET - http://mywebpage.com/api/country/:id/orders`*? O aún peor, ¿Vamos a pedir todas las órdenes de todos los usuarios y filtrarlos de forma local?*. La realidad es que se nos complica muchísimo encontrar un sistema que se acomode a nuestra dependencia inicial de pasar por los usuarios, **y esto sucede porque nuestro sistema no se encuentra modularizado**.

Una buena solución a esto es **la extracción de las órdenes de compra como un módulo aparte**. Es decir:

`GET - http://mywebpage.com/api/orders`

Y fácilmente podríamos pasarle como parámetro distintos *filtros*, como `user_id`, o `country`. Un dato a tener en cuenta: **¡Este mismo tipo de análisis estructural debemos formular sobre los controllers de Rails!** Es decir, *programemos teniendo en cuenta que nuestro sistema muy probablemente publique una interfaz que no sea unicamente la de Rails.*

### Extensibilidad de una API

En el ejemplo anterior, mientras nos ocupábamos de una buena división de responsabilidades, nos olvidamos de un dato importante: **Muy probablmeente vamos a querer mucha menos información sobre una orden al obtener un histórico de un país que al entrar al perfil de un usuario.** Por ejemplo, en el caso de los países, muy probablemente queramos saber la fecha de la orden, qué items fueron comprados, *y no mucho más*. Pero en el caso del menú del usuario, seguramente buscaremos información sobre costos, métodos de pagos y otros.

Una solución interesante seria pensar el sistema en función al endpoint que teníamos anteriormente, y que nuestra API devuelva una versión `full` de las órdenes en caso que se filtre vía usuarios, y una versión `standard` en caso contrario, con menos información.

Pero pensemos qué sucedería si nos piden ahora que agreguemos un nuevo método de consulta en el que necesitemos un poquito más de información. Cada vez tenemos un endpoint más grande y con más comportamiento... **¡Estamos llenando de responsabilidades un solo endpoint!** Y eso está muy mal desde casi cualquier punto de vista: Tenemos un [*God Endpoint*](http://stackoverflow.com/questions/8018889/categories-or-partial-classes-pattern-to-resolve-god-object-code-smell), que nos indica una mala división de responsabilidades un mal delegamiento, con potencial codigo spaghetti, con mucha repetición o semi imperativo, junto con *(vaya uno a saber)* cuantos otros [Code Smells](https://sourcemaking.com/antipatterns), y probablmeente tambén rompemos un poquito con REST, cuando nos habla del concepto de *single actions*. *Es como si la máquina expendedora de hace un rato devuelva las bebidas en lata, pero si le das una moneda de $1, venga en botella de 2L.*

Ahora, esto lo podemos resumir en que **debemos tener bien definido cuál va a ser la respuesta de nuestro endpoint y esta no debe depender del contexto**. Básicamente, **las interfaces de los sistemas son fuertemente tipadas**.

*¿Y ahora qué hacemos?* Bueno, primero charlemos de lo que **no** hacemos: *Muchos endpoints*. No es casualidad que nuestra ruta con un parámetro que nos indica el tipo de respuesta nos haya sonado mejor en un principio, y eso pasa porque **hacer gran cantidad de endpoints es claramente inmantenible**.

En este caso, entonces, lo ideal es aprovechar las bondades de REST y pensar en, un sistema que nos permita realizar consultas genéricas de órdenes de compras y luego obtener información particular a demanda:

* `GET - http://mywebpage.com/api/orders` - Para obtener la información general de las órdens a consultar.
* `GET - http://mywebpage.com/api/orders/:id/` - Para obtener informacion sbre una ordenen particular.

Este método nos ayuda bastante a dividir responsabilidades y a hacer un poco mas permeable al cambio a nuestra aplicación, pero también deja en evidencia un problema del protocolo REST: **Vamos a requerir de una gran cantidad de requests para poder obtener información completa sobre varias órdenes**. Formas de solucionar estos problemas exceden el alcance de este documento, pero es importante tener definido *qué y cuáles son los datos que vamos a publicar en un endpoint*.

### Versionado

**Las APIs no cambian -o lo hacen lo menos posible-.** Cuando una interfaz es publicada para el uso externo **se debe minimizar y en lo posible nulificar el cambio de la misma.** En el caso que sea necesario agregar modificaciones a la misma, lo que se debe hacer es cambiar y publicar una nueva versión de la misma.

Además, debemos tener una buena política de retrocompatibilidad y en lo posible, seguir manteniendo las interfaces anteriores, ya que otros sistemas podrían estar utilizándolas.
