FastAPI annotated api routed
Project description
Annotated FastAPI router
Этот пакет содержит улучшенный fastapi.APIRouter
, который содержит шорт-каты для удобной аннотации
эндпоинтов через typing.Annotated
, что бы задавать значения status_code
или модели ответов в responses
.
Warning the English part of README.md is translated via ChatGPT and may not be accurate
This package contains an enhanced fastapi.APIRouter
that includes shortcuts for annotating endpoints conveniently using typing.Annotated
, allowing you to set values like status_code
or response models in responses
.
Примеры
Статус-код
Указывать status_code
у эндпоинта можно следующим образом:
from http import HTTPStatus
from typing import Annotated
from fastapi import FastAPI
from pydantic import BaseModel
from annotated_fastapi_router import AnnotatedAPIRouter, Status
class ResponseModel(BaseModel):
message: str
router = AnnotatedAPIRouter()
@router.get("/my_endpoint")
async def my_endpoint() -> Annotated[ResponseModel, Status[HTTPStatus.ACCEPTED]]:
return ResponseModel(message="hello")
router.add_api_route("/my_endpoint", my_endpoint, methods=["POST"])
В результате swagger будет содержать следующую OpenAPI-схему:
При запросе статус код так же будет проставлен в ответ:
Однако если статус код будет указан явно в декораторе или при добавлении в роутер, Status
в аннотации будет проигнорирован.
@router.get("/my_endpoint")
@router.get("/my_endpoint_too", status_code=HTTPStatus.CREATED)
async def my_endpoint() -> Annotated[ResponseModel, Status[HTTPStatus.ACCEPTED]]:
return ResponseModel(message="hello")
router.add_api_route("/my_endpoint", my_endpoint, methods=["POST"])
router.add_api_route("/my_endpoint_too", my_endpoint, status_code=HTTPStatus.CREATED, methods=["POST"])
Важно: Status
принимает в себя только перечисления из HTTPStatus
,
на любые другие объекты будет подыматься ошибка TypeError
.
Модель ответов для ошибок
Для автоматического построения моделей для responses
используется тип ошибок ResponseError
.
В его наследниках обязательно нужно указывать переменную типа status
и model
.
status
указывает для каких кодов ошибок нужно будет построить модель, если будет передано несколько
типов ошибок для одного и того же HTTPStatus
, то полученная модель будет объединять в себе все модели model
.
from http import HTTPStatus
from typing import Annotated, Self
from fastapi import FastAPI
from pydantic import BaseModel
from annotated_fastapi_router import AnnotatedAPIRouter, Errors, ResponseError
class ResponseModel(BaseModel):
message: str
class ErrorMessageModel(BaseModel):
message: str
class OtherErrorModel(BaseModel):
code: int
class MyError(ResponseError[ErrorMessageModel]):
status = HTTPStatus.BAD_REQUEST
model = ErrorMessageModel
def __init__(self: "MyError", msg: str) -> None:
self.message = msg
class OtherError(ResponseError[OtherErrorModel]):
status = HTTPStatus.BAD_REQUEST
model = OtherErrorModel
async def entity(self: Self) -> OtherErrorModel:
return self.model(code=self.status)
router = AnnotatedAPIRouter()
@router.get("/my_endpoint")
@router.post("/my_endpoint")
async def endpoint(how_iam: str) -> Annotated[ResponseModel, Errors[MyError, OtherError]]:
if how_iam == "me":
return ResponseModel(message="hello")
if how_iam.isdigit():
raise OtherError
raise MyError("I don't know you")
Таким образом будет построены две модели ошибок – MyEndpointPOSTBadRequest
и MyEndpointGETBadRequest
.
Имя модели генерируется из пути, методов (если указаны) роута и phrase статус-кода ошибки.
Делается это потому что для fastapi<=0.95.0
требуется что бы все названия моделей (если они отличаются) имели уникальные имена.
Если модель ошибки состоит только из одной модели – тогда будет использовано имя оригинальной модели (что бы избегать баг в OpenAPI-схеме с некорректным определением компонента).
Логику построения имени модели можно изменить наследованием от AnnotatedAPIRouter
и переопределением метода response_model_name
.
Так же для построение экземпляра модели ошибки по умолчанию использует атрибуты экземпляра ошибки (через __dict__
),
но если это поведение необходимо изменить можно реализовать метод entity
(как в примере в класса OtherError
).
Если responses
уже определяется в декораторе роута или при явном добавлении в него и содержит описание для ошибки,
которая указана в Annotated
, то она не будет перезаписывать данные переданные в responses
.
@router.get("/my_endpoint_too", responses={HTTPStatus.BAD_REQUEST: {"model": dict[str, str]}})
async def endpoint(how_iam: str) -> Annotated[ResponseModel, Errors[MyError, OtherError]]:
if how_iam == "me":
return ResponseModel(message="hello")
if how_iam.isdigit():
raise OtherError
raise MyError("I don't know you")
Для того что бы автоматически отлавливать ошибки из эндпоинтов и указывать в ответе тот статус-код, который в указан в них,
необходимо добавить в FastAPI
приложение обработчик ошибок ResponseError.handler
.
app.add_exception_handler(ResponseError, ResponseError.handler)
Examples
Status-code
To specify the status_code of the endpoint, you can do it as follows:
from http import HTTPStatus
from typing import Annotated
from fastapi import FastAPI
from pydantic import BaseModel
from annotated_fastapi_router import AnnotatedAPIRouter, Status
class ResponseModel(BaseModel):
message: str
router = AnnotatedAPIRouter()
@router.get("/my_endpoint")
async def my_endpoint() -> Annotated[ResponseModel, Status[HTTPStatus.ACCEPTED]]:
return ResponseModel(message="hello")
router.add_api_route("/my_endpoint", my_endpoint, methods=["POST"])
As a result, the swagger will contain the following OpenAPI schema:
When the endpoint is requested, the status code will also be included in the response:
However, if the status code is explicitly provided in the decorator or when adding it to the router, the Status
in the annotation will be ignored.
@router.get("/my_endpoint")
@router.get("/my_endpoint_too", status_code=HTTPStatus.CREATED)
async def my_endpoint() -> Annotated[ResponseModel, Status[HTTPStatus.ACCEPTED]]:
return ResponseModel(message="hello")
router.add_api_route("/my_endpoint", my_endpoint, methods=["POST"])
router.add_api_route("/my_endpoint_too", my_endpoint, status_code=HTTPStatus.CREATED, methods=["POST"])
Important: Status
only accepts enumerations from HTTPStatus
; any other objects will raise a TypeError
Responses
To automatically build models for responses
, the error type ResponseError
is used.
In its subclasses, it is necessary to specify variables of type status
and model
.
status
indicates for which error codes the model will need to be constructed.
If multiple error types are provided for the same HTTPStatus, the resulting model will combine all model models.
from http import HTTPStatus
from typing import Annotated, Self
from fastapi import FastAPI
from pydantic import BaseModel
from annotated_fastapi_router import AnnotatedAPIRouter, Errors, ResponseError
class ResponseModel(BaseModel):
message: str
class ErrorMessageModel(BaseModel):
message: str
class OtherErrorModel(BaseModel):
code: int
class MyError(ResponseError[ErrorMessageModel]):
status = HTTPStatus.BAD_REQUEST
model = ErrorMessageModel
def __init__(self: "MyError", msg: str) -> None:
self.message = msg
class OtherError(ResponseError[OtherErrorModel]):
status = HTTPStatus.BAD_REQUEST
model = OtherErrorModel
async def entity(self: Self) -> OtherErrorModel:
return self.model(code=self.status)
router = AnnotatedAPIRouter()
@router.get("/my_endpoint")
@router.post("/my_endpoint")
async def endpoint(how_iam: str) -> Annotated[ResponseModel, Errors[MyError, OtherError]]:
if how_iam == "me":
return ResponseModel(message="hello")
if how_iam.isdigit():
raise OtherError
raise MyError("I don't know you")
In this way, two error models will be built - MyEndpointPOSTBadRequest
and MyEndpointGETBadRequest
.
The model name is generated from the path, methods (if specified) of the route, and the status code error phrase.
This is done because for fastapi<=0.95.0
, all model names (if they differ) must have unique names.
If the error model consists of only one model, the name of the original model will be used (to avoid a bug in the OpenAPI schema with an incorrect component definition).
The logic for naming the model can be changed by inheriting from AnnotatedAPIRouter
and overriding the response_model_name
method.
Also, to build an instance of the error model by default, it uses the error instance attributes (via __dict__
),
but if this behavior needs to be changed, you can implement the entity
method
(as shown in the example in the OtherError
class).
If responses
are already defined in the route decorator or explicitly added to it and contain
a description for an error specified in Annotated
, it will not overwrite the data passed to responses
.
@router.get("/my_endpoint_too", responses={HTTPStatus.BAD_REQUEST: {"model": dict[str, str]}})
async def endpoint(how_iam: str) -> Annotated[ResponseModel, Errors[MyError, OtherError]]:
if how_iam == "me":
return ResponseModel(message="hello")
if how_iam.isdigit():
raise OtherError
raise MyError("I don't know you")
To automatically catch errors from endpoints and include the status code specified in them in the response, you need to add the error handler ResponseError.handler
to the FastAPI
application.
app.add_exception_handler(ResponseError, ResponseError.handler)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file annotated_fastapi_router-0.1.0.tar.gz
.
File metadata
- Download URL: annotated_fastapi_router-0.1.0.tar.gz
- Upload date:
- Size: 10.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.3 CPython/3.12.1 Linux/6.5.0-1022-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | cb2c37cbe7e9467ff1c2fb2984f387573e8b5a99efa356584187943db4e2b130 |
|
MD5 | 4aeff5a360910add66fab75bef2b717f |
|
BLAKE2b-256 | 3db1eb50222fb44cf202dbf67dea2ecf8376ee513c9230b11d505c56153b032a |
File details
Details for the file annotated_fastapi_router-0.1.0-py3-none-any.whl
.
File metadata
- Download URL: annotated_fastapi_router-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.3 CPython/3.12.1 Linux/6.5.0-1022-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8cca229a4ae1c5a64f3f06c2e1e24618916f74c045d0ab6f7c095be7cff6e2a1 |
|
MD5 | 022b5dd62dd0635bbaa72d86de47d663 |
|
BLAKE2b-256 | 18fefa366676b1e9b530aeb796797542258ec2579361a32806aaeb35f61dee1e |