patterntypescriptModerate
Filtering and Sorting Query Parameters: Use consistent, predictable conventions
Viewed 0 times
filteringsortingquery-paramssearchpaginationoperators
Problem
Every API team invents its own query param syntax for filtering and sorting (filter[name]=, name_like=, q[name_cont]=). This inconsistency forces consumers to read docs for each endpoint instead of applying a learned model.
Solution
Adopt a consistent convention. A pragmatic approach: use simple key=value for exact match (?status=active), key[operator]=value for comparisons (?createdAt[gte]=2024-01-01), and sort=field or sort=-field (minus prefix for descending) for sorting.
Why
Predictable query param conventions reduce documentation burden and cognitive overhead. Clients can construct queries without consulting docs for each new resource.
Gotchas
- URL bracket syntax (filter[field]) requires proper encoding — some HTTP clients handle it differently.
- Always whitelist allowed filter fields server-side; never pass raw query params into SQL.
- Sorting on non-indexed columns can cause severe performance issues at scale.
Code Snippets
Consistent query param parsing for filter and sort
// GET /users?status=active&createdAt[gte]=2024-01-01&sort=-createdAt
function parseQuery(query: Record<string, string>) {
const filters: Record<string, unknown> = {}
let sort: { field: string; direction: 'asc' | 'desc' } | null = null
for (const [key, value] of Object.entries(query)) {
const bracketMatch = key.match(/^(.+)\[(.+)\]$/)
if (bracketMatch) {
const [, field, op] = bracketMatch
filters[field] = { op, value }
} else if (key === 'sort') {
const desc = value.startsWith('-')
sort = { field: desc ? value.slice(1) : value, direction: desc ? 'desc' : 'asc' }
} else {
filters[key] = value
}
}
return { filters, sort }
}Revisions (0)
No revisions yet.