Metadata-Version: 2.4
Name: verselect
Version: 0.3.0
Summary: Header-based routing for API versioning in FastAPI
Author-email: Bogdan <evstrat.bg@gmail.com>
License-File: LICENSE
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: AsyncIO
Classifier: Framework :: FastAPI
Classifier: Framework :: Pydantic
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Internet
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: fastapi>=0.128.0
Requires-Dist: httpx>=0.28.1
Requires-Dist: jinja2>=3.1.6
Requires-Dist: uvicorn>=0.40.0
Description-Content-Type: text/markdown

# verselect

Header-based version routing for FastAPI.

`verselect` routes requests based on a date header (for example, `X-API-VERSION: 2022-02-02`). If a
client sends a version that does not exist, the request falls back to the closest lower version.
Unversioned routes are supported alongside versioned ones.

Русская версия: `README.ru.md`.

## Highlights

- Header-driven routing with a "closest lower version" fallback
- Per-version OpenAPI schemas with a simple versions dashboard
- Works with standard FastAPI routers and middleware

## Install

```bash
pip install verselect
```

## Quickstart

```python
from contextvars import ContextVar
from datetime import date

from fastapi import APIRouter
from starlette.responses import Response

from verselect import HeaderRoutingFastAPI

api_version_var: ContextVar[date] = ContextVar("api_version")
router = APIRouter(prefix="/v1")
webhook_router = APIRouter(prefix="/v1")


@router.get("/users")
def users():
    return Response(f"Hello from {api_version_var.get()}", media_type="text/plain")


@webhook_router.post("/webhooks")
def webhooks():
    return {"saved": True}


app = HeaderRoutingFastAPI(
    api_version_header_name="X-API-VERSION",
    api_version_var=api_version_var,
)

app.add_header_versioned_routers(router, header_value="2022-01-10")
app.add_header_versioned_routers(router, header_value="2022-02-11")
app.add_unversioned_routers(webhook_router)
```

Send a request with a version header:

```bash
curl -H "X-API-VERSION: 2022-02-11" http://localhost:8000/v1/users
```

## Version rules

- Version format: ISO 8601 date (`YYYY-MM-DD`).
- Exact matches win.
- If there is no exact match, the closest lower version is selected.
- If the requested version is older than the oldest available, a `404` is returned.

## OpenAPI and docs

- `/openapi.json?version=YYYY-MM-DD` returns the schema for a specific version.
- `/docs` shows a dashboard of all available versions and links to their docs.

## Development (uv)

```bash
uv sync --dev
uv run ruff check .
uv run ruff format --check .
uv run mypy .
uv run pytest
```

More examples live in `tests/_resources`.
