Sort + filter query helpers per the documented grammar #192

Closed
opened 2026-06-20 17:36:15 +00:00 by james · 0 comments
Owner

Build reusable query-string parsing helpers for the sort and filter grammar documented in docs/api-conventions.md §"Sort and filter grammar". No endpoint exercises sort or filter today; the helpers exist so feature tickets that need them opt in without re-litigating the grammar.

The grammar (from docs/api-conventions.md):

  • ?sort=<field> ascending, ?sort=-<field> descending. Multiple comma-separated for tie-break: ?sort=-created_at,name.
  • ?filter[<field>]=<value> equality. Multiple filters combine with AND.

Unknown sort or filter keys must return 400 invalid_body.

Scope

Add to lib/api/query.ts (new file, alongside pagination.ts):

  • parseSort(searchParams, allowedFields: readonly string[]) — returns either { ok: true; sort: Array<{ field: string; dir: "asc" | "desc" }> } or { ok: false }. Empty input → empty array, still ok.
  • parseFilter(searchParams, allowedFields: readonly string[]) — returns either { ok: true; filter: Record<string, string> } or { ok: false }. Empty input → empty object, still ok.
  • Both helpers reject unknown fields (so a typo doesn't silently no-op).
  • Optional: zod schema helpers for typed integration in route handlers that want the result inferred.

Pair each helper with focused unit tests covering: empty input, valid input, unknown field, malformed bracket syntax, repeated keys.

Document a minimal usage example in docs/api-conventions.md (an aside inside the existing §"Sort and filter grammar", not a new section).

Acceptance criteria

  • lib/api/query.ts exports parseSort and parseFilter with strict TypeScript types.
  • tests/api/query.test.ts covers happy paths and rejection paths.
  • No route adopts the helpers in this ticket — applying them is per-feature work.
  • docs/api-conventions.md §"Sort and filter grammar" carries a usage example.

Out of scope

  • Applying sort/filter to any existing endpoint. Feature tickets pull them in as needed.
  • Server-side filter-by-relation, range queries (?filter[created_at][gt]=…), or full-text search. The current grammar is equality-only; richer forms get their own ADR or ticket if/when needed.

Composes with

#179 (PR #190), docs/api-conventions.md §"Sort and filter grammar".

Part of

#176

Build reusable query-string parsing helpers for the sort and filter grammar documented in `docs/api-conventions.md` §"Sort and filter grammar". No endpoint exercises sort or filter today; the helpers exist so feature tickets that need them opt in without re-litigating the grammar. The grammar (from `docs/api-conventions.md`): - `?sort=<field>` ascending, `?sort=-<field>` descending. Multiple comma-separated for tie-break: `?sort=-created_at,name`. - `?filter[<field>]=<value>` equality. Multiple filters combine with AND. Unknown sort or filter keys must return `400 invalid_body`. ## Scope Add to `lib/api/query.ts` (new file, alongside `pagination.ts`): - `parseSort(searchParams, allowedFields: readonly string[])` — returns either `{ ok: true; sort: Array<{ field: string; dir: "asc" | "desc" }> }` or `{ ok: false }`. Empty input → empty array, still `ok`. - `parseFilter(searchParams, allowedFields: readonly string[])` — returns either `{ ok: true; filter: Record<string, string> }` or `{ ok: false }`. Empty input → empty object, still `ok`. - Both helpers reject unknown fields (so a typo doesn't silently no-op). - Optional: `zod` schema helpers for typed integration in route handlers that want the result inferred. Pair each helper with focused unit tests covering: empty input, valid input, unknown field, malformed bracket syntax, repeated keys. Document a minimal usage example in `docs/api-conventions.md` (an aside inside the existing §"Sort and filter grammar", not a new section). ## Acceptance criteria - [ ] `lib/api/query.ts` exports `parseSort` and `parseFilter` with strict TypeScript types. - [ ] `tests/api/query.test.ts` covers happy paths and rejection paths. - [ ] No route adopts the helpers in this ticket — applying them is per-feature work. - [ ] `docs/api-conventions.md` §"Sort and filter grammar" carries a usage example. ## Out of scope - Applying sort/filter to any existing endpoint. Feature tickets pull them in as needed. - Server-side filter-by-relation, range queries (`?filter[created_at][gt]=…`), or full-text search. The current grammar is equality-only; richer forms get their own ADR or ticket if/when needed. ## Composes with #179 (PR #190), `docs/api-conventions.md` §"Sort and filter grammar". ## Part of #176
james closed this issue 2026-06-21 18:25:59 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
james/carol#192
No description provided.