Skip to main content

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 > 100 with 400 Bad Request
  • Enforce cursor XOR offset (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 limit lacks a maximum constraint
  • Warn if filter parameters lack enum or pattern validation
  • Require format or example for 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 error or warn severity
  • 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_more boolean
  • Validate next_cursor is URL-safe base64
  • Reject offset > 10000 in 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.pagination object in all list endpoints
  • Return has_more: false when dataset exhausted
  • Standardize on base64url format 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