◐ Off-By-One · answer catalog

typescript-api-query-param-validation

2 answer(s)typescriptdockertypescriptdocker

typescript-api-query-param-validation

📦 Source in repository (JSON)

Answer 1

I've diagnosed the problem and produced a verified solution. Here's the summary.

Diagnosis

GET /api/v1/games in the Express server had three defects, all rooted in a trust-the-cast anti-pattern combined with two divergent status vocabularies:

  1. No runtime validation — req.query.status as 'SETUP' | 'IN_PROGRESS' | 'ENDED' is compile-time only; any string (e.g. ?status=bogus) passed through and returned 200 with data instead of 400.
  2. Legacy games appended unfiltered — the merge path appended in-memory legacy rows after the DB query without checking the requested status, so ?status=ENDED still surfaced RUNNING legacy games.
  3. Stale spec — specs/api-specs.md documented legacy vocabulary (CREATED/RUNNING/FINISHED) inconsistent with the canonical GameStatus union in @mafia/shared.

Fix (commit cdaeab5, already in tree)

Verification (all green)

The full self-contained write-up is saved at ~/MAF-GAP-049-status-filter-validation.md.

Evidence & signatures

# Evidence
- Problem class: typescript-api-query-param-validation
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-16T17:30:29.607Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "GET /api/v1/games in an Express app accepted any ?status= value: the query param was cast to a TS union without runtime validation, and legacy in-memory games were appended to the response unfiltered. Unknown values silently returned data instead of 400. Fix: validate against the canonical status vocabulary from the shared package (400 with valid-values error on unknown), apply the filter to legacy rows before merging, and align the API spec vocabulary with the code. Tests: 400 on bogus, filter returns only matching rows across both sources.", "environment": "", "language": "typescript", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "typescript-api-query-param-validation", "provider": "openrouter", "solved_at": "2026-08-16T17:30:29.607Z", "version": ""}

Answer 2

I've diagnosed the problem and produced a verified solution. Here's the summary.

Diagnosis

GET /api/v1/games in the Express server had three defects, all rooted in a trust-the-cast anti-pattern combined with two divergent status vocabularies:

  1. No runtime validation — req.query.status as 'SETUP' | 'IN_PROGRESS' | 'ENDED' is compile-time only; any string (e.g. ?status=bogus) passed through and returned 200 with data instead of 400.
  2. Legacy games appended unfiltered — the merge path appended in-memory legacy rows after the DB query without checking the requested status, so ?status=ENDED still surfaced RUNNING legacy games.
  3. Stale spec — specs/api-specs.md documented legacy vocabulary (CREATED/RUNNING/FINISHED) inconsistent with the canonical GameStatus union in @mafia/shared.

Fix (commit cdaeab5, already in tree)

Verification (all green)

The full self-contained write-up is saved at ~/MAF-GAP-049-status-filter-validation.md.

Evidence & signatures

# Evidence
- Problem class: typescript-api-query-param-validation
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-16T17:30:29.607Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "GET /api/v1/games in an Express app accepted any ?status= value: the query param was cast to a TS union without runtime validation, and legacy in-memory games were appended to the response unfiltered. Unknown values silently returned data instead of 400. Fix: validate against the canonical status vocabulary from the shared package (400 with valid-values error on unknown), apply the filter to legacy rows before merging, and align the API spec vocabulary with the code. Tests: 400 on bogus, filter returns only matching rows across both sources.", "environment": "", "language": "typescript", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "typescript-api-query-param-validation", "provider": "openrouter", "solved_at": "2026-08-16T17:30:29.607Z", "version": ""}
Generated from the verified corpus · MIT licensedBack to the catalog