- Closes #64
- PR #158: #158
- Branch:
fix/pagination-nan-validation
IntentsController.list() was using parseInt() on raw query parameters (limitRaw, offsetRaw) without any validation. When a non-numeric value was provided (e.g., ?limit=abc), parseInt() returned NaN, which silently corrupted the pagination slice (intents.slice(offset, offset + limit)) instead of returning a clear 400 error.
Introduced a typed DTO for list query parameters using class-validator decorators consistent with the rest of the codebase:
limit:@IsInt(),@Min(1),@Max(100)— ensures the value is a valid integer between 1 and 100offset:@IsInt(),@Min(0)— ensures the value is a valid non-negative integerstate,user,chain:@IsOptional(),@IsString()— optional string filters
- Changed
list()method signature from individual@Query()parameters to a single@Query() dto: ListIntentsDto - Replaced
Math.min(parseInt(limitRaw, 10), 100)andparseInt(offsetRaw, 10)withdto.limitanddto.offset - The global
ValidationPipe(configured inmain.tswithwhitelist: true, transform: true) automatically validates the DTO and returns a 400 response with detailed error information when validation fails
Added two new e2e tests:
GET /api/v1/intents with non-numeric limit returns 400— Asserts that?limit=abcreturns HTTP 400 witherror: "Validation failed"and an array ofdetailsGET /api/v1/intents with non-numeric offset returns 400— Asserts that?offset=xyzreturns HTTP 400 witherror: "Validation failed"and an array ofdetails
npm run lintpassesnpm run typecheckpassesnpm testpassesnpm run test:e2epasses (new e2e tests for non-numeric limit/offset)
- Limit/offset moved into a proper DTO with
@IsInt()/@Min()/@Max()validators - Non-numeric
limitquery param returns 400, not a silently broken page - Non-numeric
offsetquery param returns 400, not a silently broken page - E2E tests added and passing
- PR description includes "Closes #64"