Real‑world examples of versioning APIs with Swagger: practical examples that actually work

If you’re looking for real, working examples of versioning APIs with Swagger: practical examples that go beyond theory, you’re in the right place. Versioning isn’t an academic problem; it’s the thing that decides whether your mobile apps keep working after a deploy or your partners wake up to broken integrations. In this guide, we’ll walk through concrete examples of how to version APIs with Swagger (OpenAPI), from simple URL versioning to header‑based strategies and multi‑spec setups for large platforms. We’ll look at how modern teams in 2024–2025 use OpenAPI 3, tools like Swagger UI and Swagger Codegen, and contract‑testing workflows to keep old and new versions alive without chaos. You’ll see examples of versioning APIs with Swagger: practical examples you can lift directly into your own YAML or JSON, plus commentary on trade‑offs, migration strategies, and how to avoid painting yourself into a corner. No fluff, just opinionated guidance, real examples, and patterns that scale.
Written by
Jamie
Published

Most teams don’t start by arguing about versioning theory. They start with a problem:

“We need to change a field, but 200,000 clients already depend on the current response. How do we not break them?”

That’s where examples of versioning APIs with Swagger: practical examples matter. Let’s start with concrete patterns you’ll see in production systems today.


Example of simple URL versioning in OpenAPI 3

The most common example of API versioning you’ll find in Swagger docs is URL versioning. It’s blunt, obvious, and easy to debug.

openapi: 3.0.3
info:
  title: Orders API
  version: 1.0.0
servers:

  - url: https://api.example.com/v1
paths:
  /orders:
    get:
      summary: List orders (v1)
      operationId: listOrdersV1
      responses:
        '200':
          description: A list of orders
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OrderV1'
components:
  schemas:
    OrderV1:
      type: object
      properties:
        id:
          type: string
        total:
          type: number
          format: float

A typical example of a v2 evolution adds fields without breaking v1. You publish a second spec:

openapi: 3.0.3
info:
  title: Orders API
  version: 2.0.0
servers:

  - url: https://api.example.com/v2
paths:
  /orders:
    get:
      summary: List orders (v2)
      operationId: listOrdersV2
      responses:
        '200':
          description: A list of orders with currency and status
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OrderV2'
components:
  schemas:
    OrderV2:
      allOf:

        - $ref: '#/components/schemas/OrderV1'
        - type: object
          properties:
            currency:
              type: string
              example: USD
            status:
              type: string
              enum: [PENDING, PAID, CANCELED]

This is one of the best examples for teams starting out: two Swagger documents, two base URLs, one codebase behind them. You can even reuse schemas with allOf to keep duplication tolerable.


Path‑segment versioning inside a single Swagger file

Sometimes you don’t want multiple specs. Maybe you’re a small team, or your CI pipeline isn’t ready for multi‑spec publishing. You can keep examples of versioning APIs with Swagger: practical examples in a single OpenAPI file by versioning in the path.

openapi: 3.0.3
info:
  title: Customer API
  version: 1.1.0
servers:

  - url: https://api.example.com
paths:
  /v1/customers/{id}:
    get:
      summary: Get customer (v1)
      operationId: getCustomerV1
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomerV1'

  /v2/customers/{id}:
    get:
      summary: Get customer (v2)
      operationId: getCustomerV2
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomerV2'

In Swagger UI, consumers see both /v1/... and /v2/... side by side. This is a nice example of how to:

  • Keep everything visible in one place
  • Document deprecation notes directly in description fields
  • Gradually migrate clients from v1 to v2

You can mark older endpoints clearly:

    description: |
      Get customer (legacy v1).

      **Deprecated:** Use `/v2/customers/{id}` instead.
    deprecated: true

This pattern shows up frequently in public APIs from fintech and logistics companies where they want new and old versions visible in the same developer portal.


Header‑based versioning: real examples when URLs must stay stable

Some teams can’t change URLs easily. Maybe there’s a firewall rule, a partner contract, or an app store policy tying you to /api. In that case, examples of versioning APIs with Swagger: practical examples often rely on headers.

A common pattern is a custom header like X-API-Version:

openapi: 3.0.3
info:
  title: Inventory API
  version: 2024.1.0
servers:

  - url: https://api.example.com
paths:
  /inventory/items:
    get:
      summary: List inventory items
      parameters:

        - in: header
          name: X-API-Version
          required: false
          schema:
            type: string
            enum: ['1', '2']
          description: |
            Optional API version header.
            If omitted, defaults to version 1.
      responses:
        '200':
          description: Items for requested version.

To give a best example of clarity, some teams split this into separate operations using oneOf in the response schema, but that can get messy. A cleaner approach is to maintain two Swagger specs that share the same path but describe different behavior, and route by header at the gateway (for example, using an API gateway like Kong or Apigee).

Even the Microsoft REST API guidelines discuss versioning strategies, and header‑based approaches remain popular when you can’t afford URL churn.


Media‑type versioning: vendor‑specific content types

Another class of examples of versioning APIs with Swagger: practical examples comes from media‑type versioning. Instead of versioning the URL or a custom header, you version the Accept header:

Accept: application/vnd.example.orders.v2+json

In Swagger / OpenAPI:

paths:
  /orders:
    get:
      summary: List orders with media-type versioning
      responses:
        '200':
          description: Orders response
          content:
            application/vnd.example.orders.v1+json:
              schema:
                $ref: '#/components/schemas/OrderV1'
            application/vnd.example.orders.v2+json:
              schema:
                $ref: '#/components/schemas/OrderV2'

This is a favorite in some large enterprises because:

  • You keep a clean, stable URL surface
  • You can serve multiple representations from the same endpoint

But it’s also easier to misconfigure, and many client libraries make vendor media types awkward. Still, as real examples go, this is common in internal platforms and microservice ecosystems.


Versioning schemas, not just endpoints

One of the subtler examples of versioning APIs with Swagger: practical examples is schema‑only versioning. Instead of advertising new versions via URLs, you evolve the schemas and keep the path stable.

For example, you might keep /users/{id} unchanged, but add a new UserProfileV2 schema used only when a query parameter is present:

paths:
  /users/{id}:
    get:
      summary: Get user
      parameters:

        - in: query
          name: profileVersion
          schema:
            type: string
            enum: ['v1', 'v2']
          description: Optional profile version.
      responses:
        '200':
          description: User profile
          content:
            application/json:
              schema:
                oneOf:

                  - $ref: '#/components/schemas/UserProfileV1'
                  - $ref: '#/components/schemas/UserProfileV2'

You then document the behavior clearly in descriptions and examples. This pattern often appears when a team wants to run an A/B test or gradually introduce additional fields without formally calling it “v2” at the URL level.


Multi‑version Swagger UI: one portal, many specs

By 2024, a lot of API platforms have adopted a pattern where Swagger UI (or ReDoc) presents multiple versioned specs in a single portal. This is one of the best examples of versioning APIs with Swagger: practical examples that scale to dozens of services.

Typical setup:

  • openapi-orders-v1.yaml
  • openapi-orders-v2.yaml
  • openapi-payments-v1.yaml
  • openapi-payments-v2.yaml

Swagger UI can be configured with a list of URLs:

const ui = SwaggerUIBundle({
  urls: [
    { url: '/specs/openapi-orders-v1.yaml', name: 'Orders API v1' },
    { url: '/specs/openapi-orders-v2.yaml', name: 'Orders API v2' },
    { url: '/specs/openapi-payments-v1.yaml', name: 'Payments API v1' },
    { url: '/specs/openapi-payments-v2.yaml', name: 'Payments API v2' }
  ],
  dom_id: '#swagger-ui'
});

This isn’t just convenient; it’s a documentation strategy. It lets you:

  • Keep each version’s contract frozen
  • Show deprecation timelines in descriptions
  • Give partner teams a stable reference for each integration

In 2024–2025, larger organizations often pair this with contract testing (for example, using tools inspired by consumer‑driven contracts) to ensure no breaking changes slip into a “frozen” spec.


Real migration example: evolving a healthcare‑style API safely

Consider a hypothetical healthcare API inspired by public data APIs like those described by the CDC and NIH. You start with patient lab results:

## v1
paths:
  /v1/lab-results/{patientId}:
    get:
      summary: Get lab results (v1)
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LabResultV1'

Later, you need richer metadata, units, and reference ranges. Instead of breaking v1, you add v2:

## v2
paths:
  /v2/lab-results/{patientId}:
    get:
      summary: Get lab results (v2)
      description: Includes units, reference ranges, and LOINC codes.
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LabResultV2'

This example mirrors how real health APIs evolve: keep v1 stable for existing EHR integrations while new partners adopt v2. Swagger makes the contract for each version explicit, which is critical in regulated environments where you may need to document exactly what changed and when.

If you need to support research workflows or public health dashboards, you can also version by date in the info.version field (for example, 2024-09-01) while keeping URL versions shorter. That’s a pattern you’ll see in some open data APIs.


If you look across modern API platforms, a few trends stand out:

  • OpenAPI 3.x has become the default for new examples of versioning APIs with Swagger: practical examples. OpenAPI 2.0 (Swagger 2) is still around, but new tooling is clearly optimized for 3.x.
  • More teams use semantic versioning in info.version (1.2.3) paired with coarse‑grained URL versions (/v1, /v2). This gives them room for non‑breaking changes without forcing a URL change.
  • Contract testing and CI validation are now normal. Many pipelines run openapi-diff or similar tools to check for breaking changes between versions before deploy.
  • There’s a noticeable shift toward backward‑compatible evolution. Instead of constant v2, v3, v4 churn, teams add fields, keep old ones, and only cut a new major version when absolutely necessary.

These trends all favor having clear, well‑maintained Swagger definitions for each version. Your OpenAPI specs become the source of truth for what changed.


Practical tips: picking the right versioning pattern

With all these examples of versioning APIs with Swagger: practical examples in mind, how do you pick a strategy?

Think about:

  • Who are your consumers? Public partners often prefer obvious URL versioning; internal teams might tolerate header or media‑type versioning.
  • How often will you change things? If change is frequent, plan for multiple specs and automated diffing.
  • Regulatory or audit needs? In domains like healthcare or finance, clear versioned contracts help when you need to explain behavior at a specific point in time. That’s one reason public health data APIs from organizations like the CDC tend to document versions explicitly.

In practice, URL versioning plus separate OpenAPI specs gives you the cleanest paper trail and the least confusion.


FAQ: common questions about Swagger and API versioning

Q: Can you give more examples of versioning APIs with Swagger: practical examples for internal microservices?
For internal microservices, teams often skip visible /v2 URLs and instead version by service name and spec file. For example, billing-service-v1.yaml and billing-service-v1.1.yaml, both pointing at the same URL paths. Deployments are coordinated so that consumers know which spec they target. This keeps URLs stable inside the cluster while still giving you explicit contracts.

Q: What’s a good example of avoiding breaking changes without bumping the version?
Additive changes are your friend. Adding new optional fields, new endpoints, or new enum values (if clients ignore unknown values safely) usually doesn’t require a new major version. A concrete example: adding a currency field to OrderV1 while keeping the original fields and defaults. You document the field in Swagger, but keep info.version at 1.1.0 instead of jumping to 2.0.0.

Q: Do I need a new Swagger file for every minor version?
Not necessarily. Many teams only create a new spec when they introduce a breaking change or a new URL version. Minor, backward‑compatible updates can stay in the same file with an updated info.version and a changelog section in the description.

Q: Are there examples include both URL and header versioning together?
Yes. A pattern you see in larger platforms is /v1 and /v2 URLs combined with a header that selects a minor variant, such as X-Feature-Version. Swagger can describe both: versioned paths and optional headers that toggle experimental behavior.

Q: Where can I learn more about API versioning patterns beyond Swagger examples?
While not Swagger‑specific, resources like the Microsoft REST API Guidelines and articles by practitioners such as Martin Fowler provide solid background on versioning strategies and trade‑offs.


Versioning isn’t about finding the “perfect” pattern; it’s about picking a strategy you can live with for years and then documenting it clearly. Swagger and OpenAPI give you the language to express that strategy. The real value comes from how you use that language in your own examples of versioning APIs with Swagger: practical examples that match your constraints, your tooling, and your consumers.

Explore More Using Swagger for API Definition

Discover more examples and insights in this category.

View All Using Swagger for API Definition