diff --git a/src/core/response/constants.ts b/src/core/response/constants.ts new file mode 100644 index 0000000..1da092d --- /dev/null +++ b/src/core/response/constants.ts @@ -0,0 +1 @@ +export const PAGINATION_RESPONSE = 'PAGINATION_RESPONSE'; diff --git a/src/core/response/domain/decorators/pagination.response.ts b/src/core/response/domain/decorators/pagination.response.ts new file mode 100644 index 0000000..482db0c --- /dev/null +++ b/src/core/response/domain/decorators/pagination.response.ts @@ -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); diff --git a/src/core/response/domain/exceptions/handled-exception.ts b/src/core/response/domain/exceptions/handled-exception.ts new file mode 100644 index 0000000..8170e22 --- /dev/null +++ b/src/core/response/domain/exceptions/handled-exception.ts @@ -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(); + const status = exception.getStatus(); + + response.status(status).json(exception.getResponse()); + } +} diff --git a/src/core/response/domain/ok-response.interface.ts b/src/core/response/domain/ok-response.interface.ts new file mode 100644 index 0000000..ea0a949 --- /dev/null +++ b/src/core/response/domain/ok-response.interface.ts @@ -0,0 +1,17 @@ +export interface PaginationMeta { + currentPage: number; + itemCount: number; + itemsPerPage: number; + totalItems: number; + totalPages: number; +} + +export interface SuccessResponse { + data: T; + meta?: PaginationMeta; +} + +export interface PaginationResponse { + data: T[]; + total: number; +} diff --git a/src/core/response/domain/response.interceptor.ts b/src/core/response/domain/response.interceptor.ts new file mode 100644 index 0000000..aba0534 --- /dev/null +++ b/src/core/response/domain/response.interceptor.ts @@ -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 { + const isPagination = this.reflector.getAllAndOverride( + PAGINATION_RESPONSE, + [context.getHandler(), context.getClass()], + ); + + const request = context.switchToHttp().getRequest(); + 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 }; + }), + ); + } +} diff --git a/src/core/response/domain/utils/pagination-meta.helper.ts b/src/core/response/domain/utils/pagination-meta.helper.ts new file mode 100644 index 0000000..4187eee --- /dev/null +++ b/src/core/response/domain/utils/pagination-meta.helper.ts @@ -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( + response: PaginationResponse, + start: number, + limit: number, +) { + const { data, total } = response; + const meta = createPaginationMeta(start, limit, data.length, total); + return { + data, + meta, + }; +} diff --git a/src/core/response/index.ts b/src/core/response/index.ts new file mode 100644 index 0000000..46990c8 --- /dev/null +++ b/src/core/response/index.ts @@ -0,0 +1,4 @@ +export * from './domain/response.interceptor'; +export * from './domain/exceptions/handled-exception'; +export * from './domain/decorators/pagination.response'; +export * from './constants';