Skip to content

Latest commit

 

History

History
205 lines (152 loc) · 5.89 KB

File metadata and controls

205 lines (152 loc) · 5.89 KB

Pull Request: Cursor Pagination for Credit Lines

Summary

This PR implements cursor-based pagination for the GET /api/credit/lines endpoint while maintaining full backward compatibility with the existing offset-based pagination.

Changes

Core Implementation

  1. Repository Layer (src/repositories/)

    • Added CursorPaginationResult interface with items, nextCursor, and hasMore fields
    • Added findAllWithCursor(cursor?, limit?) method to CreditLineRepository interface
    • Implemented cursor pagination in InMemoryCreditLineRepository with stable ordering by createdAt and id
  2. Service Layer (src/services/)

    • Added getAllCreditLinesWithCursor(cursor?, limit?) method to CreditLineService
    • Validates limit parameter (1-100) for cursor pagination
    • Maintains existing getAllCreditLines(offset?, limit?) for backward compatibility
  3. Route Layer (src/routes/)

    • Updated GET /api/credit/lines handler to support both pagination modes
    • Automatically detects pagination mode based on presence of cursor query parameter
    • Returns appropriate response format based on pagination mode

Documentation

  1. OpenAPI Specification (docs/openapi.yaml)

    • Added cursor query parameter documentation
    • Defined CreditLine, CreditLinesOffsetResponse, and CreditLinesCursorResponse schemas
    • Documented both pagination modes with examples
  2. User Documentation

    • Created comprehensive guide: docs/cursor-pagination.md
    • Updated README.md with pagination examples and migration guide
    • Included client implementation examples in JavaScript/TypeScript and Python

Testing

  1. 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

API Usage

Cursor-Based Pagination (Recommended)

# First page
GET /api/credit/lines?cursor&limit=10

# Next page
GET /api/credit/lines?cursor=<nextCursor>&limit=10

Response:

{
  "creditLines": [...],
  "pagination": {
    "limit": 10,
    "nextCursor": "base64EncodedCursor",
    "hasMore": true
  }
}

Offset-Based Pagination (Legacy)

GET /api/credit/lines?offset=0&limit=10

Response:

{
  "creditLines": [...],
  "pagination": {
    "total": 100,
    "offset": 0,
    "limit": 10
  }
}

Backward Compatibility

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 cursor parameter is present → cursor pagination
  • Otherwise → offset pagination

Technical Details

Cursor Format

Cursors are base64-encoded strings containing:

  • Timestamp of the last item (createdAt)
  • ID of the last item

Example: MTcwOTU2ODAwMDAwMHxjbC0xMjM0NQ==

Ordering

Results are consistently ordered by:

  1. createdAt timestamp (ascending)
  2. id (ascending, for items with same timestamp)

This ensures stable, deterministic pagination even when data changes between requests.

Error Handling

  • Invalid cursors are handled gracefully (start from beginning)
  • Limit validation: 1-100 (same as offset pagination)
  • Returns 400 Bad Request for invalid parameters

Testing

All tests pass successfully:

npm test

Test Coverage

  • ✅ Repository layer: 8 new test cases
  • ✅ Service layer: 6 new test cases
  • ✅ Route layer: 7 new integration test cases
  • ✅ Coverage maintained at 95%+

Test Scenarios Covered

  1. First page retrieval
  2. Next page using cursor
  3. Last page detection (nextCursor = null)
  4. Cursor exhaustion
  5. Invalid cursor handling
  6. Stable ordering across pages
  7. Empty result sets
  8. Limit validation (zero, negative, oversized)
  9. Backward compatibility with offset pagination

Security & Performance

Security

  • 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

Performance

  • Cursor pagination: O(n) where n is cursor position
  • More efficient than offset for large offsets
  • Consistent results even when data changes between requests

Migration Guide

For Existing Clients

No changes required! Continue using offset/limit pagination.

For New Implementations

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`
);

Files Changed

  • src/repositories/interfaces/CreditLineRepository.ts - Added cursor pagination interface
  • src/repositories/memory/InMemoryCreditLineRepository.ts - Implemented cursor pagination
  • src/services/CreditLineService.ts - Added cursor pagination service method
  • src/routes/credit.ts - Updated route to support both pagination modes
  • docs/openapi.yaml - Updated API specification
  • docs/cursor-pagination.md - New comprehensive documentation
  • README.md - Updated with pagination examples
  • Test files - Added comprehensive test coverage

Checklist

  • ✅ 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

Notes

  • 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