如何使用 FastAPI 在 OpenAPI/Swagger 中记录默认值 None/null?
How to document default None/null in OpenAPI/Swagger using FastAPI?
使用 ORM,我想做一个 POST 请求让一些字段具有 null
值,这些字段将在数据库中转换为那里指定的默认值。
问题是 OpenAPI (Swagger) docs,忽略了默认的 None
并且仍然默认提示一个 UUID
。
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
from uuid import UUID
import uvicorn
class Table(BaseModel):
# ID: Optional[UUID] # the docs show a example UUID, ok
ID: Optional[UUID] = None # the docs still shows a uuid, when it should show a null or valid None value.
app = FastAPI()
@app.post("/table/", response_model=Table)
def create_table(table: Table):
# here we call to sqlalchey orm etc.
return 'nothing important, the important thing is in the docs'
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
在 docs 的 OpenAPI 模式示例(请求正文)中,我们发现:
{
"ID": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
这不行,因为我指定默认值为None
,所以我希望这样:
{
"ID": null, # null is the equivalent of None here
}
这会将 null
传递给 ID
,最后将在数据库中解析为默认值(即新生成的 UUID
)。
当您声明 Optional
参数时,用户不必为了成为 null
而在他们的请求中包含这些参数(用 null
值指定)。参数的默认值将为 null
,除非用户在发送请求时指定其他值。
因此,您所要做的就是使用 Config
和 schema_extra
为 Pydantic 模型声明自定义 example
,如 documentation 和如下所示。下面的示例将在 OpenAPI (Swagger UI) 中创建一个空的(即 {}
)请求主体,可以成功提交(因为 ID
是模型的唯一属性并且是可选)。
class Table(BaseModel):
ID: Optional[UUID] = None
class Config:
schema_extra = {
"example": {
}
}
@app.post("/table/", response_model=Table)
def create_table(table: Table):
return table
如果 Table
模型包含一些其他 必需的 属性,您可以为这些属性添加 example
值,如下所示:
class Table(BaseModel):
ID: Optional[UUID] = None
some_attr: str
class Config:
schema_extra = {
"example": {
"some_attr": "Foo"
}
}
如果您想保留auto-generated 示例 其余属性除了ID
属性的示例,您可以使用以下命令从生成的模式中的模型属性中删除 ID
(受 Schema customization 启发):
class Table(BaseModel):
ID: Optional[UUID] = None
some_attr: str
some_attr2: float
some_attr3: bool
class Config:
@staticmethod
def schema_extra(schema: Dict[str, Any], model: Type['Table']) -> None:
del schema.get('properties')['ID']
此外,如果您想为某些属性添加自定义 example
,您可以使用 Field()
(如 here 所述);例如,some_attr: str = Field(example="Foo")
.
另一种可能的解决方案是修改生成的 OpenAPI 架构,如 的解决方案 3 中所述。不过,上述解决方案可能更适合这种情况。
备注
ID: Optional[UUID] = None
等同于 ID: UUID = None
。正如之前在 FastAPI 网站中记录的那样(参见 ):
The Optional in Optional[str]
is not used by FastAPI, but will allow
your editor to give you better support and detect errors.
从那时起,FastAPI 修改了他们的 documentation 如下:
The Union in Union[str, None]
will allow your editor to give you
better support and detect errors.
因此,ID: Union[UUID, None] = None
与上述两个选项相同。在Python 3.10及以上版本中,还可以使用:ID: UUID| None = None
.
根据 FastAPI documentation(参见上述 link 中的 Info
部分):
Have in mind that the most important part to make a parameter optional
is the part:
= None
or the:
= Query(default=None)
as it will use that None
as the default value, and that way make the
parameter not required.
The Union[str, None]
part allows your editor to provide better
support, but it is not what tells FastAPI that this parameter is not
required.
使用 ORM,我想做一个 POST 请求让一些字段具有 null
值,这些字段将在数据库中转换为那里指定的默认值。
问题是 OpenAPI (Swagger) docs,忽略了默认的 None
并且仍然默认提示一个 UUID
。
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
from uuid import UUID
import uvicorn
class Table(BaseModel):
# ID: Optional[UUID] # the docs show a example UUID, ok
ID: Optional[UUID] = None # the docs still shows a uuid, when it should show a null or valid None value.
app = FastAPI()
@app.post("/table/", response_model=Table)
def create_table(table: Table):
# here we call to sqlalchey orm etc.
return 'nothing important, the important thing is in the docs'
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
在 docs 的 OpenAPI 模式示例(请求正文)中,我们发现:
{
"ID": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
这不行,因为我指定默认值为None
,所以我希望这样:
{
"ID": null, # null is the equivalent of None here
}
这会将 null
传递给 ID
,最后将在数据库中解析为默认值(即新生成的 UUID
)。
当您声明 Optional
参数时,用户不必为了成为 null
而在他们的请求中包含这些参数(用 null
值指定)。参数的默认值将为 null
,除非用户在发送请求时指定其他值。
因此,您所要做的就是使用 Config
和 schema_extra
为 Pydantic 模型声明自定义 example
,如 documentation 和如下所示。下面的示例将在 OpenAPI (Swagger UI) 中创建一个空的(即 {}
)请求主体,可以成功提交(因为 ID
是模型的唯一属性并且是可选)。
class Table(BaseModel):
ID: Optional[UUID] = None
class Config:
schema_extra = {
"example": {
}
}
@app.post("/table/", response_model=Table)
def create_table(table: Table):
return table
如果 Table
模型包含一些其他 必需的 属性,您可以为这些属性添加 example
值,如下所示:
class Table(BaseModel):
ID: Optional[UUID] = None
some_attr: str
class Config:
schema_extra = {
"example": {
"some_attr": "Foo"
}
}
如果您想保留auto-generated 示例 其余属性除了ID
属性的示例,您可以使用以下命令从生成的模式中的模型属性中删除 ID
(受 Schema customization 启发):
class Table(BaseModel):
ID: Optional[UUID] = None
some_attr: str
some_attr2: float
some_attr3: bool
class Config:
@staticmethod
def schema_extra(schema: Dict[str, Any], model: Type['Table']) -> None:
del schema.get('properties')['ID']
此外,如果您想为某些属性添加自定义 example
,您可以使用 Field()
(如 here 所述);例如,some_attr: str = Field(example="Foo")
.
另一种可能的解决方案是修改生成的 OpenAPI 架构,如
备注
ID: Optional[UUID] = None
等同于 ID: UUID = None
。正如之前在 FastAPI 网站中记录的那样(参见
The Optional in
Optional[str]
is not used by FastAPI, but will allow your editor to give you better support and detect errors.
从那时起,FastAPI 修改了他们的 documentation 如下:
The Union in
Union[str, None]
will allow your editor to give you better support and detect errors.
因此,ID: Union[UUID, None] = None
与上述两个选项相同。在Python 3.10及以上版本中,还可以使用:ID: UUID| None = None
.
根据 FastAPI documentation(参见上述 link 中的 Info
部分):
Have in mind that the most important part to make a parameter optional is the part:
= None
or the:
= Query(default=None)
as it will use that
None
as the default value, and that way make the parameter not required.The
Union[str, None]
part allows your editor to provide better support, but it is not what tells FastAPI that this parameter is not required.