Skip to content

3.1.0

Compare
Choose a tag to compare
@yezz123 yezz123 released this 25 Mar 11:48
· 150 commits to main since this release
8e3ed62

⚠️ Drop Support of Python 3.8 | 3.9 & New Break Changes

As you create more complex FastAPI applications, you may find yourself frequently repeating the same dependencies in multiple related endpoints.

We Introduce this new version showcases the usage of CVB in FastAPI by @yezz123 in #82

A common question people have as they become more comfortable with FastAPI is how they can reduce the number of times they have to copy/paste the same dependency into related routes.

fastapi_class provides a class-based view decorator @View to help reduce the amount of boilerplate necessary when developing related routes.

Highly inspired by Fastapi-utils, Thanks to @dmontagu for the great work.

  • Example:
from fastapi import FastAPI, APIRouter, Query
from pydantic import BaseModel
from fastapi_class import View

app = FastAPI()
router = APIRouter()

class ItemModel(BaseModel):
    id: int
    name: str
    description: str = None

@View(router)
class ItemView:
    def post(self, item: ItemModel):
        return item

    def get(self, item_id: int = Query(..., gt=0)):
        return {"item_id": item_id}

app.include_router(router)

Response model 📦

Exception in list need to be either function that return fastapi.HTTPException itself. In case of a function it is required to have all of it's arguments to be optional.

from fastapi import FastAPI, APIRouter, HTTPException, status
from fastapi.responses import PlainTextResponse
from pydantic import BaseModel

from fastapi_class import View

app = FastAPI()
router = APIRouter()

NOT_AUTHORIZED = HTTPException(401, "Not authorized.")
NOT_ALLOWED = HTTPException(405, "Method not allowed.")
NOT_FOUND  = lambda item_id="item_id": HTTPException(404, f"Item with {item_id} not found.")

class ItemResponse(BaseModel):
    field: str | None = None

@view(router)
class MyView:
    exceptions = {
        "__all__": [NOT_AUTHORIZED],
        "put": [NOT_ALLOWED, NOT_FOUND]
    }

    RESPONSE_MODEL = {
        "put": ItemResponse
    }

    RESPONSE_CLASS = {
        "delete": PlainTextResponse
    }

    def get(self):
        ...
    def put(self):
        ...
    def delete(self):
        ...

app.include_router(router)

Customized Endpoints

from fastapi import FastAPI, APIRouter, HTTPException
from fastapi.responses import PlainTextResponse
from pydantic import BaseModel

from fastapi_class import View, endpoint

app = FastAPI()
router = APIRouter()

NOT_AUTHORIZED = HTTPException(401, "Not authorized.")
NOT_ALLOWED = HTTPException(405, "Method not allowed.")
NOT_FOUND  = lambda item_id="item_id": HTTPException(404, f"Item with {item_id} not found.")
EXCEPTION = HTTPException(400, "Example.")

class UserResponse(BaseModel):
    field: str | None = None

@View(router)
class MyView:
    exceptions = {
        "__all__": [NOT_AUTHORIZED],
        "put": [NOT_ALLOWED, NOT_FOUND],
        "edit": [EXCEPTION]
    }

    RESPONSE_MODEL = {
        "put": UserResponse,
        "edit": UserResponse
    }

    RESPONSE_CLASS = {
        "delete": PlainTextResponse
    }

    def get(self):
        ...
    def put(self):
        ...
    def delete(self):
        ...
    @endpoint(("PUT",), path="edit")
    def edit(self):
        ...

Dependencies 🔨

Full Changelog: 2.0.0...3.1.0