Pagination and Filtering Schema Patterns
Implement a CI/CD schema validation gate for pagination and filtering query parameters. This workflow enforces strict contract boundaries, prevents unbounded database queries, and standardizes response shapes across distributed services. Align implementation with foundational Schema Design & Validation Patterns to maintain type consistency.
1. Define Strict OpenAPI Query Contracts
Establish baseline query parameter schemas before routing requests. Define explicit limit, offset/cursor, and filter objects with strict enum boundaries and maximum constraints.
# openapi/query-contracts.yaml
paths:
/resources:
get:
parameters:
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 20
- name: status
in: query
schema:
type: string
enum: [active, archived, pending]
- name: cursor
in: query
schema:
type: string
format: base64url
description: Opaque pagination token
Validation Rules:
- Reject
limit > 100with400 Bad Request - Enforce
cursorXORoffset(mutually exclusive parameters) - Validate filter enums at the contract level before execution
2. Configure Spectral Linting for Query Enforcement
Deploy static analysis to catch schema drift before deployment. While runtime checks like Runtime Validation with Zod handle malformed payloads in production, Spectral enforces architectural consistency at merge time.
# .spectral.yaml
rules:
pagination-limit-bound:
description: Ensure pagination limit has explicit min/max bounds
given: $.paths[*][get].parameters[?(@.name=='limit')]
severity: error
then:
field: schema.maximum
function: truthy
filter-enum-required:
description: Filtering parameters must restrict to predefined enums
given: $.paths[*][get].parameters[?(@.name=='status')]
severity: warn
then:
field: schema.enum
function: truthy
Validation Rules:
- Fail PR if
limitlacks a maximum constraint - Warn if filter parameters lack
enumorpatternvalidation - Require
formatorexamplefor cursor strings
3. Integrate CI/CD Gating Pipeline
Automate contract validation in GitHub Actions. For legacy endpoints requiring backward compatibility, consider Joi and Yup for Legacy Systems during phased migrations. Enforce OpenAPI compliance for all new routes via automated pipeline gates.
# .github/workflows/schema-gate.yml
name: Schema Contract Gate
on: [pull_request]
jobs:
validate-schemas:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Spectral
run: npm install -g @stoplight/spectral
- name: Lint OpenAPI Specs
run: spectral lint ./openapi/api.yaml --ruleset .spectral.yaml --fail-severity warn
- name: Run Contract Tests
run: npx openapi-test-runner --spec ./openapi/api.yaml --test-dir ./tests/contracts
Validation Rules:
- Block merge on
errororwarnseverity - Cache Spectral dependencies for sub-10s pipeline execution
- Generate JUnit XML reports for PR annotations
4. Select Pagination Strategy & Mock Configuration
Choose between offset-based and cursor-driven architectures based on dataset volatility. Refer to Cursor vs offset pagination schema design for performance trade-offs. Configure Prism to generate deterministic mock responses.
// prism-mock-config.json
{
"mock": {
"dynamic": false,
"validateRequest": true,
"validateResponse": true,
"rules": {
"pagination": {
"strategy": "cursor",
"mock_response": {
"data": [],
"meta": {
"next_cursor": "eyJpZCI6MTAwfQ==",
"has_more": true
}
}
}
}
}
}
Validation Rules:
- Mock must return
meta.has_moreboolean - Validate
next_cursoris URL-safe base64 - Reject
offset > 10000in mock validation layer
5. Common Pitfalls & Validation Rules
Address frequent contract violations during QA and staging. Implement strict error mapping and fallback logic to prevent cascading failures in distributed systems.
Validation Rules:
- Mandate
meta.paginationobject in all list endpoints - Return
has_more: falsewhen dataset exhausted - Standardize on
base64urlformat for cursor encoding
Troubleshooting Paths
| Issue | Diagnosis | Resolution |
|---|---|---|
| Unbounded filter queries causing database timeouts | Missing maximum on limit or unvalidated IN clause arrays |
Add maxItems: 50 to filter array schemas and enforce server-side query planners with index hints |
| Cursor decoding failures in downstream services | Inconsistent base64 padding or URL encoding mismatches | Standardize on base64url format in OpenAPI and decode using RFC 4648 compliant libraries |
| Frontend infinite scroll breaks on empty sets | Missing has_more or total_count in response contract |
Mandate meta.pagination object in all list endpoints and return explicit termination flags |