coddyger
v1.4.23
Published
Coddyger est une bibliothèque JavaScript/TypeScript qui fournit des fonctions communes et des plugins pour la gestion des données, la communication entre services, et des utilitaires avancés pour le développement d'applications.
Readme
Coddyger
Coddyger est une bibliothèque JavaScript/TypeScript qui fournit des fonctions communes et des plugins pour la gestion des données, la communication entre services, et des utilitaires avancés pour le développement d'applications.
Description
Coddyger est un module conteneur qui offre :
- Gestion des opérations CRUD avec support MongoDB et SQL
- Communication via Kafka avec gestion avancée des événements
- Utilitaires complets pour la manipulation de données
- Système de logging configurable
- Validation et formatage de données
- Gestion des fichiers et des téléchargements
- Support multilingue et internationalisation
- Gestion des dates et des fuseaux horaires
- Gestion de cache configurable (Redis, mémoire, etc.)
Installation
npm install coddygerPrérequis
- Node.js >= 20.15.1
- npm >= 10.7.0
Configuration
Configuration de l'Environnement
Créez un fichier .env à la racine de votre projet :
# Configuration Kafka
TRANSPORTER_CLIENT=your-client-id
TRANSPORTER_BROKER=host1:port1,host2:port2
TRANSPORTER_GROUP=your-group-id
TRANSPORTER_TOPIC=your-topic
TRANSPORTER_FOREIGNERS=topic1,topic2,topic3
# Configuration Base de données
DATABASE_URL=your-database-url
DATABASE_NAME=your-database-name
DATABASE_DIALECT=mongodb|mysql|postgres|sqlite
DATABASE_STORAGE=path/to/sqlite.db # Pour SQLite uniquement
# Configuration des chemins
DOWNLOAD_PATH=/path/to/downloads
# Configuration du cache (exemple pour Redis)
CACHE_TYPE=redis
CACHE_HOST=localhost
CACHE_PORT=6379
CACHE_PASSWORD=yourpassword
CACHE_DB=0
CACHE_TTL=3600
CACHE_URL=redis://:yourpassword@localhost:6379/0Configuration de la Base de Données
Coddyger supporte deux types d'accès aux données :
MongoDB (via Mongoose)
import { MongooseDataAccess } from 'coddyger';
const db = new MongooseDataAccess();
db.connect(); // Utilise les variables d'environnement
// ou
db.connect('mongodb://custom-uri/database');Transactions MongoDB
Coddyger propose aussi un helper pour les transactions MongoDB (sessions) :
import { MongooseDataAccess } from 'coddyger';
const db = new MongooseDataAccess();
await db.connect();
await db.transaction(async (session) => {
await User.create([{ name: 'Alice' }], { session });
await Post.create([{ title: 'Hello' }], { session });
// Toutes les opérations sont atomiques
});SQL (via Sequelize)
import { SequelizeDataAccess } from 'coddyger';
// Utilisation de la chaîne de connexion de l'environnement
const db = new SequelizeDataAccess();
await db.connect(); // ← Obligatoire AVANT toute autre méthode
await db.sync(); // Synchronise les modèles
const isConnected = await db.isConnected();
// OU : passer une chaîne de connexion personnalisée (comme pour Mongoose)
const dbCustom = new SequelizeDataAccess('postgresql://user:password@localhost:5432/ma_base');
await dbCustom.connect();Vous pouvez passer la chaîne de connexion SQL directement au constructeur, ou laisser Coddyger utiliser celle de l'environnement (.env).
Transactions SQL
Coddyger propose des helpers pour gérer facilement les transactions avec Sequelize :
import { SequelizeDataAccess } from 'coddyger';
const db = new SequelizeDataAccess();
await db.connect();
// Transaction automatique (commit/rollback auto)
await db.transaction(async (t) => {
await User.create({ ... }, { transaction: t });
await Post.create({ ... }, { transaction: t });
});
// Transaction manuelle
const t = await db.getTransaction();
try {
await User.create({ ... }, { transaction: t });
await t.commit();
} catch (err) {
await t.rollback();
}Configuration du Cache
Coddyger supporte la configuration d’un système de cache (Redis, mémoire, etc.) via l’environnement :
# Exemple pour Redis
CACHE_TYPE=redis
CACHE_HOST=localhost
CACHE_PORT=6379
CACHE_PASSWORD=yourpassword
CACHE_DB=0
CACHE_TTL=3600
CACHE_URL=redis://:yourpassword@localhost:6379/0La configuration est accessible via env.cache.
Exemple d'utilisation de la config cache
import { env } from 'coddyger';
console.log(env.cache.type); // 'redis'
console.log(env.cache.host); // 'localhost'Tu peux brancher un client Redis ou autre système de cache selon cette configuration.
Fonctionnalités
1. Utilitaires (Namespaces)
String
import { string } from 'coddyger';
// Génération de mots de passe et tokens
const password = string.generateSecurePassword(12); // "aX9#mK2$pL5&"
const pin = string.generatePIN(6); // "123456"
const token = string.generateToken(32);
// Formatage et nettoyage
const clean = string.cleanText(" Mon Texte! "); // "mon texte"
const truncated = string.truncate("Long texte...", 10); // "Long te..."
const slug = string.slugify("Mon Titre"); // "mon-titre"Array
import { array } from 'coddyger';
// Manipulation de tableaux
const unique = array.unique([1, 2, 2, 3]); // [1, 2, 3]
const chunks = array.chunk([1, 2, 3, 4], 2); // [[1,2], [3,4]]
const intersection = array.intersection([1, 2], [2, 3]); // [2]
const difference = array.difference([1, 2, 3], [2]); // [1, 3]Object
import { object } from 'coddyger';
// Manipulation d'objets
const cloned = object.deepClone(originalObj);
const merged = object.deepMerge(obj1, obj2);
const value = object.get(obj, "user.profile.name", "default");
const cleaned = object.removeNullish(obj);Number
import { number } from 'coddyger';
// Formatage et calculs
const formatted = number.formatCurrency(1234.56, 'EUR'); // "1 234,56 €"
const random = number.random(1, 100);
const bytes = number.formatBytes(1234567); // "1.18 MB"
const percent = number.percentage(50, 200); // 25URL
import { url } from 'coddyger';
// Manipulation d'URLs
const isValid = url.isValid("https://example.com");
const domain = url.getDomain("https://sub.example.com");
const withParams = url.buildWithParams("https://api.com", { id: 123 });
const params = url.parseParams("https://api.com?key=value");Validation
import { validation } from 'coddyger';
// Validation de données
const isValidJson = validation.isValidJSON('{"key": "value"}');
const pwdStrength = validation.passwordStrength("MonMotDePasse123!");
const isValidSiret = validation.isSIRET("12345678901234");
const isValidIban = validation.isIBAN("FR7630006000011234567890189");2. Gestion des Dates
import { date } from 'coddyger';
// Manipulation de dates
const isInRange = date.isWithinInterval(
new Date(),
startDate,
endDate
);
const daysInMonth = date.getDaysInMonthCount(3, 2024); // 313. Gestion des Fichiers
import { file } from 'coddyger';
// Opérations sur les fichiers
const exists = file.exists("/path/to/file");
const ext = file.extension("document.pdf"); // ".pdf"
const base64 = file.toBase64("/path/to/image.jpg");
await file.download("https://example.com/file.pdf", "local.pdf");4. Gestion des Erreurs
Coddyger fournit des codes d'erreur et messages standardisés :
import { defines } from 'coddyger';
// Codes d'état HTTP
const { status } = defines;
response.status(status.badRequest); // 400
// Messages d'erreur
const { message } = defines;
console.log(message.notFound); // "Route introuvable ou inexistante"5. Système de Logging Avancé
Coddyger utilise Pino pour un logging performant et structuré :
import { LoggerService, LogLevel } from 'coddyger';
// Méthodes de logging simples
LoggerService.info('Opération réussie');
LoggerService.debug('Données de débogage', { userId: 123 });
LoggerService.warn('Attention', { resource: 'users' });
LoggerService.error(new Error('Erreur critique'));
LoggerService.fatal('Erreur système', { service: 'auth' });
// Logging avec contexte personnalisé
LoggerService.log({
type: LogLevel.Info,
content: 'Message personnalisé',
location: 'UserService',
method: 'create',
context: { userId: 123, action: 'create' }
});Caractéristiques du système de logging :
- Logs structurés au format JSON
- Niveaux de log multiples (trace, debug, info, warn, error, fatal)
- Rotation automatique des fichiers de log par date
- Fichiers séparés pour les erreurs
- Formatage coloré en développement avec pino-pretty
- Redaction automatique des données sensibles (mots de passe, tokens)
- Support du mode production/développement
- Contexte enrichi pour chaque log
Configuration des logs selon l'environnement :
# Configuration des logs
NODE_ENV=development # ou production6. Service HTTP (Axios)
Coddyger fournit un service HTTP robuste basé sur Axios avec des fonctionnalités avancées :
import { AxiosService } from 'coddyger';
// Configuration initiale
const axiosInstance = AxiosService.connect({
baseURL: 'https://api.example.com',
timeout: 30000,
retryConfig: {
maxRetries: 3,
delayMs: 1000,
retryCondition: (error) => error.response?.status >= 500
},
cacheConfig: {
enabled: true,
ttlMs: 5 * 60 * 1000 // 5 minutes
}
});
// Requêtes avec cache et retry
const response = await AxiosService.get('/users', {
cache: true, // Active le cache
cacheTTL: 60000, // Cache pendant 1 minute
retry: true // Active les retries en cas d'erreur
});
// Requête POST avec retry
const newUser = await AxiosService.post('/users', {
name: 'John Doe',
email: '[email protected]'
}, { retry: true });
// Gestion des headers par type de requête
AxiosService.setHeader('Authorization', 'Bearer token123', 'common');
AxiosService.setHeader('Custom-Header', 'value', 'post');
// Gestion du cache
AxiosService.clearCache();
const cacheSize = AxiosService.getCacheSize();Caractéristiques
Système de Cache Intelligent
- Cache configurable pour les requêtes GET
- TTL (Time To Live) personnalisable
- Invalidation automatique
- API pour gérer le cache manuellement
Gestion Avancée des Retries
- Nombre de tentatives configurable
- Délai exponentiel entre les tentatives
- Conditions de retry personnalisables
- Logging des tentatives
Gestion des Erreurs
try { const response = await AxiosService.get('/users'); } catch (error) { console.log(error.message); // Message d'erreur en français console.log(error.code); // Code d'erreur standardisé console.log(error.status); // Status HTTP console.log(error.timestamp); // Horodatage de l'erreur console.log(error.path); // Chemin de la requête }Codes d'État HTTP REST Complets
import { defines } from 'coddyger'; const { status } = defines; // Codes de Succès (2xx) status.requestOK; // 200 - Requête traitée avec succès status.created; // 201 - Ressource créée avec succès status.accepted; // 202 - Requête acceptée, traitement en cours status.noContent; // 204 - Requête traitée mais pas d'information à renvoyer // Codes de Redirection (3xx) status.movedPerm; // 301 - Redirection permanente status.found; // 302 - Redirection temporaire status.seeOther; // 303 - Voir autre (redirection vers une autre URI) status.notModified; // 304 - Contenu non modifié depuis la dernière requête status.tempRedirect; // 307 - Redirection temporaire (méthode HTTP préservée) status.permRedirect; // 308 - Redirection permanente (méthode HTTP préservée) // Codes d'Erreur Client (4xx) status.badRequest; // 400 - Syntaxe de la requête erronée status.authError; // 401 - Authentification nécessaire status.forbidden; // 403 - Accès refusé status.notFound; // 404 - Ressource non trouvée status.notAllowed; // 405 - Méthode HTTP non autorisée status.notAcceptable; // 406 - Format demandé non disponible status.conflict; // 409 - La requête conflicte avec l'état actuel status.gone; // 410 - La ressource n'est plus disponible status.lengthReq; // 411 - La longueur de contenu est requise status.precondFailed; // 412 - Précondition échouée status.payloadLarge; // 413 - Contenu trop volumineux status.uriTooLong; // 414 - URI trop longue status.unsupported; // 415 - Format de contenu non supporté status.rangeInvalid; // 416 - Plage demandée non satisfiable status.clientError; // 422 - Entité non traitable status.locked; // 423 - Ressource verrouillée status.tooEarly; // 425 - Trop tôt (anti-replay) status.tooMany; // 429 - Trop de requêtes status.headerLarge; // 431 - En-têtes trop grands status.legalReasons; // 451 - Indisponible pour raisons légales // Codes d'Erreur Serveur (5xx) status.serverError; // 500 - Erreur interne du serveur status.notImpl; // 501 - Fonctionnalité non implémentée status.badGateway; // 502 - Mauvaise réponse du serveur en amont status.unavailable; // 503 - Service temporairement indisponible status.gatewayTimeout;// 504 - Délai d'attente de la passerelle dépassé status.httpVersion; // 505 - Version HTTP non supportée status.variantAlso; // 506 - La négociation de contenu a échoué status.insuffStorage; // 507 - Espace insuffisant status.loopDetected; // 508 - Boucle détectée status.bandwidthLimit;// 509 - Limite de bande passante dépasséeMessages d'Erreur Standardisés par Code HTTP
const { message } = defines; // Messages pour les erreurs 4xx console.log(message.badRequest); // "La requête contient des erreurs de syntaxe" console.log(message.unauthorized); // "Authentification requise pour accéder à cette ressource" console.log(message.forbidden); // "Vous n'avez pas les droits nécessaires" console.log(message.notFound); // "La ressource demandée n'existe pas" console.log(message.methodNotAllowed); // "Cette méthode HTTP n'est pas autorisée" console.log(message.conflict); // "La ressource existe déjà ou conflit de version" console.log(message.tooMany); // "Vous avez dépassé la limite de requêtes autorisées" // Messages pour les erreurs 5xx console.log(message.serverError); // "Une erreur interne s'est produite" console.log(message.notImplemented);// "Cette fonctionnalité n'est pas encore disponible" console.log(message.unavailable); // "Le service est temporairement indisponible" // Messages génériques console.log(message.tryCatch); // "Une erreur imprévue s'est produite" console.log(message.validation); // "Les données fournies sont invalides" console.log(message.timeout); // "Le délai d'attente a été dépassé"Exemple d'Utilisation avec Gestion d'Erreur Complète
import { AxiosService, defines, LoggerService } from 'coddyger'; class APIService { async handleRequest(method: string, url: string, data?: any) { try { const response = await AxiosService[method](url, data, { retry: true, cache: method === 'get' }); return response.data; } catch (error) { switch (error.status) { case defines.status.authError: throw new Error("Votre session a expiré. Veuillez vous reconnecter."); case defines.status.forbidden: throw new Error("Vous n'avez pas les permissions nécessaires."); case defines.status.notFound: throw new Error(`La ressource ${url} n'existe pas.`); case defines.status.conflict: throw new Error("Cette opération crée un conflit avec les données existantes."); case defines.status.tooMany: const retryAfter = error.response?.headers['retry-after'] || 60; throw new Error(`Trop de requêtes. Réessayez dans ${retryAfter} secondes.`); case defines.status.clientError: throw new Error("Les données fournies sont invalides."); case defines.status.serverError: LoggerService.error("Erreur serveur", { method, url, error: error.message, stack: error.stack }); throw new Error("Une erreur serveur s'est produite. L'équipe technique a été notifiée."); default: throw error; } } } }Headers et Authentification
// Headers globaux AxiosService.setHeader('Accept-Language', 'fr-FR', 'common'); // Headers spécifiques par méthode AxiosService.setHeader('Content-Type', 'application/json', 'post'); AxiosService.setHeader('Authorization', 'Bearer token123', 'get'); // Suppression de headers AxiosService.removeHeader('Custom-Header', 'post');Logging et Traçabilité
- ID unique pour chaque requête
- Logging automatique des requêtes et réponses
- Masquage des données sensibles
- Intégration avec le système de logging
Configuration Flexible
const config = { baseURL: 'https://api.example.com', timeout: 30000, withCredentials: true, retryConfig: { maxRetries: 3, delayMs: 1000, retryCondition: (error) => error.response?.status >= 500 }, cacheConfig: { enabled: true, ttlMs: 300000 // 5 minutes } }; AxiosService.connect(config);Méthodes HTTP Supportées
// GET avec cache const users = await AxiosService.get('/users', { cache: true }); // POST avec retry const newUser = await AxiosService.post('/users', data, { retry: true }); // PUT avec configuration personnalisée const updatedUser = await AxiosService.put('/users/123', data, { retry: true, timeout: 5000 }); // DELETE avec retry await AxiosService.delete('/users/123', { retry: true }); // PATCH avec configuration const patchedUser = await AxiosService.patch('/users/123', data, { retry: true, headers: { 'Custom-Header': 'value' } });Gestion des Timeouts
// Timeout global AxiosService.connect({ baseURL: 'https://api.example.com', timeout: 30000 // 30 secondes }); // Timeout par requête const response = await AxiosService.get('/users', { timeout: 5000 // 5 secondes pour cette requête });
7. Méthodes Génériques DAO
Les DAO SQL (SequelizeDao) proposent des méthodes supplémentaires :
findByPk(id)findAll(options)increment(params, field, by)decrement(params, field, by)upsert(data, options)restore(params)
Ces méthodes sont facultatives côté Mongo (non implémentées par défaut).
Structure du Projet
src/
├── config/ # Configuration (Swagger, etc.)
├── controllers/ # Contrôleurs REST
├── data/ # Données statiques
├── database/ # Configuration et accès DB
│ ├── mongoose/ # Support MongoDB
│ └── sequelize/ # Support SQL
├── services/ # Services (Transporter, Logger)
├── types/ # Types TypeScript
├── coddyger.ts # Fonctionnalités principales
├── globals.ts # Variables globales
└── interface.ts # Interfaces TypeScriptExports
Toutes les classes et utilitaires principaux sont exportés par le module principal :
import {
LoggerService,
TransporterService,
AxiosService,
env,
defines,
LogLevel,
getDatabaseAccess,
MongoDbDao,
MongooseDataAccess,
SequelizeDataAccess,
MigrationManager, // <--- Ajouté
// etc.
} from 'coddyger';Scripts
npm start # Compile et exécute
npm run dev # Compile et exécute avec nodemon
npm run build # Compile TypeScriptDépendances Principales
- axios: ^1.x.x - Client HTTP
- bcrypt: ^5.x.x - Hachage de mots de passe
- date-fns: ^2.x.x - Manipulation de dates
- dotenv: ^16.x.x - Variables d'environnement
- kafkajs: ^2.x.x - Client Kafka
- mongoose: ^7.x.x - ODM MongoDB
- pino: ^8.x.x - Logger performant et structuré
- pino-pretty: ^10.x.x - Formatage des logs en développement
- sequelize: ^6.x.x - ORM SQL
- libphonenumber-js: ^1.x.x - Validation de numéros de téléphone
Licence
MIT
Auteur
Jordan Gnazalé
Support
For support, email [email protected] or create an issue in the GitHub repository.
