You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
4.4 KiB

import asyncio
import logging
from fastapi import APIRouter, Cookie, Depends, FastAPI, HTTPException, Response, status
from fastapi.cbx import cbr, cbv
from fastapi.testclient import TestClient
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")
async def get(self, key: str) -> CBVModel:
self.logger.info(f"GET {key}")
await asyncio.sleep(1)
return self.CBVModel(
key=key, value=self.heavies.get(key, "One scenario, one route")
)
@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")
@cbr.put("/heavies", summary="Set heavies")
@cbr.patch("/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.delete("/heavies")
async def delete(self, name: str) -> None:
del self.heavies[name]
@cbr.head("/multiple_coverage")
@cbr.options("/multiple_coverage")
@cbr.trace("/multiple_coverage")
@cbr.connect("/multiple_coverage")
@staticmethod
async def multiple_coverage(response: Response) -> None:
response.status_code = status.HTTP_200_OK
response.set_cookie("token", "fastapi-cbx")
MyCBV(version="1.0.0")
MyCBR(version="1.0.0")
app = FastAPI()
app.include_router(MyCBV.router)
app.include_router(MyCBR.router)
client = TestClient(app)
# ==================== 100% Test Suite ====================
def test_cbv():
asyncio.run(MyCBV.head(Response()))
print(dir(MyCBV))
response = client.get("/cbv?key=name")
assert response.status_code == 200
def test_cbr():
asyncio.run(MyCBR.welcome(Response()))
print(dir(MyCBR))
response = client.get("/cbr/heavies?key=name")
assert response.status_code == 200
response = client.post("/cbr/heavies", json={"key": "test", "value": "test_value"})
assert response.status_code == 401
assert response.json()["detail"] == "Invalid token"
with TestClient(app, cookies={"token": "fastapi-cbx"}) as auth_client:
response = auth_client.post(
"/cbr/heavies", json={"key": "test", "value": "test"}
)
assert response.status_code == 200
response = client.delete("/cbr/heavies?name=test")
assert response.status_code == 200
response = client.head("/cbr/multiple_coverage")
assert response.status_code == 200