Skip to content

Middleware

Middleware lets you run code before procedure handlers execute. Use it for logging, rate limiting, or request transformation.

Add middleware with .use():

import { procedure } from '@veloxts/velox';
const loggedProcedure = procedure()
.use(async ({ ctx, next }) => {
console.log('Request started');
const result = await next();
console.log('Request completed');
return result;
})
.query(handler);
type Middleware = (opts: {
ctx: Context;
input: unknown;
next: () => Promise<unknown>;
}) => Promise<unknown>;
const loggingMiddleware = async ({ ctx, next }) => {
const start = Date.now();
const result = await next();
const duration = Date.now() - start;
console.log(`${ctx.request.method} ${ctx.request.url} - ${duration}ms`);
return result;
};
const timingMiddleware = async ({ ctx, next }) => {
const start = process.hrtime.bigint();
const result = await next();
const end = process.hrtime.bigint();
ctx.reply.header('X-Response-Time', `${Number(end - start) / 1e6}ms`);
return result;
};
const errorMiddleware = async ({ next }) => {
try {
return await next();
} catch (error) {
// Log to error tracking service
console.error('Procedure error:', error);
throw error;
}
};
const tenantMiddleware = async ({ ctx, next }) => {
const tenantId = ctx.request.headers['x-tenant-id'];
ctx.tenant = await getTenant(tenantId);
return next();
};

Middleware runs in order:

const securedProcedure = procedure()
.use(loggingMiddleware) // 1. Log request
.use(authMiddleware) // 2. Verify auth
.use(rateLimitMiddleware) // 3. Check rate limit
.guard(authenticated) // 4. Require auth
.query(handler); // 5. Execute handler

Create middleware-enhanced base procedures:

// Base with logging
export const loggedProcedure = procedure().use(loggingMiddleware);
// Base with auth
export const authedProcedure = procedure()
.use(loggingMiddleware)
.guard(authenticated);
// Use in procedures
export const userProcedures = procedures('users', {
listUsers: loggedProcedure
.output(z.array(UserSchema))
.query(handler),
getProfile: authedProcedure
.output(UserSchema)
.query(({ ctx }) => ctx.user),
});
FeatureMiddlewareGuards
PurposeRequest processingAuthorization
Can modify contextYesNo
Can modify responseYesNo
Failure behaviorThrow or continueBlock request

Use middleware for cross-cutting concerns (logging, timing). Use guards for authorization (authenticated, hasRole).