fastapi-cbx
Code is disciplined. Reality is natural selection. One scenario, one route.
A precise complement to the FastAPI ecosystem, unifying layered routing patterns and strict resource lifecycle management into a clean, production‑ready solution.
Originally proposed and contributed to FastAPI as PR #15447.
🔥 Featured Case Study:
How we refactored vLLM’s API server and cut structural boilerplate by ~50%
👉 Read: Refactoring vLLM API Architecture
Overview
fastapi-cbx introduces three orthogonal, scenario‑driven routing patterns — FR, CBV, and CBR — each designed for a clear, distinct category of business logic. Built with non‑invasive composition, it fully aligns with FastAPI’s native decorator style and enforces strict resource lifecycle placement rules: heavyweight global resources initialized in __init__, lightweight request‑scoped resources managed via Depends.
Features
- Adds two scenario-driven class-based routing patterns to native FastAPI
- HTTP and WebSocket endpoints bound by the same decorator style
- Ultra-lightweight: ~130 lines of clean code
- 100% test coverage
- No monkey patching, no metaprogramming, no hidden magic
- Fully backward compatible, no breaking changes
- Zero runtime overhead
- Native typing & dependency injection support
- Predictable, transparent behavior
- Minimal API surface, easy to maintain
Quick Start (30 Seconds)
fastapi-cbx provides CBR (Class-Based Route), an original, intuitive, high-performance class-based routing utility for FastAPI.
Concept-focused, zero business logic
Install
pip install fastapi-cbx fastapi uvicorn
Minimal Example (main.py)
import logging
from typing import Dict
from fastapi import FastAPI, APIRouter, Response, status
from cbx import cbr
from pydantic import BaseModel
@cbr(router=APIRouter(prefix="/cbr"))
class MyCBR:
logger = logging.getLogger(__qualname__)
class CBRModel(BaseModel):
key: str = "CBR"
value: str = "Class-based route for complex business logic with multiple endpoints and method-level dependencies"
def __init__(self, **kwargs: Dict[str, str]):
self.heavies = {
"name": "fastapi-cbx",
"description": "Minimal class-based routing extension for FastAPI"
}
self.heavies.update(kwargs)
@cbr.get("/welcome", summary="Welcome to fastapi-cbx")
@staticmethod
async def welcome(response: Response) -> str: # Also supports sync methods
response.status_code = status.HTTP_200_OK
response.set_cookie("token", "fastapi-cbx")
return "Welcome to fastapi-cbx"
@cbr.get("/heavies", summary="Get heavies by key") # Also supports sync & @classmethod
async def get_heavies(self, key: str) -> CBRModel:
self.logger.info(f"GET {key}")
return self.CBRModel(key=key, value=self.heavies.get(key, "One scenario, one route"))
MyCBR(version="1.0.0")
app = FastAPI()
app.include_router(MyCBR.router)
Run
uvicorn main:app --host 0.0.0.0 --port 8000
API Document
http://localhost:8000/docs
Hierarchical Routing Patterns
FR(Function Route): Stateless functional route for simple standalone endpoints.
@app.get("/cbx")
async def func():
return {"message": "Hello CBX"}
CBV (Class-Based View):Class-based view for CRUD operations with singleton global dependency injection.
import logging
import asyncio
import time
from typing import Dict
from fastapi import FastAPI, APIRouter, Response, status, Cookie, Depends, HTTPException
from cbx import cbv
from pydantic import BaseModel
@cbv(router=APIRouter(prefix='/cbv'))
class MyCBV:
logger = logging.getLogger(__qualname__)
class CBVModel(BaseModel):
key: str = "cbv"
value: str = "Class-based view for CRUD operations with singleton global dependency injection"
def __init__(self, **kwargs: Dict[str, str]):
self.heavies = {
"name": "fastapi-cbx",
"description": "Minimal class-based routing extension for FastAPI",
"requires-python": ">=3.8",
}
self.heavies.update(kwargs)
@staticmethod
async def head(response: Response) -> None:
await asyncio.sleep(1)
response.status_code = status.HTTP_200_OK
response.set_cookie("token", "fastapi-cbx")
def get(self, key: str) -> CBVModel:
self.logger.info(f"GET {key}")
time.sleep(1)
return self.CBVModel(key=key, value=self.heavies.get(key, "One scenario, one route"))
@staticmethod
def session(token: str = Cookie(default="", alias="token")) -> str:
if token != "fastapi-cbx":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
return token
def post(self, body: CBVModel, token: str = Depends(session)) -> None:
self.logger.info(f"POST {body.key} {body.value} {token}")
time.sleep(1)
self.heavies[body.key] = body.value
@classmethod
def put(cls, body: CBVModel, token: str = Depends(session)) -> None:
cls.logger.info(f"PUT {body.key} {body.value} {token}")
time.sleep(1)
cls.CBVModel.model_fields["key"].default = body.key
cls.CBVModel.model_fields["value"].default = body.value
MyCBV(version="1.0.0")
app = FastAPI()
app.include_router(MyCBV.router)
CBR (Class-Based Route): Class-based route for complex business logic with multiple endpoints and method-level dependencies.
import logging
import asyncio
import time
from typing import Dict
from fastapi import FastAPI, APIRouter, Response, status, Cookie, Depends, HTTPException, WebSocket
from cbx import cbr
from pydantic import BaseModel
@cbr(router=APIRouter(prefix="/cbr"))
class MyCBR:
logger = logging.getLogger(__qualname__)
class CBRModel(BaseModel):
key: str = "CBR"
value: str = "Class-based route for complex business logic with multiple endpoints and method-level dependencies"
def __init__(self, **kwargs: Dict[str, str]):
self.heavies = {
"name": "fastapi-cbx",
"description": "Minimal class-based routing extension for FastAPI"
}
self.heavies.update(kwargs)
@cbr.get("/welcome", summary="Welcome to fastapi-cbx")
@staticmethod
async def welcome(response: Response) -> str:
response.status_code = status.HTTP_200_OK
response.set_cookie("token", "fastapi-cbx")
return "Welcome to fastapi-cbx"
@cbr.get("/heavies", summary="Get heavies by key")
async def get_heavies(self, key: str) -> CBRModel:
self.logger.info(f"GET {key}")
return self.CBRModel(key=key, value=self.heavies.get(key, "One scenario, one route"))
@staticmethod
def session(token: str = Cookie(default="", alias="token")) -> str:
if token != "fastapi-cbx":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
return token
@cbr.post("/heavies", summary="Set heavies")
async def set_heavies(self, body: CBRModel, token: str = Depends(session)) -> None:
self.logger.info(f"POST {body.key} {body.value} {token}")
await asyncio.sleep(1)
self.heavies[body.key] = body.value
@cbr.get("/default", summary="Get default heavies")
@classmethod
async def get_default(cls) -> CBRModel:
cls.logger.info(f"GET default")
return cls.CBRModel()
@cbr.get("/sync", summary="Sync Support")
@classmethod
def sync(cls) -> CBRModel:
time.sleep(1)
return cls.CBRModel(key="sync", value="ok")
@cbr.websocket("/heavies", name="websocket heavies") # WebSocket support
async def websocket_heavies(self, websocket: WebSocket) -> None:
await websocket.accept()
key = await websocket.receive_text()
await websocket.send_text(self.heavies.get(key, "One scenario, one route"))
await websocket.close()
MyCBR(version="1.0.0")
app = FastAPI()
app.include_router(MyCBR.router)
Resource Lifecycle Placement Rules
To build clean, performant, and maintainable Python web services (especially for ML / LLM / inference services), follow this strict but simple rule:
Heavyweight Global Resources
Use case:
- Database connections & ORM engines
- Shared clients (Redis, object storage, third-party SDKs)
- LLM / transformer models
- Inference engines (vLLM, TensorRT-LLM)
- Any expensive-to-initialize component
Where to initialize:
Class __init__ method
Why:
- Initialized exactly once at application startup
- Reused across all requests
- No redundant memory or CPU overhead
- Avoids global variables
- Natural domain encapsulation
Example:
@cbr(router=APIRouter(prefix="/cbr"))
class MyCBR:
def __init__(self, **kwargs: Dict[str, str]):
self.heavies = {
"name": "fastapi-cbx",
"description": "Minimal class-based routing extension for FastAPI"
}
self.heavies.update(kwargs)
Lightweight Request-Scoped Resources
Use case:
- Current logged-in user
- Request session
- Auth / token validation
- Request ID / tracing context
- Per-request temporary state
Where to initialize:
FastAPI Depends
Why:
- Created once per request
- Automatically isolated between requests
- Clean dependency injection
- Low mental overhead
Example:
@cbr(router=APIRouter(prefix="/cbr"))
class MyCBR:
...
@cbr.post("/heavies", summary="Set heavies")
async def set_heavies(self, body: CBRModel, token: str = Depends(session)) -> None:
self.logger.info(f"POST {body.key} {body.value} {token}")
await asyncio.sleep(1)
self.heavies[body.key] = body.value
Notes & Warnings
-
Focus on Routing Only
This project focuses solely on routing extension for FastAPI. It does not handle business logic, data validation (beyond FastAPI's native capabilities), or other non-routing related functionalities. -
Resource Contention & Concurrency Safety
The handling of contention over shared resources (e.g., database connections, SDK clients and other global shared instances) shall be undertaken by developers. fastapi-cbx does not embed built-in safeguards or isolation controls for concurrent access, whether in synchronous or asynchronous execution scenarios. -
Avoid
__annotations__['cbx_router']Conflict
The library uses the__annotations__['cbx_router']attribute internally to bind routers. Do not manually modify or use this attribute in your code to avoid conflicts and unexpected behavior. -
No Inheritance Support
As a lightweight encapsulation for REST APIs, fastapi-cbx does not consider or support class inheritance scenarios for CBV/CBR. Each route class should be independent and self-contained. -
Class Initialization Requirement
Classes decorated with @cbv(router=APIRouter(prefix='/cbv')) or @cbr(router=APIRouter(prefix="/cbr")) must be initialized before including the router. -
Support & Feedback
Feel free to open issues or submit PRs on GitHub. If you find this library useful, please give it a star to support the project.
Metadata
Release files for fastapi-cbx 1.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fastapi_cbx-1.0.2.tar.gz | 6.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fastapi_cbx-1.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 13.7 kB
Release files / fastapi_cbx-1.0.2.tar.gz
| Download URL | fastapi_cbx-1.0.2.tar.gz |
|---|---|
| Size | 6.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
24ae285f0ee4892adccbc494eb34f265cf117864d5dbb382912ed1b4ce67f3ee
|
|
BLAKE2b-256 checksum How to use checksums |
e6b9dff2cb39ee235d51701057e8eb70c0d2557bbfcf1f8843afa3e29a7c970d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.
Transparency logRelease files / fastapi_cbx-1.0.2-py3-none-any.whl
| Download URL | fastapi_cbx-1.0.2-py3-none-any.whl |
|---|---|
| Size | 6.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
22eeaa5ae28cbeb0a412be98cccf5ecc6373b65b963dc57224523b6e74254eaa
|
|
BLAKE2b-256 checksum How to use checksums |
177b0b59cbde4c5fb91ee8ba759fba15f280de73247fd1b09b0f6de376505c25
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.
Transparency log