From harness-claude
Transforms responses and adds cross-cutting behavior via NestInterceptor and CallHandler, including logging, timeout, caching, and exception mapping.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:nestjs-interceptors-patternThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Transform responses and add cross-cutting behavior with NestInterceptor and CallHandler
Transform responses and add cross-cutting behavior with NestInterceptor and CallHandler
NestInterceptor<T, R> and the intercept(context, next) method which returns an Observable:@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, { data: T }> {
intercept(context: ExecutionContext, next: CallHandler): Observable<{ data: T }> {
return next.handle().pipe(map((value) => ({ data: value })));
}
}
@UseInterceptors(TransformInterceptor) at class or method level, or globally:// Global — in main.ts (no DI)
app.useGlobalInterceptors(new TransformInterceptor());
// Global — with DI (preferred)
providers: [{ provide: APP_INTERCEPTOR, useClass: TransformInterceptor }];
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
const start = Date.now();
return next.handle().pipe(tap(() => console.log(`${Date.now() - start}ms`)));
}
}
@Injectable()
export class TimeoutInterceptor implements NestInterceptor {
intercept(_: ExecutionContext, next: CallHandler): Observable<unknown> {
return next.handle().pipe(timeout(5000));
}
}
return next
.handle()
.pipe(catchError((err) => throwError(() => new BadGatewayException(err.message))));
next.handle() is pre-handler logic. Code in the RxJS pipe AFTER next.handle() is post-handler logic.Interceptors are executed in the NestJS lifecycle after guards and before pipes. They wrap the handler call using RxJS Observables, which is what makes both pre- and post-execution logic possible from a single point.
RxJS operators to know:
map(fn) — transform the response valuetap(fn) — side-effect without transforming (logging, metrics)timeout(ms) — throw TimeoutError if the observable does not emit in timecatchError(fn) — handle errors in the response streammergeMap / switchMap — flatten async operationsInterceptors vs Middleware: Middleware runs before routing. Interceptors wrap the entire route handler and its result. Use interceptors when you need to inspect or transform the handler's return value.
Interceptors vs Filters: Exception filters catch thrown errors. Interceptors can intercept errors via catchError in the RxJS stream, but exception filters are the canonical place for error shaping. Use interceptors for response transformation, not error handling.
Order of execution: When multiple interceptors are applied, they execute in order (outermost wraps innermost), similar to middleware. @UseInterceptors(A, B) means A's pre-logic, then B's pre-logic, then handler, then B's post-logic, then A's post-logic.
Serialization: NestJS ships ClassSerializerInterceptor which runs class-transformer's instanceToPlain on every response, respecting @Exclude() and @Expose() decorators on entity classes.
https://docs.nestjs.com/interceptors
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeImplements NestJS guards and interceptors for authentication, authorization, logging, and request/response transformation. Covers CanActivate, ExecutionContext, and JWT patterns for cross-cutting concerns.
Provides NestJS architecture patterns for building modular, production-grade TypeScript backends with validation, guards, interceptors, and config.
Provides NestJS architecture patterns for modules, controllers, providers, DTO validation, guards, interceptors, and production-grade TypeScript backends.