I followed the documentation and was able to add an interceptor for response mapping.
I want a consistent json format output for responses.
How can I achieve this with interceptor or with something else better than this approach.
{
"statusCode": 201,
"message": "Custom Dynamic Message"
"data": {
// properties
meta: {}
}
}
transform.interceptor.ts
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
export interface Response<T> {
statusCode: number;
data: T;
}
@Injectable()
export class TransformInterceptor<T>
implements NestInterceptor<T, Response<T>> {
intercept(
context: ExecutionContext,
next: CallHandler,
): Observable<Response<T>> {
return next
.handle()
.pipe(
map((data) => ({
statusCode: context.switchToHttp().getResponse().statusCode,
data,
})),
);
}
}
app.controller.ts
export class AppController {
@Post('login')
@UseGuards(AuthGuard('local'))
@ApiOperation({ summary: 'Login user' })
@ApiBody({ type: LoginDto })
@ApiOkResponse({ content: { 'application/json': {} } })
@UseInterceptors(TransformInterceptor)
async login(@Request() req) {
const result = await this.authService.login(req.user);
return { message: 'Thank you!', result };
}
}
To specify a custom response header, you can either use a @Header() decorator or a library-specific response object (and call res. header() directly). Hint Import Header from the @nestjs/common package.
DTO is the short name of Data Transfer Object. DTO is used in order to validate incoming requests. The DTO on its own is more of a guideline for the developer and those who consume the API to know what kind of shape the request body expects to be, it doesn't actually run any validations on its own!!!.
To get all query parameter values from a GET request, you can use the @Query() decorator function from the @nestjs/common module inside the parameter brackets of the controller's respective method in Nestjs.
An interceptor is a class annotated with the @Injectable() decorator and implements the NestInterceptor interface. Interceptors have a set of useful capabilities which are inspired by the Aspect Oriented Programming (AOP) technique. They make it possible to: bind extra logic before / after method execution.
If I am understanding what you are doing with your controller response and your overall interceptor response, what you can do is something similar:
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
export interface Response<T> {
statusCode: number;
message: string;
data: T;
}
@Injectable()
export class TransformInterceptor<T>
implements NestInterceptor<T, Response<T>> {
intercept(
context: ExecutionContext,
next: CallHandler,
): Observable<Response<T>> {
return next
.handle()
.pipe(
map((data) => ({
statusCode: context.switchToHttp().getResponse().statusCode,
message: data.message
data: {
result: data.result,
meta: {} // if this is supposed to be the actual return then replace {} with data.result
}
})),
);
}
}
And keep your controller return as {message: 'Custom message', result}
.
Another option, which would require more upfront but possible allow for cleaner code would be to create a custom decorator that reflected a value (message) from the class and method and then retrieved that value in the interceptor after injecting the reflector, but again, that would take more upfront effort to set up.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With