Saltearse al contenido

Guía de Plugins

Aprende a usar y crear plugins para Veloce.

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.

interface Plugin {
name: string;
version?: string;
dependencies?: string[];
install(app: Veloce): void | Promise<void>;
}

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 API
  • version: Versión de la API
  • description: Descripción de la API

Acceso:

  • Swagger UI: http://localhost:3000/docs
  • Especificación OpenAPI: http://localhost:3000/openapi.json

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)

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,
}));
import { Veloce, OpenAPIPlugin } from 'veloce-ts';
const app = new Veloce();
// Usar un solo plugin
app.usePlugin(new OpenAPIPlugin());
// Usar múltiples plugins
app.usePlugin(new OpenAPIPlugin());
app.usePlugin(new GraphQLPlugin());
const app = new Veloce({
plugins: [
new OpenAPIPlugin({
path: '/api-docs.json',
docsPath: '/api-docs',
}),
new GraphQLPlugin({
path: '/gql',
playground: process.env.NODE_ENV !== 'production',
}),
],
});
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 plugin
const app = new Veloce();
app.usePlugin(new HelloPlugin());
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ón
app.usePlugin(new LoggerPlugin({
level: 'info',
format: 'json',
}));
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 };
},
});
}
}
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
}));
// ✓ Bueno
class AuthenticationPlugin implements Plugin {
name = 'authentication-plugin';
}
// ✗ Malo
class MyPlugin implements Plugin {
name = 'plugin1';
}
class MyPlugin implements Plugin {
name = 'my-plugin';
version = '1.0.0';
}
/**
* 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) {}
}
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
}
}
// ✓ Bueno - Configurable
class LoggerPlugin implements Plugin {
constructor(private config: LoggerConfig) {}
}
// ✗ Malo - Hardcoded
class LoggerPlugin implements Plugin {
private level = 'info'; // Hardcoded
}