@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, { data: T }> {
intercept(ctx: ExecutionContext, next: CallHandler<T>) {
return next.handle().pipe(map((data) => ({ data })));
}
}
// main.ts
app.useGlobalInterceptors(new TransformInterceptor());
Use a global interceptor that changes the handler's result. next.handle() emits whatever the handler returned. The RxJS map operator turns that value into { data } before Nest converts it to JSON (serialises it). Register the interceptor globally, with useGlobalInterceptors() or the APP_INTERCEPTOR provider, and it applies to every route.
Two limits:
- It only changes successful responses. Errors skip the
mapand go to exception filters. So you shape the error format with a filter. - If a handler uses
@Res()and writes the response itself, the mapping has no effect. Nest isn't sending that response, so the interceptor can't change it.
- Use an interceptor with
map()onnext.handle(). - Register it globally or with
APP_INTERCEPTOR. - It only changes successful responses.
- Exception filters shape the error responses instead.
Read more
- Interceptors (https://docs.nestjs.com/interceptors)docs.nestjs.com