@hemia/error-handler
v0.0.3
Published
Hemia Error Handler
Readme
@hemia/error-handler
Librería flexible para gestionar códigos de error a través de los sistemas de Hemia. Soporta errores de bases de datos (MySQL, PostgreSQL, MongoDB), errores comunes, y permite agregar errores personalizados con traducciones en múltiples idiomas.
📦 Instalación
Instala el paquete desde NPM:
NPM
npm install @hemia/error-handler
# o con bun
bun install @hemia/error-handler🚀 Características
- ✅ Soporte para errores de bases de datos (MySQL, PostgreSQL, MongoDB)
- ✅ Gestión de errores comunes de aplicación
- ✅ Sistema de internacionalización (i18n) integrado
- ✅ Estructuras anidadas con dot notation (
schema_error.field_required) - ✅ Interpolación de parámetros con
{{param}} - ✅ Soporte para errores personalizados sin dependencia de BD
- ✅ Mapeos dinámicos de errores en tiempo de ejecución
- ✅ Múltiples idiomas (en, es, y personalizados)
- ✅ TypeScript con tipos completos
- ✅ API flexible con múltiples formas de uso
📖 Uso Básico
1. Con Base de Datos (Modo Clásico)
import { ErrorHandler, dbEnum, langEnum } from '@hemia/error-handler';
// Constructor simple
const handler = new ErrorHandler(dbEnum.mysql, langEnum.es);
// Obtener mensaje de error
const error = handler.getErrorMessage('1062'); // MySQL duplicate key error
console.log(error);
// {
// message: 'Entrada duplicada',
// messageDev: 'Duplicate entry for key',
// code: '1062',
// status: 409
// }2. Estructuras Anidadas con Dot Notation
import { ErrorHandler, langEnum } from '@hemia/error-handler';
const handler = new ErrorHandler({
lang: langEnum.es,
customLocales: {
'en': {
schema_error: {
field_must_be_text: {
message: "Field must be text.",
messageDev: "The field must be of type text",
status: 400
},
field_min_length: {
message: "Minimum length is {{length}} characters.",
messageDev: "The field does not meet the minimum length requirement of {{length}} characters",
status: 400
},
validation: {
email: {
invalid_format: {
message: "Invalid email format.",
messageDev: "Email field does not comply with RFC 5322 format",
status: 400
}
}
}
}
},
'es': {
schema_error: {
field_must_be_text: {
message: "El campo debe de ser texto.",
messageDev: "El campo debe ser de tipo texto",
status: 400
},
field_min_length: {
message: "El mínimo de caracteres es {{length}}.",
messageDev: "El campo no cumple con el requerimiento de longitud mínima de {{length}} caracteres",
status: 400
},
validation: {
email: {
invalid_format: {
message: "El formato del email es inválido.",
messageDev: "El campo email no cumple con el formato RFC 5322",
status: 400
}
}
}
}
}
}
});
// Uso con dot notation (sin parámetros)
const error1 = handler.getErrorMessage('schema_error.field_must_be_text');
console.log(error1);
// { message: "El campo debe de ser texto.", messageDev: "...", status: 400 }
// Con parámetros de interpolación (sin necesidad de pasar null para lang)
const error2 = handler.getErrorMessage('schema_error.field_min_length', { length: 5 });
console.log(error2);
// { message: "El mínimo de caracteres es 5.", messageDev: "... 5 caracteres", status: 400 }
// Muy anidado
const error3 = handler.getErrorMessage('schema_error.validation.email.invalid_format');
console.log(error3);
// { message: "El formato del email es inválido.", ... }
// Con idioma específico
const error4 = handler.getErrorMessage('schema_error.field_must_be_text', langEnum.en);
console.log(error4);
// { message: "Field must be text.", ... }
// Con idioma y parámetros
const error5 = handler.getErrorMessage('schema_error.field_min_length', langEnum.en, { length: 10 });
console.log(error5);
// { message: "Minimum length is 10 characters.", ... }3. Sin Base de Datos (Solo Errores Personalizados)
import { ErrorHandler, langEnum } from '@hemia/error-handler';
const handler = new ErrorHandler({
lang: langEnum.es,
customLocales: {
'en': {
'VALIDATION_ERROR': {
message: 'Validation failed',
messageDev: 'Input validation failed. Check required fields.',
status: 400
},
'AUTH_ERROR': {
message: 'Authentication failed',
messageDev: 'Invalid credentials provided',
status: 401
}
},
'es': {
'VALIDATION_ERROR': {
message: 'Error de validación',
messageDev: 'La validación de entrada falló. Revise los campos requeridos.',
status: 400
},
'AUTH_ERROR': {
message: 'Autenticación fallida',
messageDev: 'Credenciales inválidas proporcionadas',
status: 401
}
}
},
customErrorMappings: {
'ERR_VAL_001': 'VALIDATION_ERROR',
'ERR_AUTH_001': 'AUTH_ERROR'
}
});
const error = handler.getErrorMessage('ERR_VAL_001');
console.log(error);
// {
// message: 'Error de validación',
// messageDev: 'La validación de entrada falló...',
// code: 'ERR_VAL_001',
// status: 400
// }4. Modo Híbrido (BD + Errores Personalizados)
import { ErrorHandler, dbEnum, langEnum } from '@hemia/error-handler';
const handler = new ErrorHandler({
dbType: dbEnum.postgres,
lang: langEnum.en,
customLocales: {
'en': {
'BUSINESS_RULE_VIOLATION': {
message: 'Business rule violation',
messageDev: 'The operation violates business rules',
status: 422
}
}
},
customErrorMappings: {
'BIZ_001': 'BUSINESS_RULE_VIOLATION'
}
});
// Maneja errores de PostgreSQL
const dbError = handler.getErrorMessage('23505'); // Unique violation
// Maneja errores personalizados
const bizError = handler.getErrorMessage('BIZ_001');🎯 API Avanzada
Formas de Usar getErrorMessage()
El método getErrorMessage tiene múltiples sobrecargas para máxima flexibilidad:
// 1. Solo código de error (usa idioma por defecto de la instancia)
handler.getErrorMessage('schema_error.field_required');
// 2. Código + parámetros (sin necesidad de pasar null)
handler.getErrorMessage('schema_error.field_min_length', { length: 5 });
// 3. Código + idioma específico
handler.getErrorMessage('schema_error.field_required', langEnum.en);
// 4. Código + idioma + parámetros
handler.getErrorMessage('schema_error.field_min_length', langEnum.en, { length: 10 });Métodos de Instancia
getErrorMessage(errorCode, langOrParams?, params?): ErrorMessage
Obtiene el mensaje de error traducido con soporte para:
- Dot notation para estructuras anidadas
- Interpolación de parámetros con
{{param}} - Sobrecarga flexible sin necesidad de valores
null
// Estructura anidada con parámetros
const error = handler.getErrorMessage('schema_error.field_min_length', { length: 5 });
console.log(error.message); // "El mínimo de caracteres es 5."addErrorMappings(mappings: { [key: string]: string }): void
Agrega mapeos de errores dinámicamente.
handler.addErrorMappings({
'APP_001': 'VALIDATION_ERROR',
'APP_002': 'AUTH_ERROR'
});clearErrorMappings(): void
Limpia todos los mapeos personalizados.
handler.clearErrorMappings();getErrorMappings(): { [key: string]: string }
Obtiene los mapeos actuales.
const mappings = handler.getErrorMappings();setLanguage(lang: langEnum): void
Cambia el idioma de la instancia.
handler.setLanguage(langEnum.es);getLanguage(): string
Obtiene el idioma actual de la instancia.
const currentLang = handler.getLanguage();Funciones Globales de i18n
registerLocale(lang: string, locale: any): void
Registra o fusiona traducciones para un idioma. Soporta estructuras anidadas.
import { registerLocale } from '@hemia/error-handler';
// Estructura plana
registerLocale('fr', {
'VALIDATION_ERROR': {
message: 'Erreur de validation',
messageDev: 'La validation a échoué',
status: 400
}
});
// Estructura anidada
registerLocale('de', {
schema_error: {
field_required: {
message: 'Feld ist erforderlich',
messageDev: 'Required field missing',
status: 400
},
field_min_length: {
message: 'Mindestlänge ist {{length}} Zeichen',
messageDev: 'Field does not meet minimum length of {{length}}',
status: 400
}
}
});setLocale(lang: string, locale: any): void
Reemplaza completamente las traducciones de un idioma.
import { setLocale } from '@hemia/error-handler';
setLocale('es', {
'ERROR_001': { message: 'Error 1', messageDev: 'Dev msg' }
});setLanguage(lang: string): void
Cambia el idioma global por defecto.
import { setLanguage } from '@hemia/error-handler';
setLanguage('es');getCurrentLanguage(): string
Obtiene el idioma global actual.
import { getCurrentLanguage } from '@hemia/error-handler';
const lang = getCurrentLanguage(); // 'en'getAvailableLanguages(): string[]
Obtiene todos los idiomas disponibles.
import { getAvailableLanguages } from '@hemia/error-handler';
const languages = getAvailableLanguages(); // ['en', 'es', 'fr']🌍 Ejemplo Completo: Aplicación Multiidioma con Estructuras Anidadas
import { ErrorHandler, langEnum, registerLocale } from '@hemia/error-handler';
// 1. Registrar estructura anidada para francés
registerLocale('fr', {
schema_error: {
field_required: {
message: 'Le champ est requis',
messageDev: 'Required field missing',
status: 400
},
field_min_length: {
message: 'Longueur minimale est {{length}} caractères',
messageDev: 'Field does not meet minimum length of {{length}}',
status: 400
}
}
});
// 2. Crear handler con estructura anidada compleja
const handler = new ErrorHandler({
lang: langEnum.en,
customLocales: {
'en': {
user: {
not_found: {
message: 'User not found',
messageDev: 'The requested user does not exist in the database',
status: 404
},
account: {
suspended: {
message: 'Account is suspended',
messageDev: 'User account has been suspended by administrator',
status: 403
},
expired: {
message: 'Account has expired',
messageDev: 'User subscription expired on {{date}}',
status: 403
}
}
},
payment: {
insufficient_funds: {
message: 'Insufficient funds',
messageDev: 'Account balance is {{balance}}, required {{required}}',
status: 402
}
}
},
'es': {
user: {
not_found: {
message: 'Usuario no encontrado',
messageDev: 'El usuario solicitado no existe en la base de datos',
status: 404
},
account: {
suspended: {
message: 'Cuenta suspendida',
messageDev: 'La cuenta del usuario ha sido suspendida por el administrador',
status: 403
},
expired: {
message: 'Cuenta expirada',
messageDev: 'La suscripción del usuario expiró el {{date}}',
status: 403
}
}
},
payment: {
insufficient_funds: {
message: 'Fondos insuficientes',
messageDev: 'El saldo de la cuenta es {{balance}}, se requiere {{required}}',
status: 402
}
}
}
},
customErrorMappings: {
'USR_404': 'user.not_found',
'USR_SUSPENDED': 'user.account.suspended',
'USR_EXPIRED': 'user.account.expired',
'PAY_001': 'payment.insufficient_funds'
}
});
// 3. Uso con diferentes niveles de anidación
// Simple
const error1 = handler.getErrorMessage('user.not_found');
console.log(error1);
// { message: 'User not found', status: 404, ... }
// Anidado 2 niveles
const error2 = handler.getErrorMessage('user.account.suspended', langEnum.es);
console.log(error2);
// { message: 'Cuenta suspendida', status: 403, ... }
// Con parámetros
const error3 = handler.getErrorMessage('user.account.expired', { date: '2025-01-15' });
console.log(error3);
// { message: 'Account has expired', messageDev: 'User subscription expired on 2025-01-15', ... }
// Con idioma y parámetros
const error4 = handler.getErrorMessage(
'payment.insufficient_funds',
langEnum.es,
{ balance: 50, required: 100 }
);
console.log(error4);
// { message: 'Fondos insuficientes', messageDev: 'El saldo de la cuenta es 50, se requiere 100', ... }
// Usando mapeos personalizados
const error5 = handler.getErrorMessage('USR_SUSPENDED');
console.log(error5);
// { message: 'Account is suspended', ... }
// 4. Agregar mapeos dinámicamente
handler.addErrorMappings({
'CUSTOM_001': 'user.account.expired'
});
// 5. Cambiar idioma de la instancia
handler.setLanguage(langEnum.es);
const error6 = handler.getErrorMessage('CUSTOM_001', { date: '2025-12-31' });
console.log(error6);
// { message: 'Cuenta expirada', messageDev: 'La suscripción del usuario expiró el 2025-12-31', ... }🔧 Express/Fastify Middleware Example
import { ErrorHandler, dbEnum, langEnum } from '@hemia/error-handler';
import { Request, Response, NextFunction } from 'express';
const errorHandler = new ErrorHandler({
dbType: dbEnum.postgres,
lang: langEnum.es,
customLocales: {
'es': {
'INTERNAL_ERROR': {
message: 'Error interno del servidor',
messageDev: 'An unexpected error occurred',
status: 500
}
}
}
});
// Middleware de manejo de errores
export function errorMiddleware(
err: any,
req: Request,
res: Response,
next: NextFunction
) {
const lang = req.headers['accept-language']?.includes('es')
? langEnum.es
: langEnum.en;
const errorCode = err.code || 'INTERNAL_ERROR';
const errorMessage = errorHandler.getErrorMessage(errorCode, lang);
res.status(errorMessage.status || 500).json({
success: false,
error: {
message: errorMessage.message,
code: errorMessage.code,
...(process.env.NODE_ENV === 'development' && {
messageDev: errorMessage.messageDev
})
}
});
}📝 Tipos TypeScript
interface ErrorMessage {
message: string;
messageDev?: string;
code?: string;
status?: number;
params?: { [key: string]: string | number };
}
interface ErrorHandlerOptions {
dbType?: dbEnum;
lang?: langEnum;
customLocales?: { [lang: string]: any }; // Soporta estructuras anidadas
customErrorMappings?: { [key: string]: string };
}
enum dbEnum {
mysql = 'mysql',
postgres = 'postgres',
mongo = 'mongo'
}
enum langEnum {
en = 'en',
es = 'es'
}🔑 Interpolación de Parámetros
La librería soporta interpolación de parámetros usando la sintaxis {{param}}:
// En el locale
{
'field_min_length': {
message: "El mínimo es {{length}} caracteres",
messageDev: "Minimum length is {{length}}"
}
}
// Uso
const error = handler.getErrorMessage('field_min_length', { length: 5 });
console.log(error.message); // "El mínimo es 5 caracteres"Múltiples parámetros
{
'date_range_error': {
message: "La fecha debe estar entre {{start}} y {{end}}",
messageDev: "Date must be between {{start}} and {{end}}"
}
}
const error = handler.getErrorMessage('date_range_error', {
start: '2025-01-01',
end: '2025-12-31'
});
// message: "La fecha debe estar entre 2025-01-01 y 2025-12-31"🎨 Prioridad de Búsqueda de Errores
El sistema busca errores en el siguiente orden:
- Mapeos personalizados (
customErrorMappings) - Errores de BD (si
dbTypeestá definido) - Errores comunes (definidos internamente)
- Fallback (devuelve el código como mensaje)
📄 Licencia
ISC
🤝 Contribuciones
Para contribuir al proyecto, por favor contacta al equipo de Hemia
