VelaVela
Techniques

Interceptors

Interceptors add extra logic before and after route handler execution.

Interceptors wrap the route handler execution, allowing you to run logic before and after the handler. They follow an onion/chain pattern where each interceptor wraps the next.

NestInterceptor Interface

import {
  Injectable, NestInterceptor, ExecutionContext, CallHandler,
} from '@velajs/vela';

@Injectable()
class LoggingInterceptor implements NestInterceptor {
  async intercept(context: ExecutionContext, next: CallHandler): Promise<unknown> {
    const start = Date.now();
    const result = await next.handle();
    const ms = Date.now() - start;
    console.log(`${context.getHandler().name} - ${ms}ms`);
    return result;
  }
}

The CallHandler provides a single method:

MethodDescription
handle()Calls the route handler (or next interceptor) and returns Promise<unknown> with the handler's return value

Binding Interceptors

Apply interceptors at the method or controller level with @UseInterceptors():

import { Controller, Get, UseInterceptors } from '@velajs/vela';

@Controller('spirits')
@UseInterceptors(LoggingInterceptor)
class SpiritsController {
  @Get()
  findAll() {
    return [];
  }
}

Global Interceptors

Register interceptors globally so they run on every route:

const app = await VelaFactory.create(AppModule);
app.useGlobalInterceptors(new LoggingInterceptor());

Or use the APP_INTERCEPTOR injection token:

import { APP_INTERCEPTOR } from '@velajs/vela';

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: LoggingInterceptor,
    },
  ],
})
class AppModule {}

Response Transformation

Interceptors can modify the handler's return value before it reaches the client:

@Injectable()
class WrapResponseInterceptor implements NestInterceptor {
  async intercept(context: ExecutionContext, next: CallHandler): Promise<unknown> {
    const data = await next.handle();
    return { data, timestamp: new Date().toISOString() };
  }
}

Caching Example

Short-circuit the handler by returning a cached value:

@Injectable()
class CacheInterceptor implements NestInterceptor {
  private cache = new Map<string, { data: unknown; expiry: number }>();

  async intercept(context: ExecutionContext, next: CallHandler): Promise<unknown> {
    const request = context.getRequest();
    const key = request.url;
    const cached = this.cache.get(key);

    if (cached && cached.expiry > Date.now()) {
      return cached.data;
    }

    const data = await next.handle();
    this.cache.set(key, { data, expiry: Date.now() + 60_000 });
    return data;
  }
}
Edit on GitHub

Last updated on

On this page