Referencia API
Referencia API
Sección titulada «Referencia API»Referencia API completa para el framework Veloce-TS.
Tabla de Contenidos
Sección titulada «Tabla de Contenidos»- Clases Principales
- Decoradores
- Sistema de Plugins
- Integración Drizzle ORM
- Utilidades de Prueba
- Clases de Error
- Tipos
- Nuevo en v2.0.0
Clases Principales
Sección titulada «Clases Principales»VeloceTS / Veloce
Sección titulada «VeloceTS / Veloce»Clase principal de la aplicación. Veloce es un alias exportado de VeloceTS (la misma clase).
Constructor
Sección titulada «Constructor»new VeloceTS(config?: VeloceTSConfig)// equivalente: new Veloce(config?: VeloceTSConfig)Parámetros:
config(opcional): Objeto de configuración
Interfaz VeloceTSConfig:
interface VeloceTSConfig { adapter?: 'hono' | 'express' | 'native'; title?: string; version?: string; description?: string; /** * Monta la documentación OpenAPI. `true` (por defecto) sirve el spec en * `/openapi.json` y Swagger UI en `/docs`. Pasa un objeto para cambiar esas * rutas, o `false` para desactivarlo. Se ignora si registras un plugin * `openapi` a mano. Antes de 3.0.0 esta opción se aceptaba y se ignoraba. */ docs?: boolean | { path?: string; openapi?: string }; cors?: CorsOptions | boolean; /** Plugins registrados al construir (equivale a llamar `usePlugin`). */ plugins?: Plugin[]; /** * Tamaño máximo del cuerpo de la petición en bytes. Los cuerpos mayores se * rechazan con 413 antes de que corra ningún handler. Por defecto 1 MiB; `0` * desactiva el límite. Añadido en 3.0.0 — súbelo si aceptas subidas de archivos. */ bodyLimit?: number; /** `rfc9457` (defecto desde v0.4.3) o `legacy` */ errorResponseFormat?: 'rfc9457' | 'legacy';}Ejemplo:
const app = new Veloce({ title: 'Mi API', version: '1.0.0', description: 'API para mi aplicación', docs: true, cors: true,});Métodos Principales
Sección titulada «Métodos Principales»include(controller: Class): void
Sección titulada «include(controller: Class): void»Registra una clase controlador con la aplicación.
@Controller('/users')class UserController { @Get('/') async list() { return []; }}
app.include(UserController);get/post/put/delete/patch(path: string, config: RouteConfig): void
Sección titulada «get/post/put/delete/patch(path: string, config: RouteConfig): void»Registra rutas usando la API funcional.
app.get('/users', { handler: async (c) => { return [{ id: 1, name: 'John' }]; },});usePlugin(plugin: Plugin): void
Sección titulada «usePlugin(plugin: Plugin): void»Registra un plugin con la aplicación.
import { OpenAPIPlugin } from 'veloce-ts';
app.usePlugin(new OpenAPIPlugin({ path: '/openapi.json', docsPath: '/docs',}));listen(port: number, callback?: () => void): Promise<ServerInstance>
Sección titulada «listen(port: number, callback?: () => void): Promise<ServerInstance>»Inicia el servidor en el puerto especificado.
app.listen(3000, () => { console.log('Servidor ejecutándose en http://localhost:3000');});getContainer(): DIContainer
Sección titulada «getContainer(): DIContainer»Obtiene el contenedor de inyección de dependencias.
const container = app.getContainer();container.register(DatabaseService, { scope: 'singleton' });Decoradores
Sección titulada «Decoradores»Decoradores de Clase
Sección titulada «Decoradores de Clase»@Controller(prefix?: string)
Sección titulada «@Controller(prefix?: string)»Marca una clase como controlador y opcionalmente establece un prefijo de ruta.
@Controller('/api/users')class UserController { @Get('/') async list() { return []; }}@WebSocket(path: string)
Sección titulada «@WebSocket(path: string)»Marca una clase como manejador de WebSocket.
@WebSocket('/chat')class ChatHandler { @OnConnect() handleConnect(client: WebSocketConnection) { console.log('Conectado'); }}@Resolver()
Sección titulada «@Resolver()»Marca una clase como resolver de GraphQL.
@Resolver()class UserResolver { @GQLQuery() async users() { return []; }}Decoradores de Método
Sección titulada «Decoradores de Método»Decoradores de Métodos HTTP
Sección titulada «Decoradores de Métodos HTTP»@Get(path?: string)- Registra una ruta GET@Post(path?: string)- Registra una ruta POST@Put(path?: string)- Registra una ruta PUT@Delete(path?: string)- Registra una ruta DELETE@Patch(path?: string)- Registra una ruta PATCH@All(path?: string)- Responde a todos los métodos HTTP
Ejemplo:
@Get('/users')async getUsers() { return [];}
@Post('/users')async createUser(@Body(UserSchema) user: User) { return user;}Decoradores de GraphQL
Sección titulada «Decoradores de GraphQL»@GQLQuery()- Define una consulta GraphQL. No es@Query(): ese es el decorador de parámetros de query HTTP, y un resolver decorado con él nunca se convierte en un campo GraphQL.@Mutation()- Define una mutación GraphQL@Subscription()- Define una suscripción GraphQL
Decoradores de WebSocket
Sección titulada «Decoradores de WebSocket»@OnConnect()- Maneja eventos de conexión@OnMessage(schema?: ZodSchema)- Maneja eventos de mensaje@OnDisconnect()- Maneja eventos de desconexión
Decoradores de Parámetro
Sección titulada «Decoradores de Parámetro»@Body(schema?: ZodSchema)
Sección titulada «@Body(schema?: ZodSchema)»Extrae y valida el cuerpo de la petición.
const UserSchema = z.object({ name: z.string().min(2), email: z.string().email(),});
@Post('/users')async createUser(@Body(UserSchema) user: z.infer<typeof UserSchema>) { return user;}@Query(schema?: ZodSchema)
Sección titulada «@Query(schema?: ZodSchema)»Extrae y valida parámetros de consulta.
const SearchSchema = z.object({ q: z.string(), page: z.string().transform(Number).default('1'),});
@Get('/search')async search(@Query(SearchSchema) query: z.infer<typeof SearchSchema>) { return { query: query.q, page: query.page };}@Param(name?: string)
Sección titulada «@Param(name?: string)»Extrae parámetros de ruta.
@Get('/users/:id')async getUser(@Param('id') id: string) { return { id };}@Header(name?: string, schema?: ZodSchema)
Sección titulada «@Header(name?: string, schema?: ZodSchema)»Extrae y valida encabezados.
@Get('/protected')async getProtected(@Header('authorization') auth: string) { return { auth };}@Cookie(name?: string, schema?: ZodSchema)
Sección titulada «@Cookie(name?: string, schema?: ZodSchema)»Extrae y valida cookies.
@Get('/profile')async getProfile(@Cookie('session') sessionId: string) { return { sessionId };}Inyecta el contexto de Hono (Context). Para el Request estándar de la Web API, usa c.req.raw.
import type { Context } from 'hono';
@Post('/echo')async echo(@Ctx() c: Context) { return await c.req.json();}Inyecta el objeto de petición de Hono (c.req). Se exporta desde veloce-ts. Para el Request (Fetch API), usa @Ctx() y c.req.raw.
@Get('/path')path(@Req() req: import('hono').HonoRequest) { return { path: req.path };}@Depends(provider: Provider, scope?: Scope)
Sección titulada «@Depends(provider: Provider, scope?: Scope)»Inyecta dependencias.
class UserService { async getUsers() { return []; }}
@Controller('/users')class UserController { @Get('/') async list(@Depends(UserService) userService: UserService) { return await userService.getUsers(); }}Sistema de Plugins
Sección titulada «Sistema de Plugins»Interfaz de Plugin
Sección titulada «Interfaz de Plugin»interface Plugin { name: string; version?: string; dependencies?: string[]; install(app: VeloceTS): void | Promise<void>;}Creando un Plugin
Sección titulada «Creando un Plugin»class MyPlugin implements Plugin { name = 'my-plugin'; version = '1.0.0';
install(app: VeloceTS) { // Agregar rutas app.get('/plugin-route', { handler: async (c) => { return { message: 'Desde el plugin' }; }, }); }}Plugins Integrados
Sección titulada «Plugins Integrados»OpenAPIPlugin
Sección titulada «OpenAPIPlugin»import { OpenAPIPlugin } from 'veloce-ts';
app.usePlugin(new OpenAPIPlugin({ path: '/openapi.json', docsPath: '/docs', title: 'Mi API', version: '1.0.0',}));GraphQLPlugin
Sección titulada «GraphQLPlugin»import { GraphQLPlugin } from 'veloce-ts';
app.usePlugin(new GraphQLPlugin({ path: '/graphql', playground: true,}));Integración Drizzle ORM
Sección titulada «Integración Drizzle ORM»Conecta Drizzle (u otro ORM) al contenedor de inyección de dependencias.
registerDrizzle(app, db, token?)
Sección titulada «registerDrizzle(app, db, token?)»Registra una instancia de base de datos como singleton en el DIContainer.
Parámetros:
app: Instancia de la aplicación VeloceTSdb: Instancia de la base de datos (Drizzle u otro ORM)token(opcional): Token de inyección personalizado (por defectoDB_TOKEN)
Ejemplo:
import { registerDrizzle } from 'veloce-ts';import { drizzle } from 'drizzle-orm/bun-sqlite';
const db = drizzle(new Database('mi-base.db'));registerDrizzle(app, db);@InjectDB(token?)
Sección titulada «@InjectDB(token?)»Decorador de parámetro que inyecta la instancia de base de datos registrada. Es un alias de @Depends(DB_TOKEN).
Ejemplo:
import { InjectDB } from 'veloce-ts';
@Controller('/productos')class ProductoController { @Get('/') async listar(@InjectDB() db: typeof drizzleDb) { return await db.select().from(productos); }
@Post('/') @HttpCode(201) async crear( @Body(CreateProductoSchema) data: any, @InjectDB() db: typeof drizzleDb ) { return await db.insert(productos).values(data).returning(); }}DB_TOKEN
Sección titulada «DB_TOKEN»Símbolo por defecto usado como token de inyección para la instancia de base de datos.
Utilidades de Prueba
Sección titulada «Utilidades de Prueba»createTestApp(config?: VeloceTSConfig): VeloceTS
Sección titulada «createTestApp(config?: VeloceTSConfig): VeloceTS»Crea una instancia de prueba de la aplicación.
import { createTestApp } from 'veloce-ts/testing';
const app = createTestApp();app.include(UserController);TestClient
Sección titulada «TestClient»Cliente HTTP para hacer peticiones de prueba con una API de aserciones fluente.
Métodos de petición:
get(path, options?),post(path, body?, options?),put(path, body?, options?),delete(path, options?),patch(path, body?, options?)
Helpers de autenticación:
withToken(token)— instancia inmutable conAuthorization: Bearer <token>pre-establecidowithHeaders(headers)— instancia inmutable con headers adicionalesloginAs(credentials, endpoint?)— hace login y devuelve un cliente autenticadoregisterAndLogin(user, endpoints?)— registra y hace login en una sola llamadaclearAuth()— limpia el token almacenado
TestResponse
Sección titulada «TestResponse»Envoltorio de respuesta con métodos de aserción encadenables.
Propiedades: status, ok, headers, body, text
Métodos de aserción:
expectStatus(code),expectOk(),expectCreated(),expectNotFound(),expectUnauthorized()expectJson(partialObject)— verificación parcial del bodyexpectField(field, value?)— verificar un campo específicoexpectHeader(name, value?)— verificar un header de respuestaexpectArrayLength(n)— verificar longitud de array
import { TestClient } from 'veloce-ts/testing';
const client = new TestClient(app);
// Aserciones fluentesconst response = await client.get('/usuarios');await response.expectOk().expectArrayLength(2);
// Helper de autenticaciónconst authClient = await client.loginAs({ email: 'usuario@ejemplo.com', password: 'contraseña123'});await authClient.get('/perfil').then(r => r.expectOk());
// Aserciones encadenadasconst res = await client.post('/productos', { nombre: 'Producto A', precio: 29.99 });await res.expectCreated().expectField('id').expectJson({ nombre: 'Producto A' });mockDependency(provider: Class, mock: any): void
Sección titulada «mockDependency(provider: Class, mock: any): void»Simula una dependencia en el contenedor DI.
import { mockDependency } from 'veloce-ts/testing';
const mockUserService = { getUsers: async () => [{ id: 1, name: 'Prueba' }],};
mockDependency(UserService, mockUserService);Clases de Error
Sección titulada «Clases de Error»HTTPException
Sección titulada «HTTPException»Clase de excepción base para errores HTTP.
import { HTTPException } from 'veloce-ts';
@Get('/users/:id')async getUser(@Param('id') id: string) { const user = await db.getUserById(id);
if (!user) { throw new HTTPException(404, 'Usuario no encontrado'); }
return user;}ValidationException
Sección titulada «ValidationException»Excepción para errores de validación (422). La respuesta incluye detalles estructurados con field, message, code, y opcionalmente received, expected, minimum, maximum.
import { ValidationException } from 'veloce-ts';throw new ValidationException([{ path: 'email', message: 'Email inválido' }]);NotFoundException
Sección titulada «NotFoundException»Excepción para recursos no encontrados (404).
import { NotFoundException } from 'veloce-ts';throw new NotFoundException('Usuario no encontrado');UnauthorizedException
Sección titulada «UnauthorizedException»Excepción para errores de autenticación (401).
import { UnauthorizedException } from 'veloce-ts';throw new UnauthorizedException('Credenciales inválidas');ForbiddenException
Sección titulada «ForbiddenException»Excepción para acceso prohibido (403).
import { ForbiddenException } from 'veloce-ts';throw new ForbiddenException('Acceso denegado');ConflictException
Sección titulada «ConflictException»Excepción para conflictos de datos (409).
import { ConflictException } from 'veloce-ts';throw new ConflictException('El email ya está registrado');GoneException
Sección titulada «GoneException»Excepción para recursos eliminados permanentemente (410).
import { GoneException } from 'veloce-ts';throw new GoneException('Este recurso ya no existe');PayloadTooLargeException
Sección titulada «PayloadTooLargeException»Excepción para cuerpos de petición demasiado grandes (413).
import { PayloadTooLargeException } from 'veloce-ts';throw new PayloadTooLargeException('El archivo supera el límite de 10MB');UnprocessableEntityException
Sección titulada «UnprocessableEntityException»Excepción para fallos de validación semántica (422).
import { UnprocessableEntityException } from 'veloce-ts';throw new UnprocessableEntityException('La edad debe ser mayor de 18 años');TooManyRequestsException
Sección titulada «TooManyRequestsException»Excepción para límite de peticiones excedido (429).
import { TooManyRequestsException } from 'veloce-ts';throw new TooManyRequestsException('Demasiadas peticiones. Intenta de nuevo en 1 minuto.');ServiceUnavailableException
Sección titulada «ServiceUnavailableException»Excepción para servicio no disponible (503).
import { ServiceUnavailableException } from 'veloce-ts';throw new ServiceUnavailableException('La base de datos no está disponible temporalmente');VeloceTSConfig
Sección titulada «VeloceTSConfig»interface VeloceTSConfig { adapter?: 'hono' | 'express' | 'native'; title?: string; version?: string; description?: string; docs?: boolean | { path?: string; openapi?: string }; cors?: CorsOptions | boolean; errorResponseFormat?: 'rfc9457' | 'legacy';}Los plugins se registran con app.usePlugin(new AlgunPlugin()); no existe el campo plugins: [] en esta configuración.
Middleware
Sección titulada «Middleware»type Middleware = (c: Context, next: () => Promise<void>) => Promise<void> | void;type Scope = 'singleton' | 'request' | 'transient';WebSocketConnection
Sección titulada «WebSocketConnection»interface WebSocketConnection { id: string; send(data: any): void; broadcast(data: any, includeSelf?: boolean): void; join(room: string): void; leave(room: string): void; close(): void;}Nuevo en v2.0.0
Sección titulada «Nuevo en v2.0.0»Referencia rápida de las APIs añadidas o cambiadas en v2.0.0. Los cambios incompatibles están marcados.
Aplicación
Sección titulada «Aplicación»| API | Notas |
|---|---|
await app.getFetchHandler() | Devuelve un handler fetch(request, env, ctx). Es la vía soportada para desplegar en Cloudflare Workers — listen() lanza en workerd. Compila las rutas automáticamente en la primera llamada. También sirve con Bun.serve({ fetch }) / Deno.serve(). |
await app.shutdown() | Ahora también ejecuta los handlers registrados con onShutdown() y los hooks onStop() de los plugins (antes solo cerraba el servidor). |
// worker.ts — Cloudflare Workersconst app = new Veloce({ title: 'My API' });app.get('/hello', { handler: () => ({ message: 'hi' }) });
export default { fetch: await app.getFetchHandler() };Rutas funcionales tipadas — RouteConfig<S>
Sección titulada «Rutas funcionales tipadas — RouteConfig<S>»app.get/post/put/delete/patch y app.route() son genéricos sobre el conjunto de schemas declarado, así que los argumentos del handler se infieren. El orden de inyección es body, query, params, headers; solo los schemas declarados aportan un argumento.
app.post('/users', { schema: { body: CreateUserSchema, query: QuerySchema }, handler: async (c, body, query) => body.name, // ambos completamente tipados});Tipos de apoyo: RouteSchemas, SchemaArgs<S>.
Controladores
Sección titulada «Controladores»| API | Notas |
|---|---|
@Controller(prefix, { scope }) | 'singleton' (nuevo valor por defecto) | 'request' | 'transient'. |
Autenticación
Sección titulada «Autenticación»| API | Notas |
|---|---|
Métodos de verificación/revocación de JWTProvider | Incompatible — ahora async: verifyAccessToken, verifyRefreshToken, refreshAccessToken, blacklistToken, isBlacklisted, cleanupBlacklist. |
JWTConfig.blacklist | Una implementación de TokenBlacklist. Por defecto MemoryTokenBlacklist. |
MemoryTokenBlacklist / RedisTokenBlacklist | Exportados desde veloce-ts/auth. Usa el store Redis para propagar la revocación entre réplicas. |
JWTConfig.privateKey / publicKey | Claves PEM, obligatorias para RS256/RS384/RS512 (antes esos algoritmos usaban en silencio el secret compartido). |
RateLimitOptions.trustProxy | false por defecto. Si no se activa, X-Forwarded-For/X-Real-IP se ignoran porque los envía el cliente. |
Plugins
Sección titulada «Plugins»| API | Notas |
|---|---|
Plugin.onStart?(app) | Corre después de que el servidor empieza a escuchar. |
Plugin.onStop?(app) | Corre durante el apagado gradual, en orden inverso de instalación. Los errores se recolectan en un AggregateError. |
| API | Notas |
|---|---|
CacheManager.destroy() | Libera los timers y conexiones de todos los almacenes registrados. |
CacheManager.reset() | Ahora destruye los almacenes antes de reemplazarlos (antes filtraba sus intervalos de limpieza). |
Middleware
Sección titulada «Middleware»| API | Notas |
|---|---|
createTimeoutMiddleware(ms, message?) | Exportado desde veloce-ts/middleware. Compartido por @Timeout() y la opción funcional timeout. |
WebSocket
Sección titulada «WebSocket»Opciones de WebSocketPlugin: heartbeatIntervalMs (por defecto 30000, 0 lo desactiva), heartbeatTimeoutMs (por defecto 2 × el intervalo), idleTimeoutMs (por defecto 0, desactivado), maxMessageSizeBytes (por defecto 1048576). Ver WebSockets.
GraphQL
Sección titulada «GraphQL»| API | Notas |
|---|---|
@Returns(typeOrSchema, options?) | Desde veloce-ts/graphql. Declara el tipo de retorno de un campo; las opciones son { name?, nullable?, list? }. Los resolvers y los tipos de objeto no funcionaban antes de v2.0.0. |
| API | Notas |
|---|---|
NotImplementedError | Lo lanzan los BaseRepository.count() / updateMany() / deleteMany() base, que antes hacían escaneos completos de tabla en silencio. Los adaptadores incluidos sobrescriben los tres. |
Próximos Pasos
Sección titulada «Próximos Pasos»- Lee la Guía de Decoradores
- Aprende sobre Inyección de Dependencias
- Explora Plugins
- Revisa la Guía de Pruebas
- Ve la Guía de Inicio