Skip to main content

FastAPI plugin to derive route responses based on source code.

Project description

FastAPI Derive Responses Plugin

fastapi-derive-responses is a Python library that extends FastAPI by automatically generating OpenAPI responses based on your endpoint's source code. This plugin helps you reduce boilerplate code by deriving response statuses and descriptions directly from your code.

With fastapi-derive-responses you can omit ~5 lines on endpoint definition:

@app.get(
    "/add_user",
    responses={
-        200: {"description": "User added successfully"},
-        400: {"description": "User already exists"},
-        401: {"description": "Invalid token"},
-        403: {"description": "Only admins and moderators can add users or You are banned"},
-        404: {"description": "Invalid role or User not found"},
    },
)
def add_user(
    current_user_id: Annotated[int, Depends(auth_user)],
    new_user_id: int,
    user_role: str
):
    if statuses[current_user_id] not in ("admin", "moderator"):
        raise HTTPException(403, "Only admins and moderators can add users")
    if new_user_id in statuses:
        raise HTTPException(400, "User already exists")
    if user_role not in ROLES:
        raise HTTPException(400, "Invalid role")
    statuses[new_user_id] = user_role
    return {"message": "User added successfully"}

TODO

  • raise HTTPException(401, detail="Invalid token") in endpoint source -> {401: {description: "Invalid token"}}
  • raise HTTPException(404, detail=f"User with id={id} not found") in endpoint source -> {404: {description: "User with id={id} not found"}}
  • raise HTTPException(404, headers={"X-Error": "User not found"}) in endpoint source -> {404: {headers: {" X-Error": "User not found"}}}
  • Multiple derived responses for the same endpoint merged into one -> {401: {description: "Invalid token OR Token is expired"}}
  • Don't override manually defined responses in decorators
  • ^ Same behavior for dependency functions ^
  • :raises HTTPException: 401 Invalid token in dependency function docstring parses -> {401: {description: "Invalid token"}}
  • Avoid false positives (e.g., raise HTTPException(401) where HTTPException is not from starlette or fastapi)
  • Parse custom classes that inherit from HTTPException
  • Check for custom response models
  • Allow to omit some responses from parsing
  • Code analysis for complex structures in detail and headers

Known Issues

Plugin works through AST parsing, so it may not work correctly with complex code structures or runtime generated code. Also, it may produce false positives: for example, if you raise an exception with name HTTPException from another module (not from starlette or fastapi) it will be parsed.

Installation

pip install fastapi-derive-responses

Quick Start

Basic Usage

You can just raise subclasses of starlette.HTTPException in endpoint.

It will propagate {404: {"description": "Item not found"}, 400: {"description": "Invalid item id"}} to OpenAPI schema.

from fastapi import FastAPI, HTTPException
from fastapi_derive_responses import AutoDeriveResponsesAPIRoute

app = FastAPI()
app.router.route_class = AutoDeriveResponsesAPIRoute

class CustomExeption(HTTPException):
    ...

@app.get("/items/{item_id}")
def read_item(item_id: int):
    if item_id == 0:
        raise HTTPException(status_code=404, detail="Item not found")
    if item_id == -1:
        raise CustomExeption(status_code=400, detail="Invalid item id")
    return {"id": item_id, "name": "Item Name"}

Example with Dependencies

It will propagate {401: {"description": "Invalid token"}}, {403: {"description": "You are banned"}} and {404: { "description": "User not found"}} to OpenAPI schema.

from typing import Annotated

from fastapi import Depends, FastAPI
from fastapi_derive_responses import AutoDeriveResponsesAPIRoute

app = FastAPI()
app.router.route_class = AutoDeriveResponsesAPIRoute


def auth_user(token: int) -> int:
    """
    Authenticate user

    :raises HTTPException: 401 Invalid token
    :raises HTTPException: 403 You are banned
    :raises HTTPException: 404 User not found
    """
    call_some_func_that_may_raise()
    return token


@app.get("/users/me")
def get_current_user(user_id: Annotated[int, Depends(auth_user)]):
    return {"id": user_id, "role": "admin"}

Also, you can just raise subclasses of starlette.HTTPException in your dependency function:

class CustomException(HTTPException):
    ...

def auth_user(token: int) -> int:
    if token < 100:
        raise HTTPException(401, "Invalid token")
    user_id = token - 100
    if user_id not in statuses:
        raise CustomException(404, "User not found")
    if user_id in banlist:
        raise HTTPException(403, "You are banned")
    return user_id

Also, it works then you import your custom exception from other modules:

# exceptions.py
from starlette.exceptions import HTTPException

class ImportedCustomException(HTTPException):
    ...
# main.py
from exceptions import ImportedCustomException
...

app = FastAPI(title="Custom Exception App")
app.router.route_class = AutoDeriveResponsesAPIRoute

@app.get("/")
def raise_custom_exception():
    raise ImportedCustomException(status_code=601, detail="CustomException!")

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_derive_responses-0.1.3.tar.gz (6.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_derive_responses-0.1.3-py3-none-any.whl (6.8 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_derive_responses-0.1.3.tar.gz.

File metadata

  • Download URL: fastapi_derive_responses-0.1.3.tar.gz
  • Upload date:
  • Size: 6.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.12.5 Linux/6.10.7-200.fsync.fc40.x86_64

File hashes

Hashes for fastapi_derive_responses-0.1.3.tar.gz
Algorithm Hash digest
SHA256 206af3283f43cfbb9be0954e9437386499a72ac4931a3ba0e7f88a780467002a
MD5 e929695349060943fc34cc4e5daf335d
BLAKE2b-256 ff863ad8b95dbaa95697a1b47a249afd11bfb14c213a4338304783b0af3deb62

See more details on using hashes here.

File details

Details for the file fastapi_derive_responses-0.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_derive_responses-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 b2e12825d2428b677c5373efe4bcfa3a9c9fc30dacd79f5383fbc7b1a7dea139
MD5 de0faf46c69a33402d64340f8186d171
BLAKE2b-256 9ad67723b9027d52bd4ff98c9b2d5b75b46e3e1554405b88ae10e89896328833

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page