Skip to content

Latest commit

 

History

History
100 lines (85 loc) · 5.06 KB

File metadata and controls

100 lines (85 loc) · 5.06 KB

Plan (high level)

  • Add a small DTO for pagination parameters (transform strings to numbers and validate).
  • Update modules.controller.ts GET handlers to accept the DTO and pass it to the service.
  • Update modules.service.ts (or repository) to use page/limit to compute skip and take and perform the query (prefer findAndCount if you need total).
  • Return items plus pagination metadata (page, limit, total or hasMore).
  • Add/update tests and docs.

Step-by-step instructions

  1. Create a pagination DTO (recommended location)
  • File: src/common/dto/pagination-query.dto.ts (or src/modules/dto/pagination-query.dto.ts if you prefer module-scoped).
  • Purpose: accept page and limit from query, convert to numbers, and validate defaults and ranges.
  • Implementation notes:
    • Use class-transformer's @Type(() => Number) or Nest's ParseIntPipe downstream.
    • Use class-validator decorators:
      • @IsOptional()
      • @IsInt()
      • @Min(1) for page
      • @Min(1), @Max(100) for limit (choose a sensible max)
    • Provide defaults (e.g., page = 1, limit = 20) either in the DTO or in controller defaults.
  1. Update the controller to accept the DTO and validate
  • Open modules.controller.ts.
  • Import the DTO and add @UsePipes(new ValidationPipe({ transform: true, whitelist: true })) to the controller or method. Alternatively, use global validation pipe if your app already has it (likely already set in main.ts).
  • Update the GET handler signature:
    • Before: findAll() or getModules()
    • After example:
      • @Get()
      • findAll(@Query() pagination: PaginationQueryDto) { return this.modulesService.findAll(pagination); }
  • If you prefer simpler pipes without DTO:
    • Use @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number
    • Use @Query('limit', new DefaultValuePipe(20), ParseIntPipe) limit: number
    • But the DTO approach centralizes validation.
  1. Update the service to accept pagination and apply skip/take
  • Open modules.service.ts.
  • Add parameters to the findAll method: findAll(pagination: PaginationQueryDto) or (page: number, limit: number).
  • Compute skip = (page - 1) * limit, take = limit.
  • If using TypeORM repository:
    • Simple: const [items, total] = await this.moduleRepository.findAndCount({ skip, take, order: { createdAt: 'DESC' }});
    • If not using findAndCount, you can run query builder:
      • const items = await this.moduleRepository.createQueryBuilder('m').orderBy('m.createdAt', 'DESC').skip(skip).take(take).getMany();
      • To get total count: .getCount() or .getManyAndCount().
  • Return a shaped response:
    • return { items, meta: { page, limit, total, hasMore: skip + items.length < total } }
    • If you don't want to do total (expensive), return items with { nextPage: page + 1, hasMore: items.length === limit }.
  1. Update repository (if you have a dedicated repository file)
  • If entities and src/modules/modules.repository.ts exist, move DB logic there. The service calls the repository with { skip, take }.
  1. Add tests
  • Update src/modules/modules.controller.spec.ts (or create) to call the GET /modules?limit=2&page=2 and mock the service to confirm it receives (page, limit) and returns expected subset.
  • Add service-level tests to assert correct skip/take calculations and repository call.
  1. Add documentation
  • Update module README or central API docs to include ?page and ?limit examples and default/max values.
  1. Edge cases & best-practices
  • Enforce maximum limit (e.g., 100) to avoid huge responses.
  • Use transform: true for DTOs so strings in query convert to numbers automatically.
  • Consider cursor-based pagination if the dataset is large or frequently changing.
  • Return consistent ordering (always specify orderBy) so paging is repeatable.

Example code snippets (concise)

  • DTO (using class-validator + transform):

    • class PaginationQueryDto { @IsOptional() @Type(() => Number) @IsInt() @Min(1) page?: number = 1;

      @IsOptional() @Type(() => Number) @IsInt() @Min(1) @Max(100) limit?: number = 20; }

  • Controller method (method-level snippet):

    • @Get() findAll(@Query() pagination: PaginationQueryDto) { return this.modulesService.findAll(pagination); }
  • Service logic (method-level snippet):

    • async findAll({ page = 1, limit = 20 }: PaginationQueryDto) { const skip = (page - 1) * limit; const [items, total] = await this.moduleRepository.findAndCount({ skip, take: limit, order: { createdAt: 'DESC' }}); return { items, meta: { page, limit, total, hasMore: skip + items.length < total } }; }

What to run & check

  • Run unit tests: npm test (or your repo's test command).
  • Verify controller validation: request GET /modules?page=abc should return a 400 validation error.

Wrap-up / Next step for me

  • I already created a todo plan. If you want, I can implement this for the modules endpoints now: create the DTO, patch the controller and service, and add a unit test. Tell me to proceed and whether you prefer DTO-based or direct pipes approach.