req-guard-lite : Un limiteur de débit minimal, basé sur TypeScript, pour Express
Découvrez comment fonctionne un limiteur de débit Express léger et sans dépendances, des paramètres par défaut en mémoire jusqu’à l’escalade via Redis et aux générateurs de clés personnalisés.
Toute application Express atteint tôt ou tard un stade où une limitation de fréquence devient nécessaire.
Que l’objectif soit de protéger les routes d’accès, de réduire le spam ou simplement d’éviter une utilisation excessive non intentionnelle, la limitation du trafic entrant passe rapidement d’une fonction utile à une exigence dès qu’une API est mise en ligne publiquement.
Lors de la recherche d’une solution de limitation de fréquence répondant à des besoins courants, il est apparu clairement que, bien qu’il existe déjà de nombreuses bibliothèques performantes, de nombreux projets souhaitent en réalité quelque chose de léger, facile à comprendre et simple à personnaliser.
C’est ce manque qui a conduit à la création de req-guard-lite.
Pourquoi un autre limiteur de fréquence ?
La plupart des API n’ont pas besoin d’un ensemble complet de solutions de sécurité d’entreprise dès le premier jour.
Souvent, tout ce dont on a besoin, c’est de pouvoir écrire quelque chose comme :
app.use(rateLimit({
max: 100,
windowMs: 15 * 60 * 1000
}));
...et revenir à la construction du reste de l’application.
Les objectifs de conception pour ce package étaient :
- Rester léger
- Être facile à mettre en place
- Être conçu dès le départ avec TypeScript en tête
- Permettre une extension facile
- Fonctionner aussi bien pour de petits projets que pour des systèmes à grande échelle
Présentation de req-guard-lite
req-guard-lite est un middleware Express compact conçu pour protéger votre API d’un volume écrasant de requêtes.
Par défaut, il fonctionne entièrement en mémoire, mais il peut également être étendu à des configurations distribuées en s’intégrant à Redis.
Son champ d’action est intentionnellement restreint — il fait bien une seule chose :
Suivre les requêtes entrantes et rejeter les clients dès qu’ils dépassent la limite que vous avez fixée.
Fonctionnalités
Mise en œuvre légère Aucune dépendance en temps de exécution dans le package principal Fonctionne comme middleware Express Soutien natif pour TypeScript Intégration Redis disponible Soutien pour des backends de stockage personnalisés Soutien pour des générateurs de clés personnalisés
Démarrer
Installez-le en complément d’Express.
npm install req-guard-lite express
Ensuite, connectez-le à votre application.
import express from 'express';
import { rateLimit } from 'req-guard-lite';
const app = express();
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: 'Too many requests, please try again later.'
});
app.use(limiter);
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000);
C’est toute la configuration nécessaire.
Votre API bloque désormais tout client envoyant plus de 100 requêtes dans une fenêtre de 15 minutes.
Stockage en mémoire par défaut
Déjà prêt à l’emploi, les compteurs de requêtes sont stockés en mémoire.
En pratique, cela signifie :
- Aucun Redis requis
- Aucune base de données requise
- Aucune configuration supplémentaire nécessaire
- Ideal pour le développement local
- Sélection fiable pour la production sur un seul serveur
Pour une grande partie des applications, c’est toute la limitation de débit dont vous aurez jamais besoin.
Échelle avec Redis
Lorsqu’une application s’étend pour fonctionner sur plusieurs serveurs ou conteneurs, ces instances ont besoin d’une vue partagée du nombre de requêtes.
C’est là que Redis joue son rôle.
import Redis from "ioredis";
import { createRedisStore } from "req-guard-lite/redis";
const redis = new Redis();
const limiter = rateLimit({
max: 100,
windowMs: 15 * 60 * 1000,
store: createRedisStore(redis, {
max: 100,
windowMs: 15 * 60 * 1000
})
});
Avec cela en place, chaque instance serveur lit et écrit les mêmes compteurs, de sorte que les limites restent cohérentes quel que soit le nœud qui traite une requête donnée.
Générateurs de clés personnalisés
La limitation de débit par adresse IP n’est pas toujours la bonne approche.
Dans certains cas, il est préférable de baser les limites sur :
- Un ID d’utilisateur
- Une clé API
- Un identifiant de locataire
- Une organisation
- Une prétention de sujet JWT
- Ou tout autre identifiant adapté à votre modèle
Pour cela, req-guard-lite vous permet de fournir votre propre fonction générateur de clé.
const limiter = rateLimit({
max: 100,
keyGenerator: (req) =>
req.headers["x-api-key"] as string
});
Ou, en se basant sur l’utilisateur connecté plutôt :
const limiter = rateLimit({
max: 50,
keyGenerator: (req) =>
(req as any).user.id
});
Le middleware lui-même est indifférent à la signification de la clé — il se contente de compter les appels en fonction de l’identifiant retourné par votre fonction.
Apportez votre propre stockage
L’extensibilité était une exigence fondamentale dès le début.
Au lieu de vous limiter à Redis, req-guard-lite expose une interface simple RateLimitStore. Si votre infrastructure repose déjà sur :
- PostgreSQL
- DynamoDB
- Memcached
- MongoDB
- SQLite
- Un autre layer de mise en cache personnalisé
vous pouvez l’intégrer en implémentant cette seule interface.
class MyStore implements RateLimitStore {
consume(key: string) {
// your implementation
}
}
Cette conception permet au package de s’adapter à presque n’importe quel backend déjà en cours d’exécution.
Un conseil important pour la production
Si votre application est derrière :
- Nginx
- Un chargeur de balançage AWS
- Heroku
- Cloudflare
- Tout proxy inversé
assurez-vous de configurer Express correctement :
app.set("trust proxy", 1);
Si vous sautez cette étape, Express traitera souvent chaque requête entrante comme si elle provenait du proxy lui-même, ce qui signifie que tous vos utilisateurs partageront le même quota de requêtes. La solution est simple, mais elle évite un problème en production qui prend souvent par surprise de nombreuses équipes.
Fonctionnement
Le flux interne est délibérément minimal :
- Une requête arrive.
- Le middleware génère une clé pour elle (l’IP du client, par défaut).
- Le stock actif incrémente le compteur associé à cette clé.
Comme le système est adaptable, ce même flux fonctionne que vous utilisiez de la mémoire, Redis ou une implémentation personnalisée.
Pourquoi TypeScript ?
Toute la bibliothèque est écrite en TypeScript, ce qui offre :
- Un typage strict partout
- Une complétion automatique plus riche dans l’éditeur
- Un entretien à long terme simplifié
- Des API plus difficiles à utiliser de manière abusive
Les utilisateurs de TypeScript disposent de définitions de types complètes dès le départ, sans avoir besoin d’installer de packages @types supplémentaires.
Feuille de route
v0.4.0
- Soutien aux en-têtes de réponse standard de limitation de fréquence
X-RateLimit-Limit
X-RateLimit-Remaining
X-RateLimit-Reset
Ces en-têtes permettent aux applications clientes de connaître le nombre de requêtes restantes avant d’atteindre la limite maximale.
v0.5.0
Fonctions d’ancrage configurables qui s’exécutent lorsque la limite est dépassée, utiles pour des tâches telles que :
- Le journalage
- La collecte de métriques
- L’envoi d’alertes
- Les analyses
- L’envoi de données vers des outils de surveillance externes
Pourquoi c’est open source
Ce projet n’est pas une réponse au manque de solutions existantes — il existe déjà plusieurs excellentes solutions de limitation de débit dans l’écosystème Node. req-guard-lite a été créé parce que l’objectif était un package qui soit :
- Assez compact pour être lu et compris en une seule fois
- Simple à étendre
- Développé en priorité avec TypeScript
- Exempt de complexités inutiles
- Assez flexible pour s’adapter aux besoins réels en production
Le développement de ce projet a également été une excellente opportunité d’apprendre à publier des paquets, à concevoir des API, à écrire des tests, à s’intégrer avec Redis et à créer des abstractions faciles à utiliser par d’autres développeurs.
Remarques finales
Ouvrir le code source d’un projet est l’une des façons les plus efficaces de perfectionner ses compétences en ingénierie. Lorsque d’autres développeurs peuvent installer, utiliser et contribuer à votre code, vous êtes contraint de penser au-delà de votre propre cas d’usage immédiat — la documentation, la conception des API, les tests, la gestion des versions et la compatibilité vers l’arrière deviennent tous des contraintes réelles auxquelles vous devez faire face.
req-guard-lite est né d’un petit middleware conçu pour répondre à un besoin personnel, mais on espère qu’il deviendra une solution utile, légère et extensible pour la limitation des requêtes destinée aux autres développeurs d’Express. Les retours, les suggestions de fonctionnalités et les contributions sont tous les bienvenus.
Lectures complémentaires
- Partager un schéma Zod entre votre frontend React et votre backend Node — Découvrez comment un seul schéma Zod peut valider les formulaires React, les réponses API, les corps de requête Express et les variables d’environnement tout en générant des types TypeScript correspondants.
- Zod vs express-validator : Deux approches pour la validation Express — Compare la validation des requêtes basée sur les schémas avec Zod à celle utilisant les middleware chainés d’express-validator, en abordant la configuration, le formatage des erreurs et les pièges courants.