3 consejos para diseñar APIs
Tags: webdev, programming, beginners, tutorial
Published: 2022-06-09 08:46:38

 > _OJOCUIDAO: Lo escrito a continuaicón es simplemente mi opinión en base a mi experiencia. Si te parece que estoy diciendo una burrada te agradezco que me lo comentes_

## Utiliza enums en lugar de valores booleanos.

Imaginemos que trabajamos en una empresa de tarjetas. Imaginemos que estamos diseñando un endpoint GET /cards/id que te devuelve los datos de una tarjeta de crédito. 

A grandes rasgos estos datos son el nombre del propietario, el número de tarjeta, la fecha de caducidad, el código de seguridad, el saldo y el estado de la tarjeta. (Activada o desactivada)

Con esta definición, mucha gente tenderá a representar este concepto de la siguiente forma (El número de tarjeta se llama PAN):

```js
{
      name: string,
      pan: number; 
      exp_year: number;
      exp_month: number;
      is_active: boolean; 
}
```

en principio, parece que tiene sentido pero imaginemos que añadimos una nueva característica a nuestro sistema y ahora permitimos que una tarjeta pueda estar "inactiva, activa y también congelada" 

🔥🔥🔥🔥🔥

El diseño anterior utiliza un valor booleano para el estado `is_active` por lo que para representar si está congelada tendríamos que añadir otro valor booleano `is_frozen`

```js
{
      name: string,
      pan: number;
      exp_year: number;
      exp_month: number;
      is_active: boolean;
      is_frozen: boolean;
}
```

Esto nos deja con 4 posibles combinaciones:

| is_active | is_frozen |
|-----------|-----------|
| no        | no        |
| no        | yes       |
| yes       | no        |
| yes       | yes       |

lo malo es que desde el punto de vista del producto algunas de estas combinaciones pueden no tener sentido. Por ejemplo si esta congelada, da igual si esta activada o no.

y que pasa si queremos representar que está bloqueada por fraude?

```js
{
      name: string,
      pan: number;
      exp_year: number;
      exp_month: number;
      is_active: boolean;
      is_frozen: boolean;
      is_blocked: boolean;
}
```

Poco a poco nuestro diseño se va complicando y empezamos a tener más y más combinaciones de valores booleanos.

Si alguien quiere hacer una aplicación y dibujar la tarjeta representando el estado correcto tendrá que hacer una serie de comprobaciones en esos campos para conseguir la representación adecuada.

Ahora veamos qué pasaría si utilizamos un enum (un string con una serie de valores posibles) para representar este estado:

```js
{
	name: string,
	pan: number; // El número de tarjeta se llama PAN
	exp_year: number;
	exp_month: number;
	status: 'active' | 'inactive';
}
```

Después de añadir el requisito de poder congelar la tarjeta:

```js
{
	name: string,
	pan: number; // El número de tarjeta se llama PAN
	exp_year: number;
	exp_month: number;
	status: 'active' | 'inactive' | 'frozen';
}
```

Después de añadir el requisito de bloquear tarjetas por fraude:

```js
{
	name: string,
	pan: number; // El número de tarjeta se llama PAN
	exp_year: number;
	exp_month: number;
	status: 'active' | 'inactive' | 'frozen' | 'blocked';
}
```

Por esto creo que un enum es mucho más flexible que un campo booleano y al contrario de estos permite extender la API sin hacer breaking changes.  Mi recomendación: **Cada vez que vayas a representar algo utilizando un boolean, reemplázalo con un enum con 2 valores. Lo agradecerás en el futuro.**

## Usa objetos en lugar de valores.

Otro consejo que se me ocurre dar es que las respuestas de una API deben ser diseñadas teniendo en cuenta futuros cambios.

Una forma sencilla de hacer nuestras APIs más resistentes a cambios es utilizar objetos para representar conceptos.

Por ejemplo si junto a una tarjeta queremos devolver una lista con los identificadores de las últimas 5 transacciones mucha gente optará por un array de strings.


```ts
{
  name: string,
  pan: number; // El número de tarjeta se llama PAN
  exp_year: number;
  exp_month: number;
  status: 'active' | 'inactive' | 'frozen' | 'blocked';
  // Transaction contiene un array de IDs
  transactions: [ 
          '0000-0000',
          '0000-0001',
          '0000-0002',
  ]
}
```

Ahora imaginemos que nos piden añadir el valor de cada transacción... No podemos hacerlo fácilmente sin romper el contrato de la API!

Sin embargo si desde el principio las transacciones fuesen objetos con un atributo ID 

```ts
{
  name: string,
  pan: number; // El número de tarjeta se llama PAN
  exp_year: number;
  exp_month: number;
  status: 'active' | 'inactive' | 'frozen' | 'blocked';
  // Transaction contiene un array de IDs
  transactions: [ 
          {id: '0000-0000'},
          {id: '0000-0001'},
          {id: '0000-0002'},
  ]
}
```

Es trivial extenderlos con tantos campos como necesitemos:

```ts
transactions: [
  { id: "0000-0000", amount: 1000 },
  { id: "0000-0001", amount: 2000 },
  { id: "0000-0002", amount: 3000 },
];
```

## Consulta Schema.org

La gente de Schema.org se ha preocupado de investigar y definir nombres estándar para representar conceptos en internet.

Por ejemplo para [representar una Persona](https://schema.org/Person)