Las API son una forma estupenda de que las aplicaciones de software se comuniquen entre sí. Permiten que las aplicaciones de software interactúen y compartan recursos o privilegios.

Hoy en día, muchas empresas B2B ofrecen sus servicios a través de APIs que pueden ser consumidas por apps hechas en cualquier lenguaje de programación y framework. Sin embargo, esto las hace vulnerables a los ataques DoS y DDoS, y también puede provocar una distribución desigual del ancho de banda entre los usuarios. Para hacer frente a estos problemas, se aplica una técnica conocida como limitación de la tasa de la API. La idea es sencilla — limitas el número de peticiones que los usuarios pueden hacer a tu API.

En esta guía, aprenderás qué es la limitación de la tasa de la API, las múltiples formas en que puede implementarse y algunas prácticas recomendadas y ejemplos que debes recordar al configurar los límites de la tasa de la API.

¿Qué es la Limitación de la Tasa de la API?

En palabras sencillas, la limitación de la tasa de API consiste en establecer un umbral o límite sobre el número de veces que los usuarios pueden acceder a una API. Los límites pueden decidirse de múltiples maneras.

1. Límites Basados en el Usuario

Una de las formas de establecer un límite de tasa es reducir el número de veces que un usuario concreto puede acceder a la API en un plazo determinado. Esto se puede conseguir contando el número de solicitudes realizadas utilizando la misma clave API o dirección IP, y cuando se alcanza un umbral, se limitan o deniegan más solicitudes.

2. Límites Basados en la Ubicación

En muchos casos, los desarrolladores quieren distribuir equitativamente el ancho de banda disponible para su API entre determinadas ubicaciones geográficas.

El reciente servicio de la versión preliminar de ChatGPT es un buen ejemplo de limitación de tasa basada en la ubicación, ya que empezaron a limitar las solicitudes en función de la ubicación de los usuarios en la versión gratuita del servicio una vez que se lanzó la versión de pago. Tenía sentido, ya que se suponía que la versión preliminar gratuita iba a ser utilizada por personas de todo el mundo para generar una buena muestra de datos de uso del servicio.

3. Límites Basados en el Servidor

La limitación de tarifa basada en el servidor es un límite de tarifa interno implementado en el lado del servidor para garantizar una distribución equitativa de los recursos del servidor, como CPU, memoria, espacio en disco, etc. Se realiza implementando un límite en cada servidor de un despliegue.

Cuando un servidor alcanza su límite, las demás solicitudes entrantes se dirigen a otro servidor con capacidad disponible. Si todos los servidores han alcanzado su capacidad, el usuario recibe una respuesta 429 Too Many Request. Es importante señalar que los límites de tasa basados en el servidor se aplican a todos los clientes, independientemente de su ubicación geográfica, hora de acceso u otros factores.

Tipos de Límites de la Tasa API

Aparte de la naturaleza de la aplicación de los límites de tasas, también se pueden clasificar los límites de tasas en función de su efecto sobre el usuario final. Algunos tipos comunes son:

  • Límites duros: Son límites estrictos que, cuando se sobrepasan, restringen completamente el acceso del usuario al recurso hasta que se levanta el límite.
  • Límites blandos: Son límites flexibles que, cuando se sobrepasan, pueden permitir al usuario acceder al recurso unas cuantas veces más (o acelerar las solicitudes) antes de cerrar el acceso.
  • Límites dinámicos: Estos límites dependen de múltiples factores, como la carga del servidor, el tráfico de la red, la ubicación del usuario, la actividad del usuario, la distribución del tráfico, etc., y se modifican en tiempo real para un funcionamiento eficaz del recurso.
  • Limitación de la tasa de solicitudes: Estos límites no cortan el acceso al recurso, sino que ralentizan o ponen en cola las solicitudes entrantes hasta que se levanta el límite.
  • Límites facturables: Estos límites no restringen el acceso ni regulan la tasa, sino que cobran al usuario por las solicitudes posteriores cuando se supera el umbral de gratuidad establecido.

¿Por Qué Es Necesaria la Limitación de la Tasa?

Hay múltiples razones por las que necesitarías implementar la limitación de tasa en tus APIs web. Algunas de las principales razones son:

1. Proteger el Acceso a los Recursos

La primera razón por la que deberías considerar la implementación de un límite de tasa de la API en tu aplicación es para proteger tus recursos de la sobre explotación por parte de usuarios con intenciones maliciosas. Los atacantes pueden utilizar técnicas como los ataques DDoS para acaparar el acceso a tus recursos e impedir que tu aplicación funcione normalmente para otros usuarios. Disponer de un límite de tasa garantiza que no estás facilitando a los atacantes la interrupción de tus API.

2. Repartir la Cuota Entre los Usuarios

Además de proteger tus recursos, el límite de tasa te permite dividir los recursos de tu API entre los usuarios. Esto significa que puedes crear modelos de precios escalonados y atender las necesidades dinámicas de tus clientes sin dejar que afecten a otros clientes.

3. Mejorar la Rentabilidad

La limitación de tasas también equivale a la limitación de costes. Esto significa que puedes hacer una distribución inteligente de tus recursos entre tus usuarios. Con una estructura particionada, es más fácil estimar el coste necesario para el mantenimiento del sistema. Los picos pueden gestionarse de forma inteligente mediante el aprovisionamiento o liberación de la cantidad adecuada de recursos.

4. Gestionar el Flujo entre Workers

Muchas APIs se basan en una arquitectura distribuida que utiliza múltiples workers/hilos/instancias para gestionar las peticiones entrantes. En una estructura de este tipo, puedes utilizar límites de tasa para controlar la carga de trabajo que se pasa a cada nodo worker. Esto puede ayudarte a garantizar que los nodos workers reciben cargas de trabajo equitativas y sostenibles. Puede añadir o eliminar workers cuando sea necesario sin necesidad de reestructurar toda la pasarela API.

Entendiendo los límites de Burst

Otra forma habitual de controlar el uso de la API es establecer un límite burst (también conocido como regulación) en lugar de un límite de tasa. Los límites burst son límites de tasa implementados para un intervalo de tiempo muy pequeño, digamos unos segundos. Por ejemplo, en lugar de establecer un límite de 1,3 millones de solicitudes al mes, podrías establecer un límite de 5 solicitudes por segundo. Aunque esto equivale al mismo tráfico mensual, garantiza que tus clientes no sobrecarguen tus servidores enviando bursts de miles de peticiones a la vez.

En el caso de los límites burst, las solicitudes suelen retrasarse hasta el siguiente intervalo en lugar de denegarse. También suele recomendarse utilizar conjuntamente los límites de tasa y burst para un control óptimo del tráfico y del uso.

3 Métodos de Aplicación del Límite de Tasa

En cuanto a la implementación, hay algunos métodos que puedes utilizar para configurar la limitación de tasa de la API en tu aplicación. Entre ellos están:

1. Colas de Peticiones

Uno de los métodos prácticos más sencillos para restringir el acceso a la API son las colas de peticiones. Las colas de peticiones se refieren a un mecanismo en el que las solicitudes entrantes se almacenan en forma de cola y se procesan una tras otra hasta un cierto límite.

Un caso de uso común de las colas de peticiones es segregar las peticiones entrantes de usuarios gratuitos y de pago. A continuación te explicamos cómo puedes hacerlo en una aplicación Express utilizando el paquete express-queue:

const express = require('express')
const expressQueue = require('express-queue');

const app = express()

const freeRequestsQueue = expressQueue({
    activeLimit: 1, // Maximum requests to process at once
    queuedLimit: -1 // Maximum requests allowed in queue (-1 means unlimited)
});

const paidRequestsQueue = expressQueue({
    activeLimit: 5, // Maximum requests to process at once
    queuedLimit: -1 // Maximum requests allowed in queue (-1 means unlimited)
});

// Middleware that selects the appropriate queue handler based on the presence of an API token in the request
function queueHandlerMiddleware(req, res, next) {
    // Check if the request contains an API token
    const apiToken = req.headers['api-token'];

    if (apiToken && isValidToken(apiToken)) {
        console.log("Paid request received")
        paidRequestsQueue(req, res, next);
    } else {
        console.log("Free request received")
        freeRequestsQueue(req, res, next);
     }
}

// Add the custom middleware function to the route
app.get('/route', queueHandlerMiddleware, (req, res) => {
    res.status(200).json({ message: "Processed!" })
});

// Check here is the API token is valid or not
const isValidToken = () => {
    return true;
}

app.listen(3000);

2. Regulación (Throttling)

La regulación es otra técnica utilizada para controlar el acceso a las API. En lugar de cortar el acceso tras alcanzar un umbral, la regulación se centra en nivelar los picos de tráfico de la API aplicando umbrales pequeños para intervalos de tiempo reducidos. En lugar de establecer un límite de tasa como 3 millones de llamadas al mes, la regulación establece límites de 10 llamadas por segundo. Una vez que un cliente envía más de 10 llamadas en un segundo, las siguientes peticiones en el mismo segundo se regulan automáticamente, pero el cliente recupera instantáneamente el acceso a la API en el siguiente segundo.

Puedes implementar la regulación en Express utilizando el paquete express-throttle. Aquí tienes un ejemplo de aplicación Express que muestra cómo configurar la regulación en tu aplicación:

const express = require('express')
const throttle = require('express-throttle')

const app = express()

const throttleOptions = {
    "rate": "10/s",
    "burst": 5,
    "on_allowed": function (req, res, next, bucket) {
        res.set("X-Rate-Limit-Limit", 10);
        res.set("X-Rate-Limit-Remaining", bucket.tokens);
        next()
    },
    "on_throttled": function (req, res, next, bucket) {
        // Notify client
        res.set("X-Rate-Limit-Limit", 10);
        res.set("X-Rate-Limit-Remaining", 0);
        res.status(503).send("System overloaded, try again after a few seconds.");
    }
}

// Add the custom middleware function to the route
app.get('/route', throttle(throttleOptions), (req, res) => {
    res.status(200).json({ message: "Processed!" })
});

app.listen(3000);

Puedes probar la aplicación utilizando una herramienta de prueba de carga como AutoCannon. Puedes instalar AutoCannon ejecutando el siguiente comando en tu terminal:

npm install autocannon -g

Puedes probar la aplicación utilizando lo siguiente:

autocannon http://localhost:3000/route

La prueba utiliza 10 conexiones concurrentes que envían solicitudes a la API. Aquí tienes el resultado de la prueba:

Running 10s test @ http://localhost:3000/route

10 connections

┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬───────┐
│ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max   │
├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼───────┤
│ Latency │ 0 ms │ 0 ms │ 1 ms  │ 1 ms │ 0.04 ms │ 0.24 ms │ 17 ms │
└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴───────┘
┌───────────┬─────────┬─────────┬────────┬─────────┬────────┬─────────┬─────────┐
│ Stat      │ 1%      │ 2.5%    │ 50%    │ 97.5%   │ Avg    │ Stdev   │ Min     │
├───────────┼─────────┼─────────┼────────┼─────────┼────────┼─────────┼─────────┤
│ Req/Sec   │ 16591   │ 16591   │ 19695  │ 19903   │ 19144  │ 1044.15 │ 16587   │
├───────────┼─────────┼─────────┼────────┼─────────┼────────┼─────────┼─────────┤
│ Bytes/Sec │ 5.73 MB │ 5.73 MB │ 6.8 MB │ 6.86 MB │ 6.6 MB │ 360 kB  │ 5.72 MB │
└───────────┴─────────┴─────────┴────────┴─────────┴────────┴─────────┴─────────┘

Req/Bytes counts sampled once per second.
# of samples: 11
114 2xx responses, 210455 non 2xx responses
211k requests in 11.01s, 72.6 MB read

Dado que sólo se permitían 10 solicitudes por segundo (con un burst adicional de 5 solicitudes), la API sólo procesó con éxito 114 solicitudes, y las restantes fueron respondidas con un código de error 503 que pedía esperar algún tiempo.

3. Algoritmos de limitación de tasa

Aunque la limitación de tasa parece un concepto sencillo que puede implementarse utilizando una cola, en realidad puede implementarse de múltiples formas que ofrecen diversas ventajas. Aquí tienes algunos algoritmos populares utilizados para implementar la limitación de tasa:

Algoritmo de Ventana Fija

El algoritmo de ventana fija es uno de los algoritmos de limitación de tasa más sencillos. Limita el número de solicitudes que se pueden gestionar en un intervalo de tiempo fijo.

Estableces un número fijo de solicitudes, digamos 100, que el servidor API puede gestionar en una hora. Ahora bien, cuando llega la petición 101, el algoritmo deniega su procesamiento. Cuando se restablezca el intervalo de tiempo (es decir, en la hora siguiente), se podrán procesar otras 100 solicitudes entrantes.

Este algoritmo es fácil de aplicar y funciona bien en muchos casos en los que es necesario limitar la tasa en el servidor para controlar el ancho de banda (a diferencia de la distribución del ancho de banda entre los usuarios). Sin embargo, puede dar lugar a un tráfico/procesamiento irregular hacia los límites del intervalo de tiempo fijado. El algoritmo de ventana deslizante es una alternativa mejor en los casos en los que se necesita un procesamiento uniforme.

Algoritmo de Ventana Deslizante

El algoritmo de ventana deslizante es una variación del algoritmo de ventana fija. En lugar de utilizar intervalos de tiempo fijos predefinidos, este algoritmo utiliza una ventana de tiempo móvil para hacer un seguimiento del número de solicitudes procesadas y entrantes.

En lugar de fijarse en los intervalos de tiempo absolutos (de, digamos, 60 segundos cada uno), como de 0s a 60s, de 61s a 120s, etc., el algoritmo de ventana móvil se fija en los 60s anteriores desde que se recibe una solicitud. Supongamos que se recibe una solicitud en el segundo 82; entonces el algoritmo contará el número de solicitudes procesadas entre los 22s y los 82s (en lugar del intervalo absoluto de 60s a 120s) para determinar si esta solicitud se puede procesar o no. Esto puede evitar situaciones en las que se procese un gran número de solicitudes tanto en el segundo 59 como en el 61, sobrecargando el servidor durante un periodo muy corto.

Este algoritmo gestiona mejor el tráfico de burst, pero puede ser más difícil de implementar y mantener que el algoritmo de ventana fija.

Algoritmo Token Bucket (Algoritmo del Cubo de Tokens)

En este algoritmo, se llena un cubo (bucket) ficticio con tokens, y cada vez que el servidor procesa una solicitud, se saca un token del cubo. Cuando el cubo está vacío, el servidor no puede procesar más solicitudes. Las solicitudes posteriores se retrasan o deniegan hasta que se vuelva a llenar el cubo.

El token bucket se rellena a un ritmo fijo (conocido como ritmo de generación de tokens), y el número máximo de tokens que pueden almacenarse en el bucket también es fijo (conocido como profundidad del bucket).

Controlando la tasa de regeneración de tokens y la profundidad del cubo, puedes controlar la tasa máxima de flujo de tráfico permitida por la API. El paquete express-throttle que has visto antes utiliza el algoritmo del cubo de tokens para estrangular o controlar el flujo de tráfico de la API.

La mayor ventaja de este algoritmo es que soporta tráfico en burst siempre que quepa en la profundidad del bucket. Esto es especialmente útil para el tráfico impredecible.

Algoritmo Leaky Bucket

El algoritmo leaky bucket es otro algoritmo para gestionar el tráfico de la API. En lugar de mantener una profundidad de cubo que determine cuántas solicitudes se pueden gestionar en un periodo de tiempo (como en un Token Bucket), permite un flujo fijo de solicitudes desde el cubo, que es análogo al flujo constante de agua desde un cubo con fugas.

La profundidad del bucket, en este caso, se utiliza para determinar cuántas solicitudes pueden ponerse en cola para ser procesadas antes de que el cubo empiece a desbordarse, es decir, a denegar las solicitudes entrantes.

El leaky bucket promete un flujo constante de solicitudes y, a diferencia del token bucket, no gestiona los picos de tráfico.

Buenas Prácticas para Limitar la Tasa de la API

Ahora que ya sabes qué es la limitación de tasa de la API y cómo se aplica. Aquí tienes algunas buenas prácticas que debes tener en cuenta al implementarla en tu aplicación.

Ofrece un Nivel Gratuito para que los Usuarios Exploren tus Servicios

Cuando te plantees implantar un límite de tasa de la API, intenta siempre ofrecer un nivel gratuito adecuado que tus posibles usuarios puedan utilizar para probar tu API. No tiene por qué ser muy generoso, pero debe ser suficiente para que puedan probar tu API cómodamente en su aplicación de desarrollo.

Aunque los límites de tasa de la API son vitales para mantener la calidad de los endpoints de tu API para tus usuarios, una pequeña capa gratuita no regulada puede ayudarte a conseguir nuevos usuarios.

Decide Qué Ocurre Cuando se Supera el Límite de Tasa

Cuando un usuario supera el límite de tasa de API establecido, hay un par de cosas que debe tener en cuenta para asegurarte de ofrecer una experiencia de usuario positiva y, al mismo tiempo, proteger tus recursos. Algunas preguntas que debes hacerte y consideraciones que debes tener en cuenta son:

¿Qué Código y Mensaje de Error Verán Tus Usuarios?

Lo primero que debes tener en cuenta es informar a tus usuarios de que han superado el límite de tasa de la API establecido. Para ello, debes cambiar la respuesta de la API por un mensaje preestablecido que explique el problema. Es importante que el código de estado de esta respuesta sea 429 «Too Many Requests». También es habitual explicar el problema en el cuerpo de la respuesta. Aquí tienes un ejemplo de cuerpo de respuesta:

{
    "error": "Too Many Requests",
    "message": "You have exceeded the set API rate limit of X requests per minute. Please try again in a few minutes.",
    "retry_after": 60
}

El cuerpo de respuesta de ejemplo que se muestra arriba menciona el nombre y la descripción del error y también especifica una duración (normalmente en segundos) tras la cual el usuario puede volver a intentar enviar solicitudes. Un cuerpo de respuesta descriptivo como éste ayuda a los usuarios a comprender qué ha ido mal y por qué no han recibido la respuesta que esperaban. También les permite saber cuánto tiempo deben esperar antes de enviar otra solicitud.

¿Se Ralentizarán o Detendrán por Completo las Nuevas Solicitudes?

Otro punto de decisión es qué hacer después de que un usuario supere el límite de tasa de la API establecido. Normalmente, impedirías que el usuario interactuara con el servidor enviándole una respuesta 429 «Too Many requests», como has visto antes. Sin embargo, también deberías considerar un enfoque alternativo—la regulación.

En lugar de cortar completamente el acceso al recurso del servidor, puedes ralentizar el número total de peticiones que el usuario puede enviar en un periodo de tiempo. Esto es útil cuando quieres dar a tus usuarios un pequeño tirón de orejas, pero permitirles seguir trabajando si reducen su volumen de peticiones.

Tipo Considera el Almacenamiento en Caché y la Rotura de Circuitos

Los límites de tasa de la API son desagradables — impiden a tus usuarios interactuar con tus servicios API y utilizarlos. Esto es especialmente grave para los usuarios que necesitan realizar solicitudes similares una y otra vez, como acceder a un conjunto de datos de previsión meteorológica que sólo se actualiza semanalmente o recuperar una lista de opciones para un menú desplegable que puede cambiar una vez cada mucho tiempo. En estos casos, un enfoque inteligente sería implementar la caché.

El almacenamiento en caché es una abstracción de almacenamiento de alta velocidad implementada en casos en los que el volumen de acceso a los datos es alto, pero los datos no cambian muy a menudo. En lugar de hacer una llamada a la API que podría invocar varios servicios internos e incurrir en grandes gastos, podrías almacenar en caché los endpoints utilizados con más frecuencia, de modo que la segunda solicitud en adelante se sirva desde la caché estática, lo que suele ser más rápido, más barato y puede reducir la carga de trabajo de tus servicios principales.

Puede darse otro caso en el que recibas un número inusualmente alto de peticiones de un usuario. Incluso después de establecer un límite de tasa, están alcanzando constantemente su capacidad y se les limita la tasa. Estas situaciones indican que existe la posibilidad de un posible abuso de la API.

Para proteger tus servicios de la sobrecarga y mantener una experiencia uniforme para el resto de tus usuarios, deberías considerar la posibilidad de restringir completamente el acceso a la API al usuario sospechoso. Esto se conoce como interrupción del circuito, y aunque suena parecido a la limitación de tasa, generalmente se utiliza cuando el sistema se enfrenta a una sobrecarga de peticiones y necesita tiempo para ralentizarse y recuperar su calidad de servicio.

Monitorea de Cerca tu Configuración

Aunque los límites de tasa de la API están pensados para distribuir tus recursos equitativamente entre tus usuarios, a veces pueden causar molestias innecesarias a tus usuarios o incluso indicar actividades sospechosas.

Configurar una solución de monitorización robusta para tu API puede ayudarte a comprender con qué frecuencia tus usuarios alcanzan los límites de tasa, si necesitas o no reconsiderar los límites generales teniendo en cuenta la carga de trabajo media de tus usuarios e identificar a los usuarios que alcanzan sus límites con frecuencia (lo que podría indicar que posiblemente necesitarían un aumento de sus límites pronto o que necesitan ser monitorizados para detectar actividades sospechosas). En cualquier caso, una configuración de supervisión activa te ayudará a comprender mejor el impacto de los límites de tasa de tu API.

Implementa la Limitación de Tasa en Múltiples Capas

La limitación de la tasa puede aplicarse a varios niveles (usuario, aplicación o sistema). Mucha gente comete el error de establecer límites de tasa sólo en uno de estos niveles y esperar que cubra todos los casos posibles. Aunque no es exactamente un anti-patrón, puede resultar ineficaz en algunos casos.

Si las peticiones entrantes sobrecargan la interfaz de red de tu sistema, puede que la limitación de tasa a nivel de aplicación ni siquiera sea capaz de optimizar las cargas de trabajo. Por eso es mejor establecer las reglas de limitación de tasa en más de un nivel, preferiblemente en las capas superiores de tu arquitectura, para asegurarte de que no se crean cuellos de botella.

Trabajar con Límites de Tasa de la API

En esta sección, aprenderás cómo probar los límites de tasa de la API para un determinado endpoint de la API y cómo implementar un control de uso en tu cliente para asegurarte de que no acabas agotando los límites de tu API remota.

Cómo Probar los Límites de Tasa de la API

Para identificar el límite de tasa de una API, lo primero que debes hacer siempre es leer la documentación de la API para saber si los límites están claramente definidos. En la mayoría de los casos, los documentos de la API te indicarán el límite y cómo se ha implementado. Deberías recurrir a «probar» el límite de tasa de la API para identificarlo sólo cuando no puedas identificarlo a partir de los documentos de la API, el soporte o la comunidad. Esto se debe a que probar una API para encontrar su límite de tasa significa que acabarás agotando tu límite de tasa al menos una vez, lo que podría incurrir en costes financieros y/o indisponibilidad de la API durante un cierto tiempo.

Si quieres identificar manualmente el límite de tasa, primero debes empezar con una herramienta sencilla de pruebas de API, como Postman, para hacer peticiones manualmente a la API y ver si puedes agotar su límite de tasa. Si no puedes, entonces puedes utilizar una herramienta de pruebas de carga como Autocannon o Gatling para simular un gran número de solicitudes y ver cuántas solicitudes gestiona la API antes de que empiece a responder con un código de estado 429.

Otro enfoque puede ser utilizar una herramienta de comprobación de límite de tasa como la de AppBrokers rate-limit-test-tool. Herramientas dedicadas como ésta automatizan el proceso por ti y también te proporcionan una interfaz de usuario para analizar detenidamente los resultados de la prueba.

Sin embargo, si no estás seguro del límite de tasa de una API, siempre puedes intentar estimar tus requisitos de solicitud y establecer límites en el lado del cliente para asegurarte de que el número de solicitudes de tu aplicación no supere esa cifra. Aprenderás cómo hacerlo en la siguiente sección.

Cómo Limitar las Llamadas a la API

Si realizas llamadas a una API desde tu código, es posible que desees implementar reguladores en tu lado para asegurarte de que no acabas realizando accidentalmente demasiadas llamadas a la API y agotando tu límite de API. Hay varias formas de hacerlo. Una de las formas más populares es utilizar el método throttle de la biblioteca de utilidades lodash.

Antes de empezar a regular una llamada a la API, tendrás que crear una API. Aquí tienes un código de ejemplo para una API basada en Node.js que imprime en la consola el número medio de solicitudes que recibe por minuto:

const express = require('express');
const app = express();

// maintain a count of total requests
let requestTotalCount = 0;
let startTime = Date.now();

// increase the count whenever any request is received
app.use((req, res, next) => {
    requestTotalCount++;
    next();
});

// After each second, print the average number of requests received per second since the server was started
setInterval(() => {
    const elapsedTime = (Date.now() - startTime) / 1000;
    const averageRequestsPerSecond = requestTotalCount / elapsedTime;
    console.log(`Average requests per second: ${averageRequestsPerSecond.toFixed(2)}`);
}, 1000);

app.get('/', (req, res) => {
    res.send('Hello World!');
});

app.listen(3000, () => {
    console.log('Server listening on port 3000!');
});

Una vez que se ejecute esta aplicación, imprimirá el número medio de solicitudes recibidas cada segundo:

Average requests per second: 0
Average requests per second: 0
Average requests per second: 0

A continuación, crea un nuevo archivo JavaScript con el nombre test-throttle.js y guarda en él el siguiente código:

// function that calls the API and prints the response
const request = () => {
    fetch('http://localhost:3000')
    .then(r => r.text())
    .then(r => console.log(r))
}

// Loop to call the request function once every 100 ms, i.e., 10 times per second
setInterval(request, 100)

Una vez que ejecutes este script, observarás que el número medio de peticiones del servidor se aproxima a 10:

Average requests per second: 9.87
Average requests per second: 9.87
Average requests per second: 9.88

¿Qué pasaría si esta API sólo permitiera 6 peticiones por segundo, por ejemplo? Querrías mantener el promedio de peticiones por debajo de esa cifra. Sin embargo, si tu cliente envía una solicitud basándose en alguna actividad del usuario, como el clic de un botón o un desplazamiento, es posible que no puedas limitar el número de veces que se activa la llamada a la API.

La función throttle() de lodash puede ayudarte en este caso. En primer lugar, instala la biblioteca ejecutando el siguiente comando:

npm install lodash

A continuación, actualiza el archivo test-throttle.js para que contenga el siguiente código:

// import the lodash library
const { throttle } = require('lodash');

// function that calls the API and prints the response
const request = () => {
    fetch('http://localhost:3000')
    .then(r => r.text())
    .then(r => console.log(r))
}

// create a throttled function that can only be called once every 200 ms, i.e., only 5 times every second
const throttledRequest = throttle(request, 200)

// loop this throttled function to be called once every 100 ms, i.e., 10 times every second
setInterval(throttledRequest, 100)

Ahora, si miras los registros del servidor, verás una salida similar:

Average requests per second: 4.74
Average requests per second: 4.80
Average requests per second: 4.83

Esto significa que aunque tu aplicación está llamando a la función request 10 veces por segundo, la función de regulación se asegura de que sólo se llame 5 veces por segundo, ayudándote a mantenerte por debajo del límite de tasa. Así es como puedes configurar la regulación del lado del cliente para evitar agotar los límites de tasa de la API.

Errores Comunes del Límite de Tasa de la API

Cuando trabajas con APIs de tasa limitada, puedes encontrarte con una variedad de respuestas que indican que se ha superado un límite de tasa. En la mayoría de los casos, recibirás el código de estado 429 con un mensaje similar a uno de estos:

  • Las llamadas a esta API han superado el límite de tasa
  • Límite de tasa de la API superado
  • 429 demasiadas solicitudes

Sin embargo, el mensaje que recibas depende de la implementación de la API que estés utilizando. Esta implementación puede variar, y puede que algunas API ni siquiera utilicen el código de estado 429. Aquí tienes otros tipos de códigos de error de límite de tasa y mensajes que puedes recibir al trabajar con APIs de tasa limitada:

  • 403 Forbidden o 401 Unauthorized: Algunas API pueden empezar a tratar tus peticiones como no autorizadas y, por tanto, denegarte el acceso al recurso
  • 03 Service Unavailable o 500 Internal Server Error: Si una API está sobrecargada de peticiones entrantes, puede empezar a enviar mensajes de error 5XX indicando que el servidor no está en condiciones. Esto suele ser temporal y el proveedor de servicios lo soluciona a su debido tiempo.

Cómo Implementan los Principales Proveedores de API los Límites de Tasa de la API

A la hora de establecer el límite de tasa de tu API, puede ser útil echar un vistazo a cómo lo hacen algunos de los principales proveedores de API:

  • Discord: Discord implementa la limitación de tasa de dos formas: hay un límite de tasa global de 50 solicitudes por segundo. Aparte del límite global, también hay límites de tasa específicos de cada ruta que debes tener en cuenta. Puedes leerlo todo en esta documentación. Cuando se supere el límite de tasa, recibirás una respuesta HTTP 429 con un valor retry_after que puedes utilizar para esperar antes de enviar otra solicitud.
  • Twitter: Twitter también tiene límites de tasa específicos para cada ruta que puedes encontrar en su documentación. Una vez superado el límite de tasa, recibirás una respuesta HTTP 429 con un valor de cabecera x-rate-limit-reset que te indicará cuándo puedes reanudar el acceso.
  • Reddit: La wiki de la API archivada de Reddit establece que el límite de tasa para acceder a la API de Reddit es de 60 solicitudes por minuto (sólo a través de OAuth2). La respuesta a cada llamada a la API de Reddit devuelve los valores de las cabeceras X-Ratelimit-Used, X-Ratelimit-Remaining, y X-Ratelimit-Reset con los que puedes determinar cuándo podría superarse el límite y cómo lo harás
  • Facebook: Facebook también establece límites de tasa basados en rutas. Por ejemplo, las llamadas realizadas desde aplicaciones basadas en Facebook están limitadas a 200 * (número de usuarios de la aplicación) peticiones por hora. Puedes encontrar todos los detalles aquí. Las respuestas de la API de Facebook contendrán un encabezado X-App-Usage o X-Ad-Account-Usage para ayudarte a comprender cuándo se estrangulará tu uso.

Resumen

Cuando se crean API, es crucial garantizar un control óptimo del tráfico. Si no vigilas de cerca la gestión del tráfico, pronto acabarás con una API sobrecargada y no funcional. A la inversa, cuando trabajes con una API de tasa limitada, es importante que entiendas cómo funciona la limitación de tasa y cómo debes utilizar la API para garantizar la máxima disponibilidad y uso.

En esta guía, has aprendido sobre la limitación de tasa de la API, por qué es necesaria, cómo se puede implementar y algunas buenas prácticas que debes tener en cuenta cuando trabajes con límites de tasa de la API.

¡Echa un vistazo al Alojamiento de Aplicaciones de Kinsta y pon en marcha tu próximo proyecto Node.js hoy mismo!

¿Trabajas con una API de tarifa limitada? ¿O has implementado la limitación de tarifas en tu propia API? Háznoslo saber en los comentarios