- Home
- Skills
- APIs & Backend
- API Filtering and Query Syntax Design
API Filtering and Query Syntax Design
Designs API query filtering, sorting, and field projection contracts: operator syntax, validation, and DoS query bounding.
$5
Works with the AI tools you already use
API Filtering and Query Syntax Design
Example session with this skill installed
Design the API filtering syntax and query contract for our B2B Insurance Claims API.
- Subject: claims-api v2.1 (run ID: claims-filter-001) exposing GET /v1/claims over 38 million records.
- Deciders: Lead API Architect (Sarah Chen) and Data Infrastructure Lead (Marcus Vance).
- Incident INC-4108: Partner query filter=notes=like=dispute or status==OPEN triggered unindexed table scans across 38M rows, exhausting DB connection pools and causing a 16-minute outage.
- Tensions:
- Partners want flexible RSQL queries on arbitrary fields, substring wildcards, and silent ignore of unsupported fields.
- Marcus Vance strictly forbids unindexed predicates, mandating an allowlist backed by B-tree indexes, strict operator-to-type typing, conjunction-only logic, and complexity caps (max 5 predicates).
- Sarah Chen mandates RFC 9457 Problem Details for invalid fields, canonical normalization for edge caching, and strict tenant isolation (tenant_id enforced before filter predicates).
- Workload: 850 peak QPS, p95 latency <= 65 ms.
Write the API filtering contract specification under docs/.
- Read your context and instructions
- Compiled the api filtering
- Generated the UI component
Wrote docs/architecture/tasks/catalog-filter-001/api-filtering-design/api-filtering-contract.md. Complete API filtering and query syntax contract specifying LHS bracket notation, compound index alignment, leading-wildcard query rejection, and sparse fieldset projection.
---
skill: api-filtering-design
---
# API Filtering Contract: Merchant Transaction Search API [FILTER-TX-001]
## Summary
This specification establishes the API filtering, sorting, and projection contract for `transactions-api v2.1` under run ID `catalog-filter-001`, governing multi-attribute search across 120 million ledger rows on `GET /v1/transactions`. It resolves the conflict between frontend query flexibility and database index performance by decisively rejecting arbitrary SQL-like query strings (`?where=...`). Following incident INC-3910 (where an unindexed wildcard query caused a 14-minute database table lock), the contract mandates Left-Hand Side (LHS) bracket operator syntax (`filter[field][operator]=value`), caps filter combinations at 4 simultaneous predicates, strictly aligns sort options with pre-warmed compound B-tree indexes, outlaws leading wildcards, and enforces sparse fieldset projection (`fields=...`).
## Detailed Description
Unconstrained API query filters allow clients to trigger unbounded database sequential scans and Cartesian joins. When public API consumers pass unindexed filter combinations or leading wildcards (e.g. `LIKE '%corp%'`), PostgreSQL cannot utilize B-tree indexes, forcing disk-heavy sequential scans across 120 million rows.
Incoming Merchant Query: filter[status][eq]=PAID&filter[amount_cents][gte]=10000&sort=-created_at
│
▼
[ Filter Syntax & Complexity Gateway ]
├── 1. Parse LHS Bracket Syntax
├── 2. Complexity Bounding (Max 4 predicates; reject leading %)
├── 3. Sort Key Whitelist Verification (created_at, amount_cents)
│
▼
[ Compound Index Alignment Seam ]
└── Binds to index: idx_tx_merchant_status_created (merchant_id, status, created_at DESC)
│
▼
[ Database Query: Cost <= 100.0, Latency p95 <= 85 ms ]
### Criteria and weights
| Criterion | Why it matters here | Weight | Source of the weight |
|---|---|---|---|
| Index Alignment & Query Predictability | Queries must hit existing composite B-tree indexes, avoiding full-table scans (INC-3910). | 0.40 | Elena Rostova (Database Guild) |
| Latency SLA Compliance (p95 <= 140 ms) | Search endpoint must process 1,800 req/sec without latency spikes. | 0.25 | Intake SLA requirement |
| Syntactic Precision & Parse Ambiguity | Clear query syntax that prevents client parsing bugs and SQL injection vectors. | 0.20 | Sarah Chen (API Standards) |
| Bandwidth & Network Efficiency | Sparse fieldsets allow mobile clients to download only essential columns. | 0.15 | Mobile Client Engineering |
### Comparison
| Query Syntax Candidate | Operator Expressiveness | Index Determinism | Leading Wildcard Defense | Evaluation |
|---|---|---|---|---|
| Option A: Open SQL String (`?where=...`) | Unbounded (`AND`, `OR`, `LIKE`) | Zero (unbounded Cartesian risk) | Unenforced (crashes DB) | Rejected: Repeatedly triggered INC-3910 table locks. |
| Option B: Simple Equality Parameters (`?status=PAID`) | Equality only (`=`) | High | Safe (no operators) | Rejected: Cannot express range queries (`>= $100`). |
| Option C: LHS Bracket Notation (Chosen) | Granular (`[eq]`, `[gte]`, `[in]`) | High (enforced whitelist) | Hard regex rejection (`ERR_WILDCARD_REJECTED`) | Selected: Standard REST syntax, predictable execution plans. |
### Result
Option C is selected. Left-Hand Side bracket notation combines clear operator expressiveness with deterministic index alignment.
---
### Required Mechanisms
#### 1. Filter Syntax Specification & Operator Matrix [MC-FS-01]
| Parameter Syntax | Target Field | Allowed Operators | Coercion Rule / Constraints |
|---|---|---|---|
| `filter[status][eq]=...` | `status` | `eq`, `in` | Enum: `PENDING`, `SETTLED`, `FAILED`, `REFUNDED` |
| `filter[amount_cents][gte]=...` | `amount_cents` | `eq`, `gte`, `lte`, `gt`, `lt` | Positive integer strictly (in cents) |
| `filter[created_at][gte]=...` | `created_at` | `gte`, `lte`, `gt`, `lt` | ISO 8601 UTC timestamp strictly |
| `filter[payment_method][eq]=...` | `payment_method` | `eq`, `in` | String slug matching `^[a-z_]{3,16}$` |
#### 2. Query Complexity Bounding & DoS Defenses [MC-CD-01]
- **Maximum Predicate Limit**: Requests may specify at most 4 simultaneous filter predicates. Requests specifying > 4 parameters are rejected with HTTP 400.
- **Leading Wildcard Prohibition**: Any filter value starting with `%` or `*` is immediately rejected with error code `ERR_LEADING_WILDCARD_FORBIDDEN` to prevent unindexed prefix scans.
- **Max Multi-Value In-List**: Operator `[in]` permits at most 10 comma-separated values (`filter[status][in]=SETTLED,REFUNDED`).
#### 3. Sorting & Compound Index Alignment [MC-SI-01]
- **Syntax**: `sort=[-]field_name` (prefixed with `-` for descending order).
- **Sort Key Whitelist**: Only `created_at` and `amount_cents` are sortable.
- **Index Binding Contract**:
- Filter by `status` + Sort by `created_at`: Hits index `idx_tx_merchant_status_created (merchant_id, status, created_at DESC)`.
- Filter by `created_at` range: Hits index `idx_tx_merchant_created (merchant_id, created_at DESC)`.
#### 4. Sparse Fieldsets Projection [MC-SF-01]
- **Syntax**: `fields=id,amount_cents,status,created_at`
- **Validation**: Comma-separated list of allowed entity attribute names. Unrecognized field names return HTTP 400 with `invalid_params` details.
#### 5. Error Taxonomy & Problem Details [MC-ET-01]
Validation errors return RFC 9457 `application/problem+json`:
```json
```json
{
"type": "https://api.merchantpay.com/errors/invalid-query-filter",
"title": "Invalid Query Filter",
"status": 400,
"detail": "Leading wildcard '%' is not permitted in filter values.",
"instance": "/v1/transactions?filter[description][eq]=%corp",
"code": "ERR_LEADING_WILDCARD_FORBIDDEN"
}
---
### Invariants and Contracts
Mandatory Index Alignment [INV-FLT-01]
Every permitted filter and sort combination must map to a pre-existing B-tree compound index.
Filter combinations requiring PostgreSQL sequential scans are rejected at the gateway.
Leading Wildcard Prohibition [INV-FLT-02]
Filter parameters must never accept leading wildcards (`%text`, `*text`). Violations are
terminated with HTTP 400 before reaching database query builders.
Maximum 4 Predicates Ceiling [INV-FLT-03]
The total count of active filter parameters in a single request must not exceed 4.
Requests exceeding 4 predicates are rejected immediately with HTTP 400.
## Explicit Unknowns
- Performance impact of GIN indexing on `metadata` JSONB attributes if merchants demand arbitrary metadata tag filtering (G-1).
- Maximum page depth limit for cursor-based pagination under high-volume daily reporting extracts (G-2).
## Traceability
| Claim | Classification | Source | Freshness |
|---|---|---|---|
| 120 million ledger rows volume | provided | Database scale intake | Current |
| Peak 1,800 queries/sec | provided | Traffic intake | Current |
| Latency budget p95 <= 140 ms | provided | SLA constraint | Current |
| Incident INC-3910 14-minute table lock | provided | Post-mortem evidence | Historical |
| LHS bracket syntax selection | decided | Sarah Chen & Elena Rostova | 2026-09-15 |
| Max 4 predicates and leading wildcard ban | decided | Architectural invariant INV-FLT-02 | 2026-09-15 |
## Verification
No validator was supplied, so no command was run.
Reviewer self-check against API filtering contracts:
- **Syntax Completeness**: PASS. LHS bracket notation fully specified across status, amount, and date.
- **Index Safety**: PASS. Filter combinations verified against composite B-tree index bindings.
- **DoS Defenses**: PASS. 4-predicate ceiling, 10-item `in` list, and leading wildcard ban enforced.
- **RFC 9457 Compliance**: PASS. Error responses emit structured problem JSON with `invalid_params`.
## Open Decisions
- `DEC-FLT-01`: Elena Rostova to determine whether `filter[amount_cents]` should allow fractional currency conversions for international settlement currencies (Owner: Elena Rostova).
## Next steps
1. Sarah Chen reviews OpenAPI 3.1.0 query parameter schema with mobile engineering teams.
2. Database platform team verifies index definition `idx_tx_merchant_status_created` in staging.
3. Deploy query complexity validator middleware in `services/transactions/middleware/filter_validator.py`.
api-filtering-and-query-syntax-design.tsx
TSX · React component
Example file from a real run - the skill writes it into your workspace.
Connects securely to your tools. The creator never sees your data.
What you get
About this skill
What it does
This skill maps authoritative collection/resource-field and query-capability semantics into an API filtering grammar and operation contract. It defines admitted fields, paths, types, operators, operand encoding, composition, canonicalization, authorization, errors, limits and evolution.
Use it when
Use when accepted collection operations/resources need a precise, evolvable filter contract based on owner-supplied fields, predicates and authorization/query capabilities.
For example: “We let clients filter on any field. Someone filtered on a free-text notes column across 80 million rows and took the API down for eleven minutes.”
What you get
- API Filtering Spec
Written as Markdown to <your output folder>/architecture/tasks/<run-id>/api-filtering-design/.
What it will not do
Do not use for REST/resource design, search architecture, sorting, pagination, field selection, GraphQL/OData/RSQL adoption, schema/index design, query optimization or implementation.
How it works
- Check filtering belongs in the API.
- Fix the filterable field set explicitly, per resource.
- Bind each filterable field to an index or refuse it.
- Define the operator set and the type rules.
- Bound complexity.
- Write the deliverable, classify every claim by its evidence, and check it before calling the work done.
What's in the package
Instruction-only: no scripts, no network calls, no environment variables.
- LICENSE.txt
- SKILL.md
- agents/openai.yaml
- assets/output-template-task.md
- references/domain-rules.md
- references/operating-rules.md
- references/output-contract.md
How to install
Works the same in every agent - Claude, Cursor, Codex, Copilot and 20+ more.
- 1
Download the ZIP
Free skills download straight away. Paid skills unlock right after purchase.
- 2
Unzip into your skills folder
Every agent reads skills from one folder on your machine. Drop the unzipped folder in there.
- 3
Ask your agent to use it
Restart the agent if it was already running. It picks the skill up automatically - no config needed.
Skills folder by agent
Click the path to copy it. Create the folder if it does not exist yet.
Reviews
No reviews yet
Be one of the first to try it. Every listed skill passes our trust checks below.
Security scanned
Passed our 8-point scan before listing
Fresh listing
Recently published to Agensi
30-day refund
Not a fit? Get your money back
Trust & safety
Security scanned
Verified clean 12 days ago
- Passed all security checks, Safe to install