Created
August 24, 2022 20:31
-
-
Save nkhitrov/e430850eb440665474eef17fc3062ead to your computer and use it in GitHub Desktop.
FastAPI generic request, response schemas
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import Any, Generic, Type, TypeAlias, TypeVar | |
from fastapi import status as http_status_code | |
from pydantic import Field | |
from pydantic.generics import GenericModel | |
_Model = TypeVar("_Model") | |
GenericResponse: TypeAlias = GenericModel | |
class BaseError(BaseModel): | |
"""Error response as defined in | |
https://datatracker.ietf.org/doc/html/rfc7807. | |
One difference is that the member "type" is not a URI | |
""" | |
type: Optional[str] = Field(title="The name of the class of the error") | |
title: Optional[str] = Field( | |
title="A short, human-readable summary of the problem that does not change from occurence to occurence", | |
) | |
detail: Optional[str] = Field(title="А human-readable explanation specific to this occurrence of the problem") | |
instance: Optional[Any] = Field(title="Identifier for this specific occurrence of the problem") | |
class BaseResponse(BaseModel): | |
status: int = Field(..., title="Status code of request.", example=status_code.HTTP_200_OK) | |
error: BaseError | None = Field(None, title="Errors data") | |
payload: Any | None = Field(None, title="Payload data.") | |
class NoContentResponse(BaseResponse): | |
status: int = status_code.HTTP_204_NO_CONTENT | |
class DataResponse(GenericResponse, Generic[_Model]): | |
data: _Model | list[_Model] | |
class OkResponse(GenericResponse, Generic[_Model]): | |
""" | |
# serializers.py | |
>>> class UserID(BaseModel): | |
>>> user_id: int = Field(..., example=12345) | |
# controllers.py | |
>>> @router.get("/foo", response_model=Response[UserID], status_code=200) | |
>>> async def foo_func(): | |
>>> user_id = 12345 | |
>>> return OkResponse.new( | |
>>> status_code=200, model=UserID, data=UserID(user_id=user_id), | |
>>> ) | |
""" | |
status: int = Field(..., title="Status code of request.", example=http_status_code.HTTP_200_OK) | |
error: BaseError | None = Field(None title="Errors") | |
payload: DataResponse[_Model] = Field(title="Payload data.") | |
@classmethod | |
def new( | |
cls, | |
*, | |
status_code: int, | |
model: Type[_Model] | list[Type[_Model]] | Any, | |
data: _Model | Any, | |
) -> "OkResponse[_Model]": | |
return cls[model](status=status_code, payload=DataResponse[model](data=data)) # type: ignore |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment