Decorate response model of a FastAPI route with another model
Question:
I have a common response pattern for most of the routes, like having specific fields in it (e.g. ‘date’ with default value, ‘info’, where decorated data should live in and so on).
For example, having this endpoint:
@route.get(...,response_model=Entry)
endpoint returns serialized Entry
object.
Would it be possible to declare a pydantic model, like CommonResponse
, that automatically contains predefined fields and put Entry
model in its field(‘info’), and use like this:
@route.get(...,response_model=CommonResponse[Entry])
or @route.get(...,response_model=CommonResponse[List[Entry]])
Answers:
According to pydantic doc- Generic Models
Pydantic supports the creation of generic models to make it easier to reuse a common model structure.
- define generic model
DataT = TypeVar('DataT')
class GenericResponseModel(GenericModel, Generic[DataT]):
success: bool = Field(True)
error_msg: Optional[str] = Field(None, alias='errorMsg')
data: Optional[DataT] = Field(None)
total: Optional[int] = Field(None)
class Config:
allow_population_by_field_name = True
- Use in your
response_model
@router.get('/',
response_model=schemas.GenericResponseModel[List[schemas.ShopModel]])
# ...
@router.get('/{shop_id}',
response_model=schemas.GenericResponseModel[schemas.ShopModel])
async def get():
# ...
shop = get_shop()
return schemas.GenericResponseModel(data=shop)
- The openapi doc will cantains
List[schemas.ShopModel]
or schemas.ShopModel
and have example value for these
I have a common response pattern for most of the routes, like having specific fields in it (e.g. ‘date’ with default value, ‘info’, where decorated data should live in and so on).
For example, having this endpoint:
@route.get(...,response_model=Entry)
endpoint returns serialized Entry
object.
Would it be possible to declare a pydantic model, like CommonResponse
, that automatically contains predefined fields and put Entry
model in its field(‘info’), and use like this:
@route.get(...,response_model=CommonResponse[Entry])
or @route.get(...,response_model=CommonResponse[List[Entry]])
According to pydantic doc- Generic Models
Pydantic supports the creation of generic models to make it easier to reuse a common model structure.
- define generic model
DataT = TypeVar('DataT')
class GenericResponseModel(GenericModel, Generic[DataT]):
success: bool = Field(True)
error_msg: Optional[str] = Field(None, alias='errorMsg')
data: Optional[DataT] = Field(None)
total: Optional[int] = Field(None)
class Config:
allow_population_by_field_name = True
- Use in your
response_model
@router.get('/',
response_model=schemas.GenericResponseModel[List[schemas.ShopModel]])
# ...
@router.get('/{shop_id}',
response_model=schemas.GenericResponseModel[schemas.ShopModel])
async def get():
# ...
shop = get_shop()
return schemas.GenericResponseModel(data=shop)
- The openapi doc will cantains
List[schemas.ShopModel]
orschemas.ShopModel
and have example value for these