# Pagination, Filtering and Naming Conventions — OpenAPI / Swagger

Source: https://www.skillbyai.com/en/openapi/d-conventions

> Describe common API conventions consistently in OpenAPI.

## Consistency makes APIs predictable

OpenAPI makes conventions visible, so decide them once and apply them everywhere, ideally captured in an **API style guide** enforced by linting. **Naming**: plural nouns for collections (`/orders`), kebab-case paths, consistent property casing (camelCase or snake_case, never mixed), and verbs only for genuine actions (`/orders/{id}/cancellation` as a resource, or `:cancel` if your guide allows). **Pagination**: prefer **cursor-based** pagination for large or changing collections, with `limit` and `cursor` parameters and a response envelope containing `items` and `nextCursor`; offset pagination is simpler but slower and inconsistent under concurrent inserts. **Filtering and sorting**: query parameters such as `status`, `createdAfter` and `sort=-createdAt`. **Partial responses**: optional `fields` parameters. **Dates**: ISO 8601 `date-time` in UTC. **IDs**: opaque strings, possibly prefixed by type (`ord_...`). Model these patterns as reusable components (a `Page` schema, standard parameters) so every list endpoint looks the same.

## Consistent list endpoints

Every collection returns the same page shape with items and a cursor to the next page.

![Three identical page cards stacked with an arrow from the bottom corner of each to the next.](assets/figures/openapi/section-5-map.svg) — Figure 5.1 — Cursor pagination with a standard page envelope.

## A reusable page envelope for cursor pagination

Every list endpoint returns the same structure.

```yaml
components:
  schemas:
    OrderPage:
      type: object
      required: [items, nextCursor]
      properties:
        items:
          type: array
          items: { $ref: '#/components/schemas/Order' }
        nextCursor:
          type: [string, 'null']
          description: Pass as ?cursor= to get the next page; null when there are no more items
  parameters:
    Sort:
      name: sort
      in: query
      description: Field to sort by; prefix with - for descending
      schema: { type: string, enum: [createdAt, -createdAt, total, -total], default: -createdAt }
    CreatedAfter:
      name: createdAfter
      in: query
      schema: { type: string, format: date-time }

paths:
  /orders:
    get:
      operationId: listOrders
      parameters:
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Cursor'
        - $ref: '#/components/parameters/Sort'
        - $ref: '#/components/parameters/CreatedAfter'
      responses:
        '200':
          description: A page of orders
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OrderPage' }
```

## Write the style guide as lint rules

A style guide in a wiki is forgotten; the same rules expressed as Spectral or Redocly lint rules run on every pull request and keep dozens of APIs consistent.

**Quiz:** Why is cursor-based pagination often preferred for large collections?

- [x] It stays fast and consistent as data changes, unlike large offsets
- [ ] It is easier to implement than every alternative
- [ ] It returns all items at once
- [ ] OpenAPI only supports cursors

*Answer:* It stays fast and consistent as data changes, unlike large offsets. Cursors avoid slow deep offsets and skipped or duplicated items when rows are inserted.
