Implement pagination response handling and related enhancements
- Introduced `@Pagination()` decorator to mark list endpoints for pagination.
- Added `TransformInterceptor` to wrap responses in a standardized format `{ data, meta }`.
- Created pagination-related utility functions and constants for managing pagination logic.
- Defined `PaginationQueryDto` for handling pagination query parameters.
- Established `PaginationMetaDto` for OpenAPI documentation of pagination metadata.
- Updated existing controller and service structures to support pagination in responses.
- Added unit tests for pagination utilities and interceptor to ensure correct functionality.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
NestInterceptor,
|
||||
StreamableFile,
|
||||
} from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { PAGINATION_RESPONSE, RAW_RESPONSE } from './constants';
|
||||
import {
|
||||
createPaginationResponse,
|
||||
resolvePaginationQuery,
|
||||
} from './pagination-meta.helper';
|
||||
|
||||
/**
|
||||
* Applies pagination enveloping when a handler is marked with `@Pagination()`.
|
||||
*
|
||||
* Non-paginated handlers pass through unchanged. `@RawResponse()`, empty
|
||||
* bodies, and `StreamableFile` downloads are never wrapped.
|
||||
*/
|
||||
@Injectable()
|
||||
export class TransformInterceptor implements NestInterceptor {
|
||||
constructor(private readonly reflector: Reflector) {}
|
||||
|
||||
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
|
||||
const isRaw = this.reflector.getAllAndOverride<boolean>(RAW_RESPONSE, [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
if (isRaw) {
|
||||
return next.handle();
|
||||
}
|
||||
|
||||
const isPagination = this.reflector.getAllAndOverride<boolean>(
|
||||
PAGINATION_RESPONSE,
|
||||
[context.getHandler(), context.getClass()],
|
||||
);
|
||||
if (!isPagination) {
|
||||
return next.handle();
|
||||
}
|
||||
|
||||
const request = context.switchToHttp().getRequest<{
|
||||
query: Record<string, unknown>;
|
||||
}>();
|
||||
const { page, limit } = resolvePaginationQuery(request.query);
|
||||
|
||||
return next.handle().pipe(
|
||||
map((payload: unknown): unknown => {
|
||||
if (payload == null || payload instanceof StreamableFile) {
|
||||
return payload;
|
||||
}
|
||||
return createPaginationResponse(payload, page, limit);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user