Skip to content

feat(api): paginate & filter GET /loans and GET /groups (closes #3) - #16

Open
Vyacheslav-Tomashevskiy wants to merge 2 commits into
coopfinance:mainfrom
Vyacheslav-Tomashevskiy:feat/pagination-loans-groups-3
Open

feat(api): paginate & filter GET /loans and GET /groups (closes #3)#16
Vyacheslav-Tomashevskiy wants to merge 2 commits into
coopfinance:mainfrom
Vyacheslav-Tomashevskiy:feat/pagination-loans-groups-3

Conversation

@Vyacheslav-Tomashevskiy

Copy link
Copy Markdown

Closes #3.

Problem

GET /api/loans and GET /api/groups returned all records with no bound — slow responses and heavy memory use once a group has hundreds of contributions or there are thousands of loans.

Changes

  • Reusable PaginationQueryDto (src/common/dto/pagination-query.dto.ts): page (>=1, default 1) and limit (1-100, default 20). Built on the existing global ValidationPipe({ transform: true }), so ?page=&limit= strings are coerced to numbers and a limit > 100 is rejected with 400 automatically (@Max(100)).
  • paginate() helper returns the standard envelope: { "data": [...], "meta": { "page": 1, "limit": 20, "total": 143, "totalPages": 8 } }.
  • Loans (FindLoansQueryDto extends PaginationQueryDto): pagination + sortBy=amount|requestedAt & order=asc|desc (defaults requestedAt desc, preserving current behaviour), keeping the existing groupId / status filters. sortBy/order are whitelisted with @IsIn so no arbitrary field reaches Prisma's orderBy.
  • Groups: pagination applied to findAll(); on-chain balance enrichment now runs only over the current page, not the whole table.
  • Page rows and total count are fetched together in a single prisma.$transaction([...]).
  • Swagger @ApiQuery added for every new param on both controllers.

Tests

Added a jest setup (repo had none) and 10 unit tests, all green (npx jest):

  • pagination-query.dto.spec.ts — numeric coercion, limit > 100 rejected, < 1 rejected, non-integer rejected, envelope math.
  • loans.service.spec.ts — defaults, skip/take/where/orderBy derivation, totalPages 0 on empty.
  • groups.service.spec.ts — pagination + per-page balance enrichment.

Acceptance criteria

  • Both endpoints paginated
  • Response includes meta object
  • Default page 1, limit 20
  • Max limit 100 (rejects >100 with 400)
  • Swagger docs updated (@ApiQuery for all params)
  • Unit tests for service layer with page/limit params

Scope kept tight: no unrelated changes. The 3 pre-existing tsc errors (stellar.service.ts, notifications.service.ts) are on main already and untouched here; the added files type-check clean.

…inance#3)

Both endpoints returned all rows unbounded. Add offset pagination with a
{ data, meta } envelope, a reusable PaginationQueryDto (page>=1 default 1,
limit 1..100 default 20; a limit >100 is rejected 400 by the global
ValidationPipe), plus sortBy(amount|requestedAt)+order for loans while
keeping the existing groupId/status filters. Count and page fetched in one
prisma.$transaction; Swagger @apiquery added for every param.

Service-layer unit tests + DTO validation tests (10 tests, jest).
# Conflicts:
#	jest.config.js
#	src/modules/groups/groups.controller.ts
#	src/modules/loans/loans.controller.ts
@Vyacheslav-Tomashevskiy
Vyacheslav-Tomashevskiy force-pushed the feat/pagination-loans-groups-3 branch from 912e5bf to 2e777aa Compare July 24, 2026 16:20
@Vyacheslav-Tomashevskiy

Copy link
Copy Markdown
Author

Rebased onto latest main (past the JWT auth guard + Soroban indexer merges). Resolved the controller conflicts by keeping the new @UseGuards(JwtAuthGuard)/@ApiBearerAuth() on the write endpoints while preserving pagination on the list endpoints. All 15 unit tests pass locally. Ready for review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API] Add pagination and filtering to GET /api/loans and GET /api/groups

1 participant