API Reference
API Reference
Section titled “API Reference”Complete API reference for Veloce-TS framework.
Table of Contents
Section titled “Table of Contents”- Core Classes
- Decorators
- Plugin System
- Drizzle ORM Integration
- Testing Utilities
- Error Classes
- Types
- New in v2.0.0
Core Classes
Section titled “Core Classes”VeloceTS / Veloce
Section titled “VeloceTS / Veloce”The main application class. Veloce is a named export alias of VeloceTS (same class).
Constructor
Section titled “Constructor”new VeloceTS(config?: VeloceTSConfig)// same as: new Veloce(config?: VeloceTSConfig)Parameters:
config(optional): Configuration object
VeloceTSConfig interface:
interface VeloceTSConfig { adapter?: 'hono' | 'express' | 'native'; title?: string; version?: string; description?: string; /** * Mount OpenAPI docs. `true` (the default) serves the spec at `/openapi.json` * and Swagger UI at `/docs`. Pass an object to change those paths, or `false` * to disable. Ignored when an `openapi` plugin is registered manually. * Before 3.0.0 this option was accepted and ignored. */ docs?: boolean | { path?: string; openapi?: string }; cors?: CorsOptions | boolean; /** Plugins registered at construction time (same as calling `usePlugin`). */ plugins?: Plugin[]; /** * Event bus that `@On` listeners subscribe to. Defaults to `globalEvents`. * Pass your own to keep a test suite from sharing subscriptions across apps. * Added in 3.3.0. */ eventBus?: EventBus; /** * Maximum request body size in bytes. Bodies above it are rejected with 413 * before any handler runs. Defaults to 1 MiB; `0` disables the limit. * Added in 3.0.0 — raise it if you accept file uploads. */ bodyLimit?: number; /** * Error JSON shape: * - `rfc9457` — `application/problem+json` (default since v0.4.3) * - `legacy` — `{ error, statusCode, details? }` */ errorResponseFormat?: 'rfc9457' | 'legacy';}Example:
const app = new Veloce({ title: 'My API', version: '1.0.0', description: 'API for my application', docs: true, cors: true,});Methods
Section titled “Methods”include(controller: Class): void
Section titled “include(controller: Class): void”Register a controller class with the application.
@Controller('/users')class UserController { @Get('/') async list() { return []; }}
app.include(UserController);get(path: string, config: RouteConfig): void
Section titled “get(path: string, config: RouteConfig): void”Register a GET route using functional API.
app.get('/users', { handler: async (c) => { return [{ id: 1, name: 'John' }]; },});post(path: string, config: RouteConfig): void
Section titled “post(path: string, config: RouteConfig): void”Register a POST route using functional API.
const UserSchema = z.object({ name: z.string(), email: z.string().email(),});
app.post('/users', { schema: { body: UserSchema }, handler: async (c) => { const body = await c.req.json(); return { id: 2, ...body }; },});put(path: string, config: RouteConfig): void
Section titled “put(path: string, config: RouteConfig): void”Register a PUT route using functional API.
delete(path: string, config: RouteConfig): void
Section titled “delete(path: string, config: RouteConfig): void”Register a DELETE route using functional API.
patch(path: string, config: RouteConfig): void
Section titled “patch(path: string, config: RouteConfig): void”Register a PATCH route using functional API.
route(path: string): RouteBuilder
Section titled “route(path: string): RouteBuilder”Create a route builder for chaining multiple methods on the same path.
app.route('/users') .get({ handler: async (c) => { return []; }, }) .post({ handler: async (c) => { const body = await c.req.json(); return body; }, });group(prefix: string, callback: () => void): void
Section titled “group(prefix: string, callback: () => void): void”Group routes under a common prefix.
app.group('/api', () => { app.get('/users', { handler: async (c) => [] }); app.get('/posts', { handler: async (c) => [] });});// Creates: /api/users and /api/postsuse(middleware: Middleware): void
Section titled “use(middleware: Middleware): void”Register global middleware.
app.use(async (c, next) => { console.log(`${c.req.method} ${c.req.url}`); await next();});useCors(options?: CorsOptions): void
Section titled “useCors(options?: CorsOptions): void”Enable CORS with optional configuration.
app.useCors({ origin: 'https://example.com', methods: ['GET', 'POST'], credentials: true,});useRateLimit(options: RateLimitOptions): void
Section titled “useRateLimit(options: RateLimitOptions): void”Enable rate limiting.
app.useRateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // 100 requests per window});Options:
interface RateLimitOptions { windowMs?: number; // Window length in ms (default 60000) max?: number; // Requests allowed per window (default 100) keyGenerator?: (c: Context) => string; /** * Trust X-Forwarded-For / X-Real-IP for client identity. Leave false (the * default) unless you run behind a trusted proxy — these headers are * client-supplied and trivially spoofable otherwise. */ trustProxy?: boolean; /** * Counter backend. Defaults to an in-memory, per-process store, which means * each replica enforces its own limit. Use `RedisRateLimitStore` to share one * counter across instances. Added in 3.0.0. */ store?: RateLimitStore;}import { RedisRateLimitStore } from 'veloce-ts/middleware';
app.useRateLimit({ max: 100, store: new RedisRateLimitStore(redis),});useCompression(options?: CompressionOptions): void
Section titled “useCompression(options?: CompressionOptions): void”Enable response compression.
app.useCompression({ threshold: 1024, // Only compress responses > 1KB});usePlugin(plugin: Plugin): void
Section titled “usePlugin(plugin: Plugin): void”Register a plugin with the application.
import { OpenAPIPlugin } from 'veloce-ts';
app.usePlugin(new OpenAPIPlugin({ path: '/openapi.json', docsPath: '/docs',}));onError(handler: ErrorHandler): void
Section titled “onError(handler: ErrorHandler): void”Register a custom error handler.
app.onError((error, c) => { console.error('Error:', error); return c.json({ error: error.message, timestamp: new Date().toISOString(), }, 500);});listen(port: number, callback?: () => void): Promise<ServerInstance>
Section titled “listen(port: number, callback?: () => void): Promise<ServerInstance>”Start the server on the specified port.
app.listen(3000, () => { console.log('Server running on http://localhost:3000');});compile(): Promise<void>
Section titled “compile(): Promise<void>”Compile all routes and metadata. Called automatically by listen().
app.compile();getHono(): Hono
Section titled “getHono(): Hono”Get the underlying Hono instance.
const hono = app.getHono();getMetadata(): MetadataRegistry
Section titled “getMetadata(): MetadataRegistry”Get the metadata registry.
const metadata = app.getMetadata();const routes = metadata.getRoutes();getContainer(): DIContainer
Section titled “getContainer(): DIContainer”Get the dependency injection container.
const container = app.getContainer();container.register(DatabaseService, { scope: 'singleton' });Response
Section titled “Response”:::note Renamed in 3.0.0
The response builder is now exported as VeloceResponse (with Res as a short alias).
The old Response export shadowed the global Web API Response in any file that imported it,
so new Response(body, init) silently resolved to the builder instead. Response is still
exported as a deprecated alias.
import { VeloceResponse } from 'veloce-ts'; // or: import { Res } from 'veloce-ts'
VeloceResponse.json({ ok: true }, 201);VeloceResponse.fileFrom('./uploads', filename, { download: true }); // path-traversal safeThe individual classes below (JSONResponse, HTMLResponse, …) keep their names.
:::
Response builder classes for different content types.
JSONResponse
Section titled “JSONResponse”import { JSONResponse } from 'veloce-ts';
@Get('/data')async getData() { return new JSONResponse({ data: 'value' }, 200);}HTMLResponse
Section titled “HTMLResponse”import { HTMLResponse } from 'veloce-ts';
@Get('/page')async getPage() { return new HTMLResponse('<h1>Hello</h1>', 200);}FileResponse
Section titled “FileResponse”import { FileResponse } from 'veloce-ts';
@Get('/download')async download() { return new FileResponse('/path/to/file.pdf', { filename: 'document.pdf', contentType: 'application/pdf', });}StreamResponse
Section titled “StreamResponse”import { StreamResponse } from 'veloce-ts';
@Get('/stream')async stream() { const stream = createReadStream('/path/to/large-file.txt'); return new StreamResponse(stream, { contentType: 'text/plain', });}RedirectResponse
Section titled “RedirectResponse”import { RedirectResponse } from 'veloce-ts';
@Get('/old-path')async redirect() { return new RedirectResponse('/new-path', 301);}Decorators
Section titled “Decorators”Class Decorators
Section titled “Class Decorators”@Controller(prefix?: string)
Section titled “@Controller(prefix?: string)”Marks a class as a controller and optionally sets a path prefix.
Parameters:
prefix(optional): Path prefix for all routes in the controller
Example:
@Controller('/api/users')class UserController { @Get('/') async list() { return []; }}@WebSocket(path: string)
Section titled “@WebSocket(path: string)”Marks a class as a WebSocket handler.
Parameters:
path: WebSocket endpoint path
Example:
@WebSocket('/chat')class ChatHandler { @OnConnect() handleConnect(client: WebSocketConnection) { console.log('Connected'); }}@Resolver()
Section titled “@Resolver()”Marks a class as a GraphQL resolver.
Example:
@Resolver()class UserResolver { @GQLQuery() async users() { return []; }}@UseMiddleware(...middleware: Middleware[])
Section titled “@UseMiddleware(...middleware: Middleware[])”Apply middleware to a controller or route.
Parameters:
middleware: One or more middleware functions
Example:
const authMiddleware = async (c, next) => { // Auth logic await next();};
@Controller('/admin')@UseMiddleware(authMiddleware)class AdminController { // All routes protected}Method Decorators
Section titled “Method Decorators”HTTP Method Decorators
Section titled “HTTP Method Decorators”@Get(path?: string)
Section titled “@Get(path?: string)”Register a GET route.
Parameters:
path(optional): Route path
Example:
@Get('/users')async getUsers() { return [];}
@Get('/users/:id')async getUser(@Param('id') id: string) { return { id };}@Post(path?: string)
Section titled “@Post(path?: string)”Register a POST route.
Example:
@Post('/users')async createUser(@Body(UserSchema) user: User) { return user;}@Put(path?: string)
Section titled “@Put(path?: string)”Register a PUT route.
Example:
@Put('/users/:id')async updateUser( @Param('id') id: string, @Body(UserSchema) user: User) { return { id, ...user };}@Delete(path?: string)
Section titled “@Delete(path?: string)”Register a DELETE route.
Example:
@Delete('/users/:id')async deleteUser(@Param('id') id: string) { return { success: true };}@Patch(path?: string)
Section titled “@Patch(path?: string)”Register a PATCH route.
Example:
@Patch('/users/:id')async patchUser( @Param('id') id: string, @Body(PartialUserSchema) data: Partial<User>) { return { id, ...data };}@All(path?: string)
Section titled “@All(path?: string)”Register a route that responds to all HTTP methods.
Example:
@All('/webhook')async webhook() { return { received: true };}OpenAPI Documentation Decorators
Section titled “OpenAPI Documentation Decorators”@Summary(text: string)
Section titled “@Summary(text: string)”Sets the short description for the route in Swagger UI.
@Description(text: string)
Section titled “@Description(text: string)”Sets the long description for the route operation detail panel.
@Tag(name: string)
Section titled “@Tag(name: string)”Assigns a single OpenAPI tag to the route. Stackable.
@Tags(...names: string[])
Section titled “@Tags(...names: string[])”Assigns multiple tags in a single decorator.
@Deprecated()
Section titled “@Deprecated()”Marks the route as deprecated in the OpenAPI spec.
Example:
@Get('/products')@Summary('List all products')@Tags('Products', 'Catalog')async listProducts() { return products;}
@Delete('/products/:id')@Deprecated()@Summary('Delete a product (deprecated)')async deleteProduct(@Param('id') id: string) { return { success: true };}Response Control Decorators
Section titled “Response Control Decorators”@HttpCode(statusCode: number)
Section titled “@HttpCode(statusCode: number)”Overrides the HTTP response status code and documents it in the OpenAPI spec.
Example:
@Post('/products')@HttpCode(201)async createProduct(@Body(CreateProductSchema) data: any) { return await db.create(data);}@ResponseSchema(schema: ZodSchema, statusCode?: number)
Section titled “@ResponseSchema(schema: ZodSchema, statusCode?: number)”Validates the handler response against a Zod schema and documents the response model in OpenAPI.
Example:
@Get('/products/:id')@ResponseSchema(ProductSchema)async getProduct(@Param('id') id: string) { return await db.findById(id);}Per-Route Middleware Decorators
Section titled “Per-Route Middleware Decorators”@Timeout(ms: number, message?: string)
Section titled “@Timeout(ms: number, message?: string)”Aborts the request with 408 Request Timeout if the handler exceeds the time limit. Emits the X-Timeout-Ms header.
Parameters:
ms: Timeout in millisecondsmessage(optional): Custom timeout message
Example:
@Get('/report')@Timeout(5000)async generateReport() { return await heavyReport();}@RateLimit(options: RateLimitOptions)
Section titled “@RateLimit(options: RateLimitOptions)”Applies rate-limiting to an individual route. Standard X-RateLimit-* headers are sent automatically.
Example:
@Post('/auth/login')@RateLimit({ windowMs: 15 * 60_000, max: 10 })async login(@Body(LoginSchema) credentials: any) { return await authService.login(credentials);}GraphQL Method Decorators
Section titled “GraphQL Method Decorators”@GQLQuery(name?: string)
Section titled “@GQLQuery(name?: string)”Define a GraphQL query.
:::caution Not @Query()
Query at the package root is the HTTP query-parameter decorator. A resolver
method decorated with it never becomes a GraphQL field. The GraphQL decorators
are @GQLQuery, @GQLMutation and @GQLSubscription — Mutation and
Subscription are also exported as aliases, but Query is not, precisely
because the name is taken.
:::
Example:
@Resolver()class UserResolver { @GQLQuery() async users() { return await db.getUsers(); }
@GQLQuery() async user(@Arg('id', z.number()) id: number) { return await db.getUserById(id); }}@GQLMutation(name?: string)
Section titled “@GQLMutation(name?: string)”Define a GraphQL mutation. Also exported as Mutation.
Example:
@GQLMutation()async createUser(@Arg('input', CreateUserInput) input: any) { return await db.createUser(input);}@GQLSubscription(name?: string)
Section titled “@GQLSubscription(name?: string)”Define a GraphQL subscription. Also exported as Subscription.
Example:
@GQLSubscription()async userCreated() { return pubsub.asyncIterator('USER_CREATED');}WebSocket Method Decorators
Section titled “WebSocket Method Decorators”@OnConnect()
Section titled “@OnConnect()”Handle WebSocket connection events.
Example:
@OnConnect()handleConnect(client: WebSocketConnection) { console.log(`Client ${client.id} connected`);}@OnMessage(schema?: ZodSchema)
Section titled “@OnMessage(schema?: ZodSchema)”Handle WebSocket message events with optional validation.
Parameters:
schema(optional): Zod schema for message validation
Example:
const MessageSchema = z.object({ type: z.string(), content: z.string(),});
@OnMessage(MessageSchema)handleMessage( client: WebSocketConnection, message: z.infer<typeof MessageSchema>) { client.broadcast(message);}@OnDisconnect()
Section titled “@OnDisconnect()”Handle WebSocket disconnection events.
Example:
@OnDisconnect()handleDisconnect(client: WebSocketConnection) { console.log(`Client ${client.id} disconnected`);}Parameter Decorators
Section titled “Parameter Decorators”@Body(schema?: ZodSchema)
Section titled “@Body(schema?: ZodSchema)”Extract and validate request body.
Parameters:
schema(optional): Zod schema for validation
Example:
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)
Section titled “@Query(schema?: ZodSchema)”Extract and validate query parameters.
Parameters:
schema(optional): Zod schema for validation
Example:
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)
Section titled “@Param(name?: string)”Extract route parameters.
Parameters:
name(optional): Specific parameter name to extract
Example:
@Get('/users/:id')async getUser(@Param('id') id: string) { return { id };}
// Extract all params@Get('/users/:userId/posts/:postId')async getPost(@Param() params: { userId: string; postId: string }) { return params;}@Header(name?: string, schema?: ZodSchema)
Section titled “@Header(name?: string, schema?: ZodSchema)”Extract and validate headers.
Parameters:
name(optional): Specific header name to extractschema(optional): Zod schema for validation
Example:
@Get('/protected')async getProtected(@Header('authorization') auth: string) { return { auth };}
const HeaderSchema = z.object({ 'x-api-key': z.string(),});
@Get('/api')async apiEndpoint(@Header(HeaderSchema) headers: z.infer<typeof HeaderSchema>) { return headers;}@Cookie(name?: string, schema?: ZodSchema)
Section titled “@Cookie(name?: string, schema?: ZodSchema)”Extract and validate cookies.
Parameters:
name(optional): Specific cookie name to extractschema(optional): Zod schema for validation
Example:
@Get('/profile')async getProfile(@Cookie('session') sessionId: string) { return { sessionId };}@Ctx()
Section titled “@Ctx()”Inject the Hono Context. For the Web standard Request, use c.req.raw.
import type { Context } from 'hono';
@Post('/echo')async echo(@Ctx() c: Context) { return await c.req.json();}@Req()
Section titled “@Req()”Inject Hono’s request object (c.req). Exported from veloce-ts. For Request (Fetch API), prefer @Ctx() and c.req.raw.
@Get('/path')path(@Req() req: import('hono').HonoRequest) { return { path: req.path };}@Depends(provider: Provider, scope?: Scope)
Section titled “@Depends(provider: Provider, scope?: Scope)”Inject dependencies.
Parameters:
provider: Service class to injectscope(optional): Dependency scope (‘singleton’, ‘request’, ‘transient’)
Example:
class UserService { async getUsers() { return []; }}
@Controller('/users')class UserController { @Get('/') async list(@Depends(UserService) userService: UserService) { return await userService.getUsers(); }}@Arg(name: string, schema?: ZodSchema)
Section titled “@Arg(name: string, schema?: ZodSchema)”GraphQL argument with validation.
Parameters:
name: Argument nameschema(optional): Zod schema for validation
Example:
@Resolver()class UserResolver { @GQLQuery() async user(@Arg('id', z.number().int().positive()) id: number) { return await db.getUserById(id); }}Plugin System
Section titled “Plugin System”Plugin Interface
Section titled “Plugin Interface”interface Plugin { name: string; version?: string; dependencies?: string[]; install(app: VeloceTS): void | Promise<void>;}Creating a Plugin
Section titled “Creating a Plugin”class MyPlugin implements Plugin { name = 'my-plugin'; version = '1.0.0';
install(app: VeloceTS) { // Add routes app.get('/plugin-route', { handler: async (c) => { return { message: 'From plugin' }; }, });
// Add middleware app.use(async (c, next) => { console.log('Plugin middleware'); await next(); });
// Register services app.getContainer().register(MyService, { scope: 'singleton' }); }}Using Plugins
Section titled “Using Plugins”const app = new VeloceTS();app.usePlugin(new MyPlugin());Built-in Plugins
Section titled “Built-in Plugins”OpenAPIPlugin
Section titled “OpenAPIPlugin”import { OpenAPIPlugin } from 'veloce-ts';
app.usePlugin(new OpenAPIPlugin({ path: '/openapi.json', docsPath: '/docs', title: 'My API', version: '1.0.0', description: 'API description',}));Options:
path: OpenAPI spec endpoint (default:/openapi.json)docsPath: Swagger UI endpoint (default:/docs)title: API titleversion: API versiondescription: API description
GraphQLPlugin
Section titled “GraphQLPlugin”import { GraphQLPlugin } from 'veloce-ts';
app.usePlugin(new GraphQLPlugin({ path: '/graphql', playground: true, introspection: true,}));Options:
path: GraphQL endpoint (default:/graphql)playground: Enable GraphQL Playground (default:true)introspection: Enable introspection (default:true)
WebSocketPlugin
Section titled “WebSocketPlugin”import { WebSocketPlugin } from 'veloce-ts';
app.usePlugin(new WebSocketPlugin({ path: '/ws', maxConnections: 1000,}));Options:
path: WebSocket endpoint (default:/ws)maxConnections: Maximum concurrent connections
Drizzle ORM Integration
Section titled “Drizzle ORM Integration”Connect Drizzle (or any other ORM) to the dependency injection container.
registerDrizzle(app, db, token?)
Section titled “registerDrizzle(app, db, token?)”Registers a database instance as a singleton in the DIContainer.
Parameters:
app: VeloceTS application instancedb: Database instance (Drizzle or other ORM)token(optional): Custom injection token (defaults toDB_TOKEN)
Example:
import { registerDrizzle } from 'veloce-ts';import { drizzle } from 'drizzle-orm/bun-sqlite';
const db = drizzle(new Database('my.db'));registerDrizzle(app, db);@InjectDB(token?)
Section titled “@InjectDB(token?)”Parameter decorator that injects the registered database instance. Alias of @Depends(DB_TOKEN).
Parameters:
token(optional): Custom injection token (defaults toDB_TOKEN)
Example:
import { InjectDB } from 'veloce-ts';
@Controller('/products')class ProductController { @Get('/') async list(@InjectDB() db: typeof drizzleDb) { return await db.select().from(products); }
@Post('/') @HttpCode(201) async create( @Body(CreateProductSchema) data: any, @InjectDB() db: typeof drizzleDb ) { return await db.insert(products).values(data).returning(); }}DB_TOKEN
Section titled “DB_TOKEN”Default symbol used as the injection token for the database instance.
import { DB_TOKEN } from 'veloce-ts';
// Custom token exampleconst CUSTOM_DB_TOKEN = Symbol('CUSTOM_DB');registerDrizzle(app, db, CUSTOM_DB_TOKEN);
@Get('/')async list(@InjectDB(CUSTOM_DB_TOKEN) db: any) { return await db.select().from(table);}Testing Utilities
Section titled “Testing Utilities”createTestApp(config?: VeloceTSConfig): VeloceTS
Section titled “createTestApp(config?: VeloceTSConfig): VeloceTS”Creates a test instance of the application.
Example:
import { createTestApp } from 'veloce-ts/testing';
const app = createTestApp();app.include(UserController);TestClient
Section titled “TestClient”HTTP client for making test requests with a fluent assertion API.
Request Methods:
get(path: string, options?: RequestOptions): Promise<TestResponse>post(path: string, body?: any, options?: RequestOptions): Promise<TestResponse>put(path: string, body?: any, options?: RequestOptions): Promise<TestResponse>delete(path: string, options?: RequestOptions): Promise<TestResponse>patch(path: string, body?: any, options?: RequestOptions): Promise<TestResponse>
Auth Helpers:
withToken(token: string): TestClient— creates an immutable instance withAuthorization: Bearer <token>pre-setwithHeaders(headers: Record<string, string>): TestClient— creates an immutable instance with additional headersloginAs(credentials, endpoint?): Promise<TestClient>— logs in, extracts the JWT, and returns an authenticated clientregisterAndLogin(user, endpoints?): Promise<TestClient>— registers and logs in in a single callclearAuth(): void— clears the stored token
TestResponse
Section titled “TestResponse”Response wrapper with chainable assertion methods returned by TestClient requests.
Properties:
status: number— HTTP status codeok: boolean— true if status is 2xxheaders: Headers— response headersbody: any— parsed JSON bodytext: string— raw response text
Assertion Methods:
expectStatus(code: number): TestResponseexpectOk(): TestResponse— asserts 200expectCreated(): TestResponse— asserts 201expectNotFound(): TestResponse— asserts 404expectUnauthorized(): TestResponse— asserts 401expectForbidden(): TestResponse— asserts 403expectBadRequest(): TestResponse— asserts 400expectJson(partialObject: any): TestResponse— partial body checkexpectField(field: string, value?: any): TestResponse— verify a specific fieldexpectHeader(name: string, value?: string): TestResponse— verify a response headerexpectArrayLength(n: number): TestResponse— verify array length in response
Example:
import { TestClient } from 'veloce-ts/testing';
const client = new TestClient(app);
// Fluent assertionsconst response = await client.get('/users');await response.expectOk().expectArrayLength(2);
// Auth helpersconst authClient = await client.loginAs({ email: 'user@example.com', password: 'password123'});await authClient.get('/profile').then(r => r.expectOk());
// Chained assertionsconst res = await client.post('/products', { name: 'Product A', price: 29.99});await res.expectCreated() .expectField('id') .expectJson({ name: 'Product A' });
// Manual assertions (still supported)const raw = await client.get('/users');expect(raw.status).toBe(200);const data = raw.body;expect(data).toBeArray();mockDependency(provider: Class, mock: any): void
Section titled “mockDependency(provider: Class, mock: any): void”Mocks a dependency in the DI container.
Example:
import { mockDependency } from 'veloce-ts/testing';
const mockUserService = { getUsers: async () => [{ id: 1, name: 'Test' }],};
mockDependency(UserService, mockUserService);Error Classes
Section titled “Error Classes”HTTPException
Section titled “HTTPException”Base exception class for HTTP errors.
Constructor:
new HTTPException(status: number, message: string, details?: any)Example:
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, 'User not found'); }
return user;}ValidationException
Section titled “ValidationException”Exception for validation errors (422 status).
Example:
import { ValidationException } from 'veloce-ts';
throw new ValidationException([ { path: 'email', message: 'Invalid email format' },]);NotFoundException
Section titled “NotFoundException”Exception for not found errors (404 status).
Example:
import { NotFoundException } from 'veloce-ts';
throw new NotFoundException('Resource not found');UnauthorizedException
Section titled “UnauthorizedException”Exception for unauthorized errors (401 status).
Example:
import { UnauthorizedException } from 'veloce-ts';
throw new UnauthorizedException('Invalid credentials');ForbiddenException
Section titled “ForbiddenException”Exception for forbidden errors (403 status).
Example:
import { ForbiddenException } from 'veloce-ts';
throw new ForbiddenException('Access denied');ConflictException
Section titled “ConflictException”Exception for conflict errors (409 status).
Example:
import { ConflictException } from 'veloce-ts';
throw new ConflictException('Email already registered');GoneException
Section titled “GoneException”Exception for gone errors (410 status). Use when a resource has been permanently deleted.
Example:
import { GoneException } from 'veloce-ts';
throw new GoneException('This resource no longer exists');PayloadTooLargeException
Section titled “PayloadTooLargeException”Exception for payload too large errors (413 status).
Example:
import { PayloadTooLargeException } from 'veloce-ts';
throw new PayloadTooLargeException('File exceeds the 10MB limit');UnprocessableEntityException
Section titled “UnprocessableEntityException”Exception for unprocessable entity errors (422 status). Use for semantic validation failures.
Example:
import { UnprocessableEntityException } from 'veloce-ts';
throw new UnprocessableEntityException('Age must be at least 18');TooManyRequestsException
Section titled “TooManyRequestsException”Exception for rate limit exceeded errors (429 status).
Example:
import { TooManyRequestsException } from 'veloce-ts';
throw new TooManyRequestsException('Too many requests. Try again in 1 minute.');ServiceUnavailableException
Section titled “ServiceUnavailableException”Exception for service unavailable errors (503 status).
Example:
import { ServiceUnavailableException } from 'veloce-ts';
throw new ServiceUnavailableException('Database is temporarily unavailable');VeloceTSConfig
Section titled “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';}Register plugins with app.usePlugin(new SomePlugin()) — there is no plugins: [] field on this config type.
RouteConfig
Section titled “RouteConfig”interface RouteConfig { handler: (c: Context) => any | Promise<any>; schema?: { body?: ZodSchema; query?: ZodSchema; params?: ZodSchema; headers?: ZodSchema; }; middleware?: Middleware[];}Middleware
Section titled “Middleware”type Middleware = (c: Context, next: () => Promise<void>) => Promise<void> | void;Context
Section titled “Context”Hono context object with request and response utilities.
Properties:
req: Request objectres: Response objectenv: Environment variablesexecutionCtx: Execution context
Methods:
json(data: any, status?: number): Responsetext(text: string, status?: number): Responsehtml(html: string, status?: number): Responseredirect(url: string, status?: number): Response
type Scope = 'singleton' | 'request' | 'transient';WebSocketConnection
Section titled “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;}New in v2.0.0
Section titled “New in v2.0.0”Quick reference for the APIs added or changed in v2.0.0. Breaking changes are marked.
Application
Section titled “Application”| API | Notes |
|---|---|
await app.getFetchHandler() | Returns a fetch(request, env, ctx) handler. The supported Cloudflare Workers deploy path — listen() throws on workerd. Auto-compiles routes on first call. Also usable with Bun.serve({ fetch }) / Deno.serve(). |
await app.shutdown() | Now also runs registered onShutdown() handlers and plugin onStop() hooks (it previously closed only the server). |
// worker.ts — Cloudflare Workersconst app = new Veloce({ title: 'My API' });app.get('/hello', { handler: () => ({ message: 'hi' }) });
export default { fetch: await app.getFetchHandler() };Typed functional routes — RouteConfig<S>
Section titled “Typed functional routes — RouteConfig<S>”app.get/post/put/delete/patch and app.route() are generic over the declared schema bag, so handler arguments are inferred. Injection order is body, query, params, headers; only declared schemas contribute an argument.
app.post('/users', { schema: { body: CreateUserSchema, query: QuerySchema }, handler: async (c, body, query) => body.name, // both fully typed});Supporting types: RouteSchemas, SchemaArgs<S>.
Controllers
Section titled “Controllers”| API | Notes |
|---|---|
@Controller(prefix, { scope }) | 'singleton' (new default) | 'request' | 'transient'. |
| API | Notes |
|---|---|
JWTProvider verification/revocation methods | Breaking — now async: verifyAccessToken, verifyRefreshToken, refreshAccessToken, blacklistToken, isBlacklisted, cleanupBlacklist. |
JWTConfig.blacklist | A TokenBlacklist implementation. Defaults to MemoryTokenBlacklist. |
MemoryTokenBlacklist / RedisTokenBlacklist | Exported from veloce-ts/auth. Use the Redis store to propagate revocation across replicas. |
JWTConfig.privateKey / publicKey | PEM keys, required for RS256/RS384/RS512 (previously those algorithms silently used the shared secret). |
RateLimitOptions.trustProxy | false by default. When unset, X-Forwarded-For/X-Real-IP are ignored because they are client-supplied. |
Plugins
Section titled “Plugins”| API | Notes |
|---|---|
Plugin.onStart?(app) | Runs after the server starts listening. |
Plugin.onStop?(app) | Runs during graceful shutdown, reverse install order. Errors are collected into an AggregateError. |
| API | Notes |
|---|---|
CacheManager.destroy() | Releases every registered store’s timers and connections. |
CacheManager.reset() | Now destroys stores before replacing them (it previously leaked their cleanup intervals). |
Middleware
Section titled “Middleware”| API | Notes |
|---|---|
createTimeoutMiddleware(ms, message?) | Exported from veloce-ts/middleware. Shared by @Timeout() and the functional timeout option. |
WebSocket
Section titled “WebSocket”WebSocketPlugin options: heartbeatIntervalMs (default 30000, 0 disables), heartbeatTimeoutMs (default 2 × interval), idleTimeoutMs (default 0, disabled), maxMessageSizeBytes (default 1048576). See WebSockets.
GraphQL
Section titled “GraphQL”| API | Notes |
|---|---|
@Returns(typeOrSchema, options?) | From veloce-ts/graphql. Declares a field’s return type; options are { name?, nullable?, list? }. Resolvers and object types did not work before v2.0.0. |
| API | Notes |
|---|---|
NotImplementedError | Thrown by base BaseRepository.count() / updateMany() / deleteMany(), which previously did silent full table scans. Bundled adapters override all three. |
Next Steps
Section titled “Next Steps”- Read the Decorators Guide for detailed decorator usage
- Learn about Dependency Injection
- Explore Plugins
- Check out Testing Guide
- View the Getting Started Guide