pythonasyncioapiasyncfastapiframeworkjsonjson-schemaopenapiopenapi3pydanticpython-typespython3redocreststarletteswaggerswagger-uiuvicornweb
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
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
|
|
|