feat: implement response interceptor

master
shancheas 2023-02-09 17:28:58 +07:00
parent 5bbe9b2970
commit e54dddfd89
7 changed files with 113 additions and 0 deletions

View File

@ -0,0 +1 @@
export const PAGINATION_RESPONSE = 'PAGINATION_RESPONSE';

View File

@ -0,0 +1,9 @@
import { SetMetadata } from '@nestjs/common';
import { PAGINATION_RESPONSE } from '../../constants';
/**
* This decorator will tell the response,
* that this request is pagination type
*/
export const Pagination = (isPagination = true) =>
SetMetadata(PAGINATION_RESPONSE, isPagination);

View File

@ -0,0 +1,18 @@
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
} from '@nestjs/common';
import { Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
response.status(status).json(exception.getResponse());
}
}

View File

@ -0,0 +1,17 @@
export interface PaginationMeta {
currentPage: number;
itemCount: number;
itemsPerPage: number;
totalItems: number;
totalPages: number;
}
export interface SuccessResponse<T> {
data: T;
meta?: PaginationMeta;
}
export interface PaginationResponse<T> {
data: T[];
total: number;
}

View File

@ -0,0 +1,35 @@
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Request } from 'express';
import { Reflector } from '@nestjs/core';
import { PAGINATION_RESPONSE } from '../constants';
import { createPaginationResponse } from './utils/pagination-meta.helper';
@Injectable()
export class TransformInterceptor implements NestInterceptor {
constructor(protected readonly reflector: Reflector) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const isPagination = this.reflector.getAllAndOverride<boolean>(
PAGINATION_RESPONSE,
[context.getHandler(), context.getClass()],
);
const request = context.switchToHttp().getRequest<Request>();
const start = request.params.page ?? 1;
const limit = request.params.limit ?? 10;
return next.handle().pipe(
map((data) => {
return isPagination
? createPaginationResponse(data, +start, +limit)
: { data };
}),
);
}
}

View File

@ -0,0 +1,29 @@
import { PaginationMeta, PaginationResponse } from '../ok-response.interface';
export function createPaginationMeta(
start: number,
limit: number,
dataCount: number,
total: number,
): PaginationMeta {
return {
currentPage: start,
itemCount: dataCount,
itemsPerPage: limit,
totalItems: +total,
totalPages: Math.ceil(+total / limit),
};
}
export function createPaginationResponse<T>(
response: PaginationResponse<T>,
start: number,
limit: number,
) {
const { data, total } = response;
const meta = createPaginationMeta(start, limit, data.length, total);
return {
data,
meta,
};
}

View File

@ -0,0 +1,4 @@
export * from './domain/response.interceptor';
export * from './domain/exceptions/handled-exception';
export * from './domain/decorators/pagination.response';
export * from './constants';