anatix-tools
v1.0.6
Published
Anatix toolkit pour NestJS avec event-bus, logger, proxy, decorators et utils.
Readme
🧰 anatix-tools – Librairie utilitaire NestJS pour Anatix-Generator
anatix-tools est une boîte à outils Node.js/TypeScript pour NestJS, utilisée dans le générateur de microservices Anatix-Generator. Elle fournit un socle commun de fonctionnalités (communication inter-services, journalisation centralisée, appels HTTP uniformisés, etc.) pour standardiser et simplifier le développement des microservices dans l'écosystème Anatix. La librairie regroupe plusieurs modules clés (bus d'événements, gestionnaire de logs, proxy HTTP, filtre global d'erreurs, utilitaires divers) destinés à être intégrés dans chaque microservice, garantissant une architecture cohérente et des bonnes pratiques partagées.
✨ Fonctionnalités principales
📢 Bus d'événements centralisé (basé sur RabbitMQ) permettant la communication asynchrone et découplée entre microservices.
📝 Journalisation unifiée des logs via le bus d'événements, pour centraliser et corréler les journaux de tous les services.
🌐 Proxy HTTP pour les appels inter-services avec gestion automatique des délais d'attente (timeout), des nouvelles tentatives (retry) et des erreurs (exceptions HTTP homogénéisées).
⚠️ Filtre global d'exceptions assurant un traitement uniforme des erreurs et des réponses cohérentes en cas d'échec dans les API.
🛠️ Utilitaires généraux (formatage de dates, parsing de paramètres, etc.) évitant la duplication de code commun dans les microservices.
📦 Installation
Cette librairie est distribuée via npm. Pour l'ajouter à votre projet NestJS :
npm install anatix-toolsPrérequis : Assurez-vous de disposer d'une application NestJS (v10+) fonctionnelle avant d'intégrer Anatix-Tools. Ce package repose sur plusieurs peer dependencies (telles que @nestjs/common, @nestjs/core, @nestjs/microservices, rxjs, class-validator, class-transformer...), qui doivent déjà être présentes dans votre projet NestJS.
⚙️ Configuration & Dépendances
Certains composants d'Anatix-Tools nécessitent une configuration par variables d'environnement et des services externes :
RabbitMQ : un serveur RabbitMQ est requis pour le bus d'événements. Configurez l'URL de connexion via la variable
RABBITMQ_URL(par défautamqp://localhost). Assurez-vous qu'une instance RabbitMQ est accessible à cette adresse.Échange et file d'événements : par défaut, le bus utilise l'échange
anatix-event-bus(modifiable viaEVENT_BUS_EXCHANGE) et une file de messages nomméedefault-queue(modifiable viaEVENT_BUS_QUEUE). Il est conseillé de définir pour chaque microservice un nom de queue distinct viaEVENT_BUS_QUEUEafin que chaque service reçoive uniquement les événements qui lui sont destinés.Timeout et retries HTTP : les fonctions de proxy HTTP utilisent une valeur par défaut de 5000 ms pour le timeout (
PROXY_TIMEOUT_MS) et effectuent 2 tentatives en cas d'échec (PROXY_RETRY). Vous pouvez ajuster ces valeurs via les variables d'environnement correspondantes.Autres dépendances : assurez-vous d'avoir ajouté le module
HttpModulede NestJS (fournissantHttpService) dans vos microservices si vous utilisez les proxies HTTP. Le filtre global d'exceptions utilise le framework Web par défaut de Nest (Express) pour formater la réponse d'erreur.
En résumé, vérifiez que vos variables d'environnement (fichier .env ou autre) sont correctement définies pour RabbitMQ et les paramètres de proxy, et que les services requis (comme RabbitMQ) sont opérationnels avant de démarrer vos microservices.
📁 Structure du code et modules
anatix-tools/
├── packages/
│ ├── event-bus/ # 🔄 Bus d'événements basé sur RabbitMQ (EventBusModule & Service)
│ ├── logger/ # 📝 Journalisation centralisée via le bus d'événements (LogHelper, DTO de log)
│ ├── proxy/ # 🌐 Proxy HTTP pour appels externes (fonctions GET/POST/... avec retry)
│ ├── decorators/ # 🎖️ Filtre global d'exceptions NestJS (GlobalExceptionFilter)
│ ├── utils/ # 🛠️ Fonctions utilitaires diverses (dates, filtres, etc.)
│ └── constants.ts # ⚙️ Constantes de configuration globales (RabbitMQ, timeouts, etc.)
├── package.json
└── ...Les principaux modules inclus dans la librairie sont détaillés ci-dessous :
Event Bus (Bus d'événements)
Le module Event Bus fournit un EventBusModule et un service EventBusService permettant la communication asynchrone entre microservices via RabbitMQ. À l'initialisation, le service établit une connexion AMQP en utilisant l'URL fournie (RABBITMQ_URL), déclare un exchange de type topic (par défaut nommé anatix-event-bus) et une queue dédiée au microservice (nom définissable via EVENT_BUS_QUEUE).
Émission d'événements : la méthode
emit(eventName, payload)publie un message sur le bus avec une clé de routage correspondant au nom de l'événement. Tous les microservices ayant souscrit à cet événement recevront le message (via leur propre queue).Souscription aux événements : le
EventBusServicepermet de s'abonner à un type d'événement grâce à une méthode dédiée (par ex.subscribe(eventName, handler)). Lorsqu'un microservice s'abonne à un événement, le service va lier sa queue RabbitMQ à l'exchange sur la clé de routage correspondante, puis appeler la fonction de handler fournie à chaque fois qu'un message de ce type est reçu.Communication découplée : ce système de publication/souscription permet un couplage lâche entre services. Un microservice peut émettre des événements sans se préoccuper de qui les consomme, et réciproquement écouter certains événements produits par d'autres services, ce qui facilite l'extensibilité et la résilience de l'architecture.
Requêtes avec réponse (RPC) : en plus des événements "one-way", le bus prend en charge un mode requête/réponse. La méthode
emitAndWait(eventName, payload, timeout?)émet un événement en attendant explicitement une réponse. Sous le capot, le service crée une queue éphémère de réponse et utilise un correlation ID pour corréler la réponse attendue. Cela permet d'implémenter des appels synchrones (de type RPC) entre microservices tout en passant par RabbitMQ.
Pour utiliser le bus d'événements dans un microservice Anatix, importez simplement EventBusModule dans le module principal du service. Le EventBusService pourra alors être injecté dans vos services ou controllers NestJS afin d'émettre des événements ou de s'y abonner selon les besoins.
Logger (Journalisation centralisée)
Le module Logger offre un mécanisme de logs centralisés en s'appuyant sur le bus d'événements. La classe principale, LogHelper, s'utilise pour enregistrer des journaux structurés sans dépendre d'un fichier local ou de la console de chaque microservice.
Log via EventBus : au lieu d'écrire directement dans la console,
LogHelperenvoie chaque log sous forme d'événement sur le bus. Pour ce faire, on instancie unLogHelperavec une référence vers leEventBusServiceet le nom du microservice courant. Par exemple :const logger = new LogHelper(eventBusService, 'UserService').Niveaux de log : le helper propose des méthodes correspondant aux différents niveaux de log :
info(),warn(),error(), etcritical(). Chaque appel construit un objet de log structuré (défini par le DTOCreateLogDtoavec les champs : service émetteur, niveau, message, métadonnées éventuelles, utilisateur, tag, stack trace) puis publie un événement sur le bus d'événements. Par convention, les événements de log utilisent une clé de routage dédiée, par ex.log.UserService, ce qui permet de filtrer/diriger ces messages spécifiquement.Traitement des erreurs critiques : la méthode
critical()enregistre un log de niveau ERROR puis lance une exception correspondante. Concrètement, si l'erreur passée est une exception HTTP connue (HttpException), elle sera relancée telle quelle. Sinon, une exception génériqueInternalServerErrorException(500) est levée après journalisation. Cela permet de centraliser le pattern de gestion des erreurs fatales : loguer l'erreur et interrompre le flux d'exécution de manière appropriée.Agrégation centralisée : en publiant tous les logs sur le bus (par exemple avec la clé de routage
log.*), il devient possible de mettre en place un microservice de collecte des logs ou tout autre consommateur écoutant ces événements pour stocker ou analyser les journaux de l'ensemble du système de microservices.
En résumé, le module Logger d'Anatix-Tools permet à chaque service de pousser ses logs dans un canal commun (RabbitMQ) plutôt que de simplement les afficher en local, offrant ainsi la possibilité d'un monitoring et d'une analyse centralisés des événements de log.
Proxy HTTP (Appels externes)
Le module Proxy regroupe des fonctions utilitaires facilitant les appels HTTP sortants depuis un microservice (typiquement pour appeler un autre service Anatix ou une API externe). Plutôt que d'utiliser directement un client HTTP basique, ces fonctions proxy apportent robustesse et simplification en gérant pour vous les points suivants :
Timeout global : chaque requête est soumise à un délai maximal (par défaut 5000 ms, configurable via
PROXY_TIMEOUT_MS). Au-delà, une exception de typeHttpException504 Gateway Timeout est automatiquement levée pour signaler l'indisponibilité du service cible.Retries automatisés : en cas d'échec transitoire (par exemple, service temporairement inaccessible), le proxy retente automatiquement la requête selon un nombre prédéfini de tentatives (2 retries par défaut, via
PROXY_RETRY). Ceci augmente la résilience face aux erreurs réseau momentanées.Propagation des erreurs HTTP : si le service appelé retourne une réponse d'erreur (code HTTP 4xx ou 5xx), la fonction proxy relaie cette erreur sous forme d'exception NestJS contenant le même code statut et le message d'erreur retourné. Votre microservice peut ainsi renvoyer directement l'erreur au client appelant, sans traitement manuel, tout en conservant le code approprié.
Simplicité d'utilisation : cinq fonctions sont disponibles –
proxyGet,proxyPost,proxyPut,proxyPatch,proxyDelete– correspondant aux verbes HTTP. Chacune attend en paramètre une instance deHttpService(de NestJS) ainsi que l'URL cible, et éventuellement des paramètres de requête, un corps (pour POST/PUT/PATCH) ou des en-têtes. La fonction retourne une promesse résolue avec les données de la réponse en cas de succès, ou rejette une exception en cas d'erreur (timeout, statut d'erreur, etc.).
Pour utiliser ces proxies, assurez-vous d'avoir importé le HttpModule de @nestjs/axios dans votre microservice (afin de pouvoir injecter HttpService). Vous pouvez ensuite appeler, par exemple, await proxyGet(httpService, 'http://autre-service/api/endpoint', queryParams) depuis un service NestJS. Vous bénéficierez ainsi d'appels HTTP fiables et uniformisés, avec gestion automatique des exceptions, sans avoir à répéter le même code de contrôle des erreurs dans chaque appel.
Filtre global d'exceptions
Le module Decorators contient principalement le GlobalExceptionFilter, un filtre d'exception NestJS conçu pour uniformiser le traitement des erreurs non gérées dans l'application. En déclarant ce filtre au niveau global (via un provider { provide: APP_FILTER, useClass: GlobalExceptionFilter } ou en l'enregistrant dans le bootstrap de l'application avec app.useGlobalFilters(new GlobalExceptionFilter())), vous centralisez la gestion des erreurs.
Gestion des HttpException : Si l'exception interceptée est une instance de
HttpException(erreur volontairement levée dans le code applicatif, par exemple pour signaler une ressource non trouvée ou un accès interdit), le filtre extrait le code HTTP et le message/objet de réponse de cette exception et les utilise tels quels dans la réponse.Gestion des erreurs système : Pour toute autre erreur (erreur non prévue, exception JavaScript, etc.), le filtre attribue un code HTTP 500 Internal Server Error et un message générique "Internal server error".
Réponse uniformisée : Le filtre construit une réponse JSON standard contenant toujours le champ
statusCode(code numérique),path(l'URL de la requête ayant causé l'erreur), un timestamp ISO (timestamp) et un champmessagepouvant être soit un texte explicatif, soit un objet détaillant l'erreur. Ce format de sortie cohérent facilite le traitement côté client et le diagnostic.Logging intégré : À chaque exception interceptée, le filtre utilise la classe
Loggerde NestJS pour consigner l'erreur (méthode HTTP, URL et contenu de l'erreur) dans la console du serveur. Ceci assure une traçabilité des erreurs même si aucun système de log externe n'est encore en place.
Grâce à GlobalExceptionFilter, les microservices Anatix partagent tous la même politique de gestion des erreurs : l'équipe de développement n'a pas besoin d'implémenter manuellement la sérialisation d'erreurs dans chaque contrôleur, et les clients des API reçoivent systématiquement des réponses d'erreur structurées de la même manière.
Utilitaires (fonctions communes)
Le module Utils rassemble des fonctions utilitaires pour les besoins courants des microservices :
toISOStringSafe(value): convertit une date en chaîne ISO (format UTC) de manière sûre. Sivalueest un objet Date, la méthode renvoievalue.toISOString(). Si c'est une chaîne ou un timestamp numérique, elle tente de le convertir en Date puis en ISO. En cas de valeur invalide ou non convertible, la fonction retourne une chaîne vide plutôt que de produire une erreur.toDateOnlyString(value): extrait la partie date (formatYYYY-MM-DD) d'une date ou d'une chaîne date/heure. Sivalueest un objet Date, la date est formatée en ISO puis tronquée au jour uniquement. Si c'est une chaîne (par ex."2025-07-16T12:00:00Z"), la fonction ne conserve que la portion avant leT. Utile pour normaliser des dates sans composante horaire (par ex. pour comparer des dates de naissance, etc.).parseFilterFields(filters, defs): fonction de parsage des filtres très pratique pour traiter les paramètres de requête HTTP. Elle prend en entrée un objetfilters(typiquement issu des query params de l'URL) et un objet de définitiondefsde typeFilterFieldDefsqui spécifie le type attendu pour certains champs. La fonction retourne un nouvel objet où chaque champ est converti selon les règles fournies dansdefs:date : les champs listés dans
defs.date(p. ex.createdAt) sont convertis de chaîne en objetDate. De plus, si un champ est suffixé par "From" ou "To" (p. ex.createdAtFrom), il sera également converti en Date, ce qui facilite la gestion des intervalles de dates.dateOnly : pour les champs purement date (liste
defs.dateOnly), la valeur est transformée en chaîne "YYYY-MM-DD" sans composante horaire (si une heure était présente, elle est ignorée).number : les champs numériques (liste
defs.number) sont convertis de chaîne en valeurNumber. S'ils sont suffixés "From"/"To", la conversion s'applique de la même manière.boolean : les champs booléens (
defs.boolean) acceptent en entrée les chaînes"true"/"1"(converties entrue) ou"false"/"0"(converties enfalse).enum : pour les champs énumérés (
defs.enum), la fonction vérifie que la valeur fournie fait partie des valeurs autorisées définies dansdefs.enumValues. Si ce n'est pas le cas, deux stratégies sont possibles : soit lever une erreur (sithrowOnInvalidEnumest àtruedans la définition), soit simplement supprimer ce filtre non valide du résultat (le champ est ignoré).array : pour les champs qui doivent être des listes (
defs.array), si la valeur d'entrée est une chaîne comportant des virgules, elle sera découpée en un tableau (séparation sur,avec suppression des espaces inutiles).json : pour les champs devant contenir du JSON (
defs.json), si la valeur est une chaîne, la fonction tentera de la parser avecJSON.parsepour obtenir un objet JavaScript (en cas d'échec du parsing, la valeur d'origine est laissée telle quelle).custom : il est possible de définir dans
defs.customun objet de la forme{ champ: transformFn }pour appliquer une transformation personnalisée à certains champs. Si un champ est présent dansfilterset qu'une fonction custom est fournie pour ce champ, la valeur sera transformée par cette fonction.
Grâce à parseFilterFields, le code d'un contrôleur peut aisément convertir en quelques lignes l'ensemble de ses paramètres de recherche (query) en types natifs appropriés, au lieu de vérifier et convertir chaque champ manuellement. Cela contribue à des contrôleurs plus concis et fiables.
En conclusion, Anatix-Tools fournit une base solide pour construire des microservices NestJS cohérents et robustes. En intégrant ce toolkit, les microservices générés par Anatix-Generator partagent une structure commune pour la communication (événements), le logging, la gestion des erreurs et les utilitaires de traitement, ce qui accélère le développement tout en améliorant la maintenabilité et l'homogénéité de l'ensemble de la plateforme Anatix.
