How to document default None/null in OpenAPI/Swagger using FastAPI?

When you declare Optional parameters, users shouldn’t have to include those parameters in their request specified with null or None (in Python), in order to be None. The default value of the parameters will be None, 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 ID: Optional[UUID] = None and ID: UUID = None. In Python 3.10+, one could also use ID: UUID| None = None (see here).

As per FastAPI documentation (see Info section in the link provided):

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.

Leave a Comment