Skip to content

Multiple APIs Versioning Example

The example demonstrates two independent versioned APIs (public and private) inside one application: each aggregating sub-application gets its own VersioningMiddleware, and their versions do not affect each other.

The example code is on GitHub.

Run it locally

git clone https://github.com/feodor-ra/fastapi-easy-versioning.git
uvx --python=3.14 --from="fastapi[standard]" --with="fastapi-easy-versioning" fastapi dev fastapi-easy-versioning/examples/multiple_versioning.py

The example contains the following code:

from fastapi import Depends, FastAPI, middleware
from fastapi_easy_versioning import (
    VersioningMiddleware,
    versioning,
)

app = FastAPI()

public_app = FastAPI(middleware=[middleware.Middleware(VersioningMiddleware)])
public_v1 = FastAPI(api_version=1)
public_v2 = FastAPI(api_version=2)

private_app = FastAPI(middleware=[middleware.Middleware(VersioningMiddleware)])
private_v1 = FastAPI(api_version=1)
private_v2 = FastAPI(api_version=2)

app.mount("/api/public", public_app)
public_app.mount("/v1", public_v1)
public_app.mount("/v2", public_v2)

app.mount("/api/private", private_app)
private_app.mount("/v1", private_v1)
private_app.mount("/v2", private_v2)


@private_v1.get("/endpoint", dependencies=[Depends(versioning(until=1))])
def private_endpoint() -> str:
    return "I'm v1 private endpoint"


@private_v1.get("/another-endpoint", dependencies=[Depends(versioning())])
def private_another_endpoint() -> str:
    return "I'm v1 private another endpoint"


@private_v2.get("/endpoint", dependencies=[Depends(versioning())])
def private_endpoint_v2() -> str:
    return "I'm v2 private endpoint"


@public_v1.get("/endpoint", dependencies=[Depends(versioning(until=1))])
def public_endpoint() -> str:
    return "I'm v1 public endpoint"


@public_v1.get("/another-endpoint", dependencies=[Depends(versioning())])
def public_another_endpoint() -> str:
    return "I'm v1 public another endpoint"


@public_v2.get("/endpoint", dependencies=[Depends(versioning())])
def public_endpoint_v2() -> str:
    return "I'm v2 public endpoint"

This code creates two independent versioned APIs: public and private. Each has two versions (v1 and v2). Swagger documentation for them is available at:

The resulting structure is as follows:

  • In the public API:
  • /endpoint is available only in version v1 (with until=1 restriction)
  • /another-endpoint is available in all versions (starting from v1)
  • in v2, a new /endpoint is added, which overrides the version from v1

  • In the private API:

  • /endpoint is available only in version v1 (with until=1 restriction)
  • /another-endpoint is available in all versions (starting from v1)
  • in v2, a new /endpoint is added, which overrides the version from v1

Both APIs operate independently thanks to the use of separate VersioningMiddleware instances.

graph TD
    A[Endpoint Availability] --> B[Public API]
    A --> C[Private API]

    B --> B1[v1<br/>api_version=1]
    B --> B2[v2<br/>api_version=2]

    C --> C1[v1<br/>api_version=1]
    C --> C2[v2<br/>api_version=2]

    B1 --> B11["/endpoint ✓<br/>(until=1)"]:::available
    B1 --> B12["/another-endpoint ✓"]:::available

    B2 --> B21["/endpoint ✓<br/>(from v2)"]:::available
    B2 --> B22["/another-endpoint ✓"]:::available

    C1 --> C11["/endpoint ✓<br/>(until=1)"]:::available
    C1 --> C12["/another-endpoint ✓"]:::available

    C2 --> C21["/endpoint ✓<br/>(from v2)"]:::available
    C2 --> C22["/another-endpoint ✓"]:::available

    classDef available fill:#90EE90,stroke:#333,color:#1b1b1b