api-pagination-filtering-sorting
HTTP query parameter conventions for pagination, filtering, sorting, and search with standardized response metadata.
Skill by ajyadav013
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/ajyadav013-api-pagination-filtering-sorting
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: backend, agent-building
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 26, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/api-pagination-filtering-sorting
What's inside
- Skill name
api-pagination-filtering-sorting- Description
- HTTP query parameter conventions for pagination, filtering, sorting, and search with standardized response metadata. Use when designing list endpoints or building repositories that turn query params into SQL.
- License
- MIT
- Instructions
- 350 lines in SKILL.md · view on GitHub
Before installing
- Instructions call the network
Files (4)
- SKILL.md
- query-params-conventions.md · references/
- repo-evidence.md · references/
- response-metadata.md · references/
SKILL.md (first lines)
Standardize HTTP query parameter conventions and response metadata for paginated, filtered, and sorted list endpoints.
## When to use
- Designing a new list endpoint with pagination, filtering, or sorting
- Implementing multi-value or hierarchical filters (e.g., segment, family, class filters)
- Building repository/query builder layers that translate query params to SQL
- Adding search across multiple fields to a list endpoint
- Standardizing response metadata across paginated endpoints
- Reviewing endpoint consistency for pagination patterns
- Adding sort_by/order_by capabilities to existing endpoints
- Implementing cursor-based pagination for large datasets (complement to offset-based)
## Core conventions
1. **Pagination styles**: Two common patterns emerge—(a) `page` (1-indexed) + `page_size` with `total_pages` in response; (b) `limit` + `offset` (0-indexed) with `has_next` boolean. Pattern (a) is friendlier for UI pagination controls; pattern (b) is more SQL-native. Choose one per service; mixing within a service confuses clients. `page_size` or `limit` should have a `ge=1, le=<MAX>` constraint (common max: 100 or 1000).
2. **Offset calculation**: When using `page`/`page_size`, calculate `offset = (page - 1) * page_size` in the route handler or service layer before passing to repository. When using `limit`/`offset`, pass directly. Both approaches translate to `LIMIT {limit} OFFSET {offset}` in SQL.
3. **Response pagination metadata**: Standardize on a `PaginationInfo` or inline fields embedded in the data response. Common fields: `page` (current page, 1-indexed), `page_size` or `limit` (records per page), `total` or `total_records` (total count across all pages), `total_pages` (ceiling division: `(total + page_size - 1) // page_size`), `has_next` (boolean: `(offset + limit) < total` or `page < total_pages`), optional `has_prev` (boolean: `page > 1` or `offset > 0`). Return metadata alongside `data` list in the response envelope.
4. **Multi-value filters via FastAPI `Query`**: For filters that accept multiple values (e.g., `status`, `store_ids`, `segment_codes`), use `Optional[List[str]] = Query(None, description="...")`. The client sends `?status=pending&status=approved` or `?status[]=pending&status[]=approved` (FastAPI accepts both). In the query builder, translate to SQL `IN` clause or `ANY(ARRAY[...])`.
5. **Comma-separated multi-value filters**: Some endpoints accept comma-separated values in a single param (e.g., `?items=ITEM-001,ITEM-002,ITEM-003`). Use `Optional[str] = Query(None)` and split by comma in the service or repository layer before building SQL. This pattern is common for legacy APIs or when the client cannot send array query params.
6. **Hierarchical filters**: Product or location hierarchies (e.g., segment → family → class → brick; zone → format → state → region → city → store) use separate query params for each level. Each is optional; when provided, it narrows results to that level. Example: `?segment=BEVERAGES&family=SOFT_DRINKS&class=COLA`. Query builder applies `WHERE` clauses for each non-null filter. Some services support both singular and plural param names (`?store=...` and `?stores=...`); prefer plural for multi-value, singular for single value.
7. **Sorting via `sort_by` + `sort_order` or `order_by` + `direction`**: Two naming conventions—`sort_by` (field name) + `sort_order` (asc/desc) or `order_by` + `direction`. Choose one per service. Use FastAPI `Query` with `regex="^(ASC|DESC)$"` or `regex="^(asc|desc)$"` for order validation. Map user-facing sort field names (e.g., `doh`, `stock`, `sales`) to actual column names in query builder via a `sort_mapping` dict. Default sort is usually `created_at DESC` or a domain-specific default (e.g., `total_actual_qty DESC` for forecast data).
8. **QueryBuilder pattern**: Encapsulate SQL construction in a `QueryBuilder` class. It receives filters, pagination params, and sort params; returns `(query, params)` tuple with parameterized placeholders (`$1, $2, ...` for PostgreSQL, `?` for others). The builder resets params per query via `_reset_params()` and adds params via `_add_param(value)` returning a placeholder. Separate methods for data query (`build_data_query`) and count query (`build_count_query`) sharing the same filter logic.
9. **Repository layer pagination**: The repository fetches two results in parallel—`(records_data, total_count)`—via `asyncio.gather` or sequential calls. It executes the count query to get `total_count`, then executes the data query with `LIMIT/OFFSET`. Service layer constructs the response object with data + pagination metadata. For download endpoints (no pagination), omit `LIMIT/OFFSET` from the query.
10. **Search across multiple fields**: A single `search` query param applies a case-insensitive substring match across multiple columns. In SQL, use `WHERE (LOWER(field1) LIKE LOWER(:search) OR LOWER(field2) LIKE LOWER(:search) OR ...)` with param `%{search}%`. Some implementations use `ILIKE` (PostgreSQL) or full-text search. Common searchable fields: item codes, descriptions, store IDs, order IDs.
11. **Pydantic models for query params**: Define a `QueryParams` Pydantic model (e.g., `InventoryQueryParams`, `ForecastQuery`) to encapsulate all filters, pagination, sorting, and search params. This separates route handler param extraction from business logic. The model can provide helper methods like `@property def limit(self)` to derive limit from `page_size` or compute `offset` from `page` and `page_size`.
12. **FastAPI route handler**: Extract query params via `Query()` for primitive types or depend on Pydantic model. Calculate `offset = (page - 1) * page_size` if needed. Call service layer with `query_params` object or individual params. Return response via `ResponseData.ok(data=..., pagination=...)` or a typed response model wrapping data + metadata.
13. **Default and max constraints**: Pagination params should have defaults and constraints: `page: int = Query(1, ge=1)`, `page_size: int = Query(20, ge=1, le=100)`, `limit: int = Query(20, ge=1, le=1000)`, `offset: int = Query(0, ge=0)`. Document max values in endpoint docstring. Constants like `DEFAULT_PAGE_SIZE = 20`, `MAX_PAGE_SIZE = 1000` centralize these values.
14. **RBAC / hierarchy access control**: Some endpoints filter results by user's hierarchy access (e.g., user can only see data for their assigned stores or segments). This is modeled as `List[HierarchyFilter]` derived from user context (x-user-data JWT). The query builder applies RBAC filters as additional `WHERE` clauses (e.g., `WHERE (segment = ANY(:allowed_segments) OR :allowed_segments = '{all}')`). Cross-reference `python-dao-and-database` for DAO-level RLS patterns.
15. **Caching paginated responses**: For expensive queries, cache results by a key derived from `(query_params, hierarchy_filters, org_id, run_id)`. Serialize the Pydantic response model to JSON for cache storage. Cache TTL is typically 1 hour. Invalidate cache on data writes. Use Redis or in-memory cache. Avoid caching every page individually; instead cache the full result set or the first page and accept cache misses for deeper pages.
16. **Cursor/keyset pagination — and *why* it beats offset for large or mutating sets**: offset pagination (`LIMIT/OFFSET`) has two failure modes the conventions above don't fix. **Correctness:** when rows are inserted or deleted between two page fetches, the offset shifts, so the client silently **skips rows or sees the same row twice** across page boundaries. **Performance:** the database must scan and discard all `offset` rows before returning the page, so deep pages (`OFFSET 100000`) degrade linearly. **Cursor (keyset) pagination** fixes both by paginating *relative to a stable ordering key* instead of a numeric skip: `WHERE (sort_key, id) > (:last_sort_key, :last_id) ORDER BY sort_key, id LIMIT :n`. Return an **opaque, encoded `next_cursor`** (the last row's ordering key(s) — never a raw offset the client can tamper with) plus `has_next`. It requires a **total, stable sort** — append a unique tiebreaker (e.g. `id`) so ties can't reorder between requests. Trade-off: no "jump to page 50" and no exact `total_pages`. Use offset for small, bounded, human-paged lists; use cursor for infinite scroll, large tables, and any list that mutates under the reader.
> The offset-skips-rows / deep-page-cost rationale and the opaque-cursor convention follow common API design canon (e.g. Stripe's list pagination). Stack-agnostic; the `(sort_key, id)` keyset predicate maps to any ordered store.
## Skeleton / example
```python
# models.py
from typing import Optional, List
from pydantic import BaseModel, Field
class QueryParams(BaseModel):
"""Query parameters for list endpoint."""
# Pagination (page/page_size style)
page: int = Field(default=1, ge=1, description="Page number (1-indexed)")
page_size: int = Field(default=20, ge=1, le=100, description="Records per page")
# Sorting
sort_by: str = Field(default="created_at", description="Field to sort by")
sort_order: str = Field(default="desc", description="Sort direction: asc or desc")
# Search
search: Optional[str] = Field(None, description="Search text")
# Multi-value filters
status: Optional[List[str]] = Field(None, description="Filter by status")
store_ids: Optional[List[str]] = Field(None, description="Filter by store IDs")
# Hierarchical filters
segment: Optional[str] = Field(None, description="Product segment")
family: Optional[str] = Field(None, description="Product family")
@property
def offset(self) -> int:
"""Calculate offset from page and page_size."""
return (self.page - 1) * self.page_size
class PaginationInfo(BaseModel):
"""Pagination metadata."""
page: int = Field(..., description="Current page number")
page_size: int = Field(..., description="Records per page")
total_records: int = Field(..., description="Total number of records")
total_pages: int = Field(..., description="Total number of pages")
has_next: bool = Field(..., description="Whether more records are available")
class ItemListData(BaseModel):
"""Response data for item list."""
data: List[dict] = Field(default_factory=list, description="List of records")
pagination: PaginationInfo = Field(..., description="Pagination metadata")
```
```python
# query_builder.py
from typing import Dict, List, Any, Tuple
class ItemQueryBuilder:
"""Builds SQL queries for item list with filters, sorting, pagination."""
def __init__(self, schema: str, table: str):
self.schema = schema
self.table = table
self._params: List[Any] = []
self._param_index = 1
def build_data_query(
self,
query_params: QueryParams,
limit: int,
offset: int
) -> Tuple[str, List[Any]]:
"""Build main query with pagination."""
self._reset_params()From ajyadav013/claude-kit, MIT.
More from ajyadav013/claude-kit
- 0.602score
design-patterns-and-conventions
ajyadav013
Cross-cutting design patterns, naming, folder layout, and anti-patterns for production Python/FastAPI backends.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
auth-and-rbac
ajyadav013
FastAPI auth patterns — session/JWT chains, argon2id hashing, pyotp TOTP/Email OTP, role-based access control, x-user-data gateway forwarding.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
data-engineering-bigquery-gcs
ajyadav013
BigQuery medallion architecture (bronze/silver/gold), parameterized queries, MERGE upserts, partitioning, CDC dedup, Temporal orchestration.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
cron-and-scheduled-jobs
ajyadav013
Scheduled jobs across two mechanisms — Kubernetes CronJobs (schedule in Helm values, MODE=cron) and Temporal Schedules.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
api-and-interface-design
ajyadav013
Stable API and interface design patterns.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
async-python-patterns
ajyadav013
Async Python for high-performance services.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
code-simplification
ajyadav013
Simplifies/refactors working code for clarity without changing behavior.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
backend-repo-architecture
ajyadav013
Canonical backend repository structure for Python/FastAPI — multi-mode entrypoint, app factory, ConnectionManager, BaseDao, flat vs versioned layout.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
docker-shared
ajyadav013
Shared Docker building blocks — base images for private registries, .dockerignore conventions, compose fragment reuse with YAML anchors.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
dockerfile-backend
ajyadav013
Multi-stage Dockerfiles for Python/FastAPI backends — builder vs runtime, slim vs alpine, system deps, layer caching, non-root users.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
anthropic-vertex-integration
ajyadav013
Claude on Vertex AI via the AnthropicVertex SDK — lazy ADC client init, env-based project/region resolution, async helpers, backoff retry.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
distributed-systems-patterns
ajyadav013
Distributed data placement and replication — consistent hashing/vnodes, sharding, N/W/R quorums, KV-store and cache anatomy, gossip failure detection, B-tree…
SkillBFreshness: B★ 14Claude Code +9
Signals
- Stars
- 14
- Forks
- 5
- Open issues
- 9
- Last commit (this folder)
- Aug 22, 2026 (2 months ago)
- Last release
- Sep 7, 2026 (1 month ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/ajyadav013/claude-kit
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from ajyadav013
- 0.602score
anthropic-vertex-integration
ajyadav013
Claude on Vertex AI via the AnthropicVertex SDK — lazy ADC client init, env-based project/region resolution, async helpers, backoff retry.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
dockerfile-backend
ajyadav013
Multi-stage Dockerfiles for Python/FastAPI backends — builder vs runtime, slim vs alpine, system deps, layer caching, non-root users.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
code-simplification
ajyadav013
Simplifies/refactors working code for clarity without changing behavior.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
cron-and-scheduled-jobs
ajyadav013
Scheduled jobs across two mechanisms — Kubernetes CronJobs (schedule in Helm values, MODE=cron) and Temporal Schedules.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
docker-shared
ajyadav013
Shared Docker building blocks — base images for private registries, .dockerignore conventions, compose fragment reuse with YAML anchors.
SkillBFreshness: B★ 14Claude Code +9 - 0.602score
api-and-interface-design
ajyadav013
Stable API and interface design patterns.
SkillBFreshness: B★ 14Claude Code +9
Cite this page
api-pagination-filtering-sorting skill. Agent Mart. https://agentmart.dev/skills/ajyadav013-api-pagination-filtering-sorting (last updated 2026-10-24)