'How to document default None/null in OpenAPI/Swagger using FastAPI?
Using a ORM, I want to do a POST request letting some fields with a null
value, which will be translated in the database for the default value specified there.
The problem is that OpenAPI (Swagger) docs, ignores the default None
and still prompts a UUID
by default.
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)
In the OpenAPI schema example (request body) which is at the docs we find:
{
"ID": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
This is not ok, because I specified that the default value is None
,so I expected this instead:
{
"ID": null, # null is the equivalent of None here
}
Which will pass a null
to the ID
and finally will be parsed in the db to the default value (that is a new generated UUID
).
Solution 1:[1]
When you declare Optional
parameters, users shouldn't have to include those parameters in their request (specified with null
value) in order to be null
. The default value of the parameters will be null
, unless the user specifies some other value when sending the request.
Hence, all you have to do is to declare a custom example
for the Pydantic model using Config
and schema_extra
, as described in the documentation and as shown below. The below example will create an empty (i.e., {}
) request body in OpenAPI (Swagger UI), which can be successfully submitted (as ID
is the only attribute of the model and is optional).
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
If the Table
model included some other required attributes, you could add example
values for those, as demonstrated below:
class Table(BaseModel):
ID: Optional[UUID] = None
some_attr: str
class Config:
schema_extra = {
"example": {
"some_attr": "Foo"
}
}
If you would like to keep the auto-generated examples for the rest of the attributes except the one for the ID
attribute, you could use the below to remove ID
from the model's properties in the generated schema (inspired by 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']
Also, if you would like to add custom example
to some of the attributes, you could use Field()
(as described here); for example, some_attr: str = Field(example="Foo")
.
Another possible solution would be to modify the generated OpenAPI schema, as described in Solution 3 of this answer. Though, the above solution is likely more suited to this case.
Note
ID: Optional[UUID] = None
is the same as ID: UUID = None
. As previously documented in FastAPI website (see this answer):
The Optional in
Optional[str]
is not used by FastAPI, but will allow your editor to give you better support and detect errors.
Since then, FastAPI has revised their documentation with the following:
The Union in
Union[str, None]
will allow your editor to give you better support and detect errors.
Hence, ID: Union[UUID, None] = None
is the same as the above two options. And in Python 3.10 and above, one can also use: ID: UUID| None = None
.
As per FastAPI documentation (see Info
section in the link referred above):
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |