Here’s an example of a NestJS interceptor that checks for a specific API key in the request headers before allowing the request to proceed to the route handler. The interceptor also fetches some data related to the API key and attaches it to the request object for use in the route handler.
@Injectable()
export class ApiKeyInterceptor implements NestInterceptor {
  constructor(private readonly studioService: StudioService) {}

  async intercept(
    context: ExecutionContext,
    next: CallHandler,
  ): Promise<Observable<any>> {
    const apiKey = context.switchToHttp().getRequest().headers['x-api-key'];

    if (apiKey == null) {
      throw new UnauthorizedException('Unauthorized');
    }
    const studio = await this.studioService.findOne({
      conditions: { apiKey: apiKey },
    });

    if (studio == null) {
      throw new UnauthorizedException('Unauthorized');
    }

    context.switchToHttp().getRequest().studio = studio;

    return next.handle();
  }
}

Usage

// Attach the interceptor to a route using the @UseInterceptors() decorator.
@UseInterceptors(ApiKeyInterceptor)
@Get('public')
publicEndpoint() {
  // Your route handler logic
}

Explanation

Interceptor Creation

  1. A new interceptor class ApiKeyInterceptor is created, decorated with @Injectable() indicating it’s a provider that can be injected.
  2. It implements NestInterceptor, requiring the intercept() method to be defined.

intercept Method

  1. The intercept() method is where the main logic of the interceptor resides.
  2. In this method, it’s checking if the x-api-key header exists in the request. If not, an UnauthorizedException is thrown.
  3. If the API key exists, it then queries a service (studioService) to fetch some data related to the API key.
  4. If no data is found, again an UnauthorizedException is thrown.
  5. If data is found, it attaches this data to the request object under the studio property for later use in the route handler.
  6. Finally, it calls next.handle() to pass control to the next handler (which would be the route handler).

Usage

  1. The interceptor is then attached to a specific route using the @UseInterceptors() decorator and passing the ApiKeyInterceptor class.
  2. This means that whenever a request hits this publicEndpoint route, the ApiKeyInterceptor will run first, perform its logic, and then (assuming no exceptions are thrown) pass control to the publicEndpoint route handler.
  3. This interceptor is effectively a way to implement API key authentication on a route and also fetch and attach related data to the request for use in the route handler.