This PR implements cursor-based pagination for the GET /api/credit/lines endpoint while maintaining full backward compatibility with the existing offset-based pagination.
-
Repository Layer (
src/repositories/)- Added
CursorPaginationResultinterface withitems,nextCursor, andhasMorefields - Added
findAllWithCursor(cursor?, limit?)method toCreditLineRepositoryinterface - Implemented cursor pagination in
InMemoryCreditLineRepositorywith stable ordering bycreatedAtandid
- Added
-
Service Layer (
src/services/)- Added
getAllCreditLinesWithCursor(cursor?, limit?)method toCreditLineService - Validates limit parameter (1-100) for cursor pagination
- Maintains existing
getAllCreditLines(offset?, limit?)for backward compatibility
- Added
-
Route Layer (
src/routes/)- Updated
GET /api/credit/lineshandler to support both pagination modes - Automatically detects pagination mode based on presence of
cursorquery parameter - Returns appropriate response format based on pagination mode
- Updated
-
OpenAPI Specification (
docs/openapi.yaml)- Added
cursorquery parameter documentation - Defined
CreditLine,CreditLinesOffsetResponse, andCreditLinesCursorResponseschemas - Documented both pagination modes with examples
- Added
-
User Documentation
- Created comprehensive guide:
docs/cursor-pagination.md - Updated
README.mdwith pagination examples and migration guide - Included client implementation examples in JavaScript/TypeScript and Python
- Created comprehensive guide:
- Comprehensive Test Coverage
- Repository tests: First page, next page, last page, cursor exhaustion, invalid cursor, stable ordering, empty results
- Service tests: Cursor handling, limit validation, empty results
- Route integration tests: Full pagination flow, error handling, backward compatibility
- All tests pass with 95%+ coverage maintained
# First page
GET /api/credit/lines?cursor&limit=10
# Next page
GET /api/credit/lines?cursor=<nextCursor>&limit=10Response:
{
"creditLines": [...],
"pagination": {
"limit": 10,
"nextCursor": "base64EncodedCursor",
"hasMore": true
}
}GET /api/credit/lines?offset=0&limit=10Response:
{
"creditLines": [...],
"pagination": {
"total": 100,
"offset": 0,
"limit": 10
}
}✅ Fully backward compatible - Existing clients using offset/limit pagination continue to work without any changes.
The API automatically detects which pagination mode to use:
- If
cursorparameter is present → cursor pagination - Otherwise → offset pagination
Cursors are base64-encoded strings containing:
- Timestamp of the last item (
createdAt) - ID of the last item
Example: MTcwOTU2ODAwMDAwMHxjbC0xMjM0NQ==
Results are consistently ordered by:
createdAttimestamp (ascending)id(ascending, for items with same timestamp)
This ensures stable, deterministic pagination even when data changes between requests.
- Invalid cursors are handled gracefully (start from beginning)
- Limit validation: 1-100 (same as offset pagination)
- Returns 400 Bad Request for invalid parameters
All tests pass successfully:
npm test- ✅ Repository layer: 8 new test cases
- ✅ Service layer: 6 new test cases
- ✅ Route layer: 7 new integration test cases
- ✅ Coverage maintained at 95%+
- First page retrieval
- Next page using cursor
- Last page detection (nextCursor = null)
- Cursor exhaustion
- Invalid cursor handling
- Stable ordering across pages
- Empty result sets
- Limit validation (zero, negative, oversized)
- Backward compatibility with offset pagination
- Cursors are opaque tokens (base64-encoded)
- No PII or sensitive data in cursors
- Invalid cursors handled gracefully without exposing internals
- No changes to authentication or authorization
- Cursor pagination: O(n) where n is cursor position
- More efficient than offset for large offsets
- Consistent results even when data changes between requests
No changes required! Continue using offset/limit pagination.
Use cursor pagination for better performance:
// First page
const firstPage = await fetch('/api/credit/lines?cursor&limit=10');
// Next page
const nextPage = await fetch(
`/api/credit/lines?cursor=${firstPage.pagination.nextCursor}&limit=10`
);src/repositories/interfaces/CreditLineRepository.ts- Added cursor pagination interfacesrc/repositories/memory/InMemoryCreditLineRepository.ts- Implemented cursor paginationsrc/services/CreditLineService.ts- Added cursor pagination service methodsrc/routes/credit.ts- Updated route to support both pagination modesdocs/openapi.yaml- Updated API specificationdocs/cursor-pagination.md- New comprehensive documentationREADME.md- Updated with pagination examples- Test files - Added comprehensive test coverage
- ✅ Backward compatible query params
- ✅ Documented in OpenAPI
- ✅ Tests for first page, next cursor, and exhaustion
- ✅ 95%+ test coverage maintained
- ✅ Clear documentation (OpenAPI, README, inline comments)
- ✅ No breaking changes
- ✅ Security considerations addressed
- ✅ Performance optimized
- Timeframe: Completed within 96 hours
- No type changes requiring
npm run build - OpenAPI spec kept in sync with route behavior
- All security and operational notes included in documentation