Guía de Plugins
Guía de Plugins
Sección titulada «Guía de Plugins»Aprende a usar y crear plugins para Veloce.
Tabla de Contenidos
Sección titulada «Tabla de Contenidos»- Introducción
- Plugins Integrados
- Usando Plugins
- Creando Plugins Personalizados
- Ejemplos de Plugins
- Mejores Prácticas
Introducción
Sección titulada «Introducción»El sistema de plugins de Veloce te permite extender el framework con funcionalidad adicional. Los plugins pueden agregar rutas, middleware, modificar la aplicación e integrarse con servicios externos.
Interfaz de Plugin
Sección titulada «Interfaz de Plugin»interface Plugin { name: string; version?: string; dependencies?: string[]; install(app: Veloce): void | Promise<void>;}Plugins Integrados
Sección titulada «Plugins Integrados»OpenAPIPlugin
Sección titulada «OpenAPIPlugin»Genera documentación OpenAPI automáticamente desde tus rutas.
import { Veloce, OpenAPIPlugin } from 'veloce-ts';
const app = new Veloce();
app.usePlugin(new OpenAPIPlugin({ path: '/openapi.json', docsPath: '/docs', title: 'Mi API', version: '1.0.0', description: 'Descripción de la API',}));Opciones:
path: Ruta para servir la especificación JSON de OpenAPI (por defecto:/openapi.json)docsPath: Ruta para servir Swagger UI (por defecto:/docs)title: Título de la APIversion: Versión de la APIdescription: Descripción de la API
Acceso:
- Swagger UI:
http://localhost:3000/docs - Especificación OpenAPI:
http://localhost:3000/openapi.json
GraphQLPlugin
Sección titulada «GraphQLPlugin»Habilita soporte para GraphQL con generación automática de esquemas.
import { Veloce, GraphQLPlugin } from 'veloce-ts';
const app = new Veloce();
app.usePlugin(new GraphQLPlugin({ path: '/graphql', playground: true, introspection: true,}));Opciones:
path: Ruta del endpoint GraphQL (por defecto:/graphql)playground: Habilitar GraphQL Playground (por defecto:true)introspection: Habilitar introspección de esquema (por defecto:true)
WebSocketPlugin
Sección titulada «WebSocketPlugin»Habilita soporte para WebSocket (incluido automáticamente).
import { Veloce, WebSocketPlugin } from 'veloce-ts';
const app = new Veloce();
app.usePlugin(new WebSocketPlugin({ path: '/ws', maxConnections: 1000,}));Usando Plugins
Sección titulada «Usando Plugins»Uso Básico
Sección titulada «Uso Básico»import { Veloce, OpenAPIPlugin } from 'veloce-ts';
const app = new Veloce();
// Usar un solo pluginapp.usePlugin(new OpenAPIPlugin());
// Usar múltiples pluginsapp.usePlugin(new OpenAPIPlugin());app.usePlugin(new GraphQLPlugin());Configuración de Plugins
Sección titulada «Configuración de Plugins»const app = new Veloce({ plugins: [ new OpenAPIPlugin({ path: '/api-docs.json', docsPath: '/api-docs', }), new GraphQLPlugin({ path: '/gql', playground: process.env.NODE_ENV !== 'production', }), ],});Creando Plugins Personalizados
Sección titulada «Creando Plugins Personalizados»Plugin Simple
Sección titulada «Plugin Simple»import { Plugin, Veloce } from 'veloce-ts';
class HelloPlugin implements Plugin { name = 'hello-plugin'; version = '1.0.0';
install(app: Veloce) { // Agregar una ruta app.get('/hello', { handler: async (c) => { return { message: '¡Hola desde el plugin!' }; }, });
console.log('HelloPlugin instalado'); }}
// Usar el pluginconst app = new Veloce();app.usePlugin(new HelloPlugin());Plugin con Configuración
Sección titulada «Plugin con Configuración»interface LoggerPluginConfig { level: 'debug' | 'info' | 'warn' | 'error'; format: 'json' | 'text';}
class LoggerPlugin implements Plugin { name = 'logger-plugin'; version = '1.0.0';
constructor(private config: LoggerPluginConfig) {}
install(app: Veloce) { // Agregar middleware de logging app.use(async (c, next) => { const start = Date.now();
await next();
const duration = Date.now() - start; const log = { method: c.req.method, url: c.req.url, status: c.res.status, duration: `${duration}ms`, };
if (this.config.format === 'json') { console.log(JSON.stringify(log)); } else { console.log(`${log.method} ${log.url} - ${log.status} (${log.duration})`); } }); }}
// Usar con configuraciónapp.usePlugin(new LoggerPlugin({ level: 'info', format: 'json',}));Ejemplos de Plugins
Sección titulada «Ejemplos de Plugins»Plugin de Autenticación
Sección titulada «Plugin de Autenticación»interface AuthPluginConfig { secret: string; expiresIn: string;}
class AuthPlugin implements Plugin { name = 'auth-plugin';
constructor(private config: AuthPluginConfig) {}
install(app: Veloce) { // Agregar servicio de autenticación class AuthService { generateToken(userId: string) { // Generar token JWT return 'token'; }
verifyToken(token: string) { // Verificar token JWT return { userId: '1' }; } }
app.getContainer().register(AuthService, { scope: 'singleton' });
// Agregar rutas de autenticación app.post('/auth/login', { handler: async (c) => { const { email, password } = await c.req.json(); // Validar credenciales const token = 'token-generado'; return { token }; }, }); }}Plugin de Rate Limiting
Sección titulada «Plugin de Rate Limiting»interface RateLimitConfig { windowMs: number; max: number;}
class RateLimitPlugin implements Plugin { name = 'rate-limit-plugin'; private requests = new Map<string, number[]>();
constructor(private config: RateLimitConfig) {}
install(app: Veloce) { app.use(async (c, next) => { const ip = c.req.header('x-forwarded-for') || 'unknown'; const now = Date.now();
// Obtener timestamps de peticiones para esta IP const timestamps = this.requests.get(ip) || [];
// Remover timestamps antiguos const validTimestamps = timestamps.filter( t => now - t < this.config.windowMs );
// Verificar si se excedió el límite if (validTimestamps.length >= this.config.max) { return c.json({ error: 'Demasiadas peticiones' }, 429); }
// Agregar timestamp actual validTimestamps.push(now); this.requests.set(ip, validTimestamps);
await next(); }); }}
app.usePlugin(new RateLimitPlugin({ windowMs: 15 * 60 * 1000, // 15 minutos max: 100, // 100 peticiones por ventana}));Mejores Prácticas
Sección titulada «Mejores Prácticas»1. Usa Nombres Descriptivos
Sección titulada «1. Usa Nombres Descriptivos»// ✓ Buenoclass AuthenticationPlugin implements Plugin { name = 'authentication-plugin';}
// ✗ Maloclass MyPlugin implements Plugin { name = 'plugin1';}2. Versiona tus Plugins
Sección titulada «2. Versiona tus Plugins»class MyPlugin implements Plugin { name = 'my-plugin'; version = '1.0.0';}3. Documenta las Opciones de Configuración
Sección titulada «3. Documenta las Opciones de Configuración»/** * Opciones de configuración para CachePlugin */interface CachePluginConfig { /** Tiempo de vida en segundos */ ttl: number; /** Número máximo de elementos en caché */ maxSize: number; /** Prefijo de clave de caché */ prefix?: string;}
class CachePlugin implements Plugin { constructor(private config: CachePluginConfig) {}}4. Maneja Errores Apropiadamente
Sección titulada «4. Maneja Errores Apropiadamente»class MyPlugin implements Plugin { name = 'my-plugin';
async install(app: Veloce) { try { await this.initialize(); } catch (error) { console.error(`Falló la inicialización de ${this.name}:`, error); throw error; } }
private async initialize() { // Lógica de inicialización }}5. Haz los Plugins Configurables
Sección titulada «5. Haz los Plugins Configurables»// ✓ Bueno - Configurableclass LoggerPlugin implements Plugin { constructor(private config: LoggerConfig) {}}
// ✗ Malo - Hardcodedclass LoggerPlugin implements Plugin { private level = 'info'; // Hardcoded}Próximos Pasos
Sección titulada «Próximos Pasos»- Lee la Guía de Pruebas
- Revisa la Guía de Inicio
- Aprende sobre Inyección de Dependencias