Body - Multiple Parameters¶
Now that we have seen how to usePath andQuery, let's see more advanced uses of request body declarations.
MixPath,Query and body parameters¶
First, of course, you can mixPath,Query and request body parameter declarations freely andFastAPI will know what to do.
And you can also declare body parameters as optional, by setting the default toNone:
fromtypingimportAnnotatedfromfastapiimportFastAPI,PathfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:Annotated[int,Path(title="The ID of the item to get",ge=0,le=1000)],q:str|None=None,item:Item|None=None,):results={"item_id":item_id}ifq:results.update({"q":q})ifitem:results.update({"item":item})returnresults🤓 Other versions and variants
Tip
Prefer to use theAnnotated version if possible.
fromfastapiimportFastAPI,PathfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=None@app.put("/items/{item_id}")asyncdefupdate_item(*,item_id:int=Path(title="The ID of the item to get",ge=0,le=1000),q:str|None=None,item:Item|None=None,):results={"item_id":item_id}ifq:results.update({"q":q})ifitem:results.update({"item":item})returnresultsNote
Notice that, in this case, theitem that would be taken from the body is optional. As it has aNone default value.
Multiple body parameters¶
In the previous example, thepath operations would expect a JSON body with the attributes of anItem, like:
{"name":"Foo","description":"The pretender","price":42.0,"tax":3.2}But you can also declare multiple body parameters, e.g.item anduser:
fromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=NoneclassUser(BaseModel):username:strfull_name:str|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item,user:User):results={"item_id":item_id,"item":item,"user":user}returnresultsIn this case,FastAPI will notice that there is more than one body parameter in the function (there are two parameters that are Pydantic models).
So, it will then use the parameter names as keys (field names) in the body, and expect a body like:
{"item":{"name":"Foo","description":"The pretender","price":42.0,"tax":3.2},"user":{"username":"dave","full_name":"Dave Grohl"}}Note
Notice that even though theitem was declared the same way as before, it is now expected to be inside of the body with a keyitem.
FastAPI will do the automatic conversion from the request, so that the parameteritem receives its specific content and the same foruser.
It will perform the validation of the compound data, and will document it like that for the OpenAPI schema and automatic docs.
Singular values in body¶
The same way there is aQuery andPath to define extra data for query and path parameters,FastAPI provides an equivalentBody.
For example, extending the previous model, you could decide that you want to have another keyimportance in the same body, besides theitem anduser.
If you declare it as is, because it is a singular value,FastAPI will assume that it is a query parameter.
But you can instructFastAPI to treat it as another body key usingBody:
fromtypingimportAnnotatedfromfastapiimportBody,FastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=NoneclassUser(BaseModel):username:strfull_name:str|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item,user:User,importance:Annotated[int,Body()]):results={"item_id":item_id,"item":item,"user":user,"importance":importance}returnresults🤓 Other versions and variants
Tip
Prefer to use theAnnotated version if possible.
fromfastapiimportBody,FastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=NoneclassUser(BaseModel):username:strfull_name:str|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item,user:User,importance:int=Body()):results={"item_id":item_id,"item":item,"user":user,"importance":importance}returnresultsIn this case,FastAPI will expect a body like:
{"item":{"name":"Foo","description":"The pretender","price":42.0,"tax":3.2},"user":{"username":"dave","full_name":"Dave Grohl"},"importance":5}Again, it will convert the data types, validate, document, etc.
Multiple body params and query¶
Of course, you can also declare additional query parameters whenever you need, additional to any body parameters.
As, by default, singular values are interpreted as query parameters, you don't have to explicitly add aQuery, you can just do:
q:str|None=NoneFor example:
fromtypingimportAnnotatedfromfastapiimportBody,FastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=NoneclassUser(BaseModel):username:strfull_name:str|None=None@app.put("/items/{item_id}")asyncdefupdate_item(*,item_id:int,item:Item,user:User,importance:Annotated[int,Body(gt=0)],q:str|None=None,):results={"item_id":item_id,"item":item,"user":user,"importance":importance}ifq:results.update({"q":q})returnresults🤓 Other versions and variants
Tip
Prefer to use theAnnotated version if possible.
fromfastapiimportBody,FastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=NoneclassUser(BaseModel):username:strfull_name:str|None=None@app.put("/items/{item_id}")asyncdefupdate_item(*,item_id:int,item:Item,user:User,importance:int=Body(gt=0),q:str|None=None,):results={"item_id":item_id,"item":item,"user":user,"importance":importance}ifq:results.update({"q":q})returnresultsInfo
Body also has all the same extra validation and metadata parameters asQuery,Path and others you will see later.
Embed a single body parameter¶
Let's say you only have a singleitem body parameter from a Pydantic modelItem.
By default,FastAPI will then expect its body directly.
But if you want it to expect a JSON with a keyitem and inside of it the model contents, as it does when you declare extra body parameters, you can use the specialBody parameterembed:
item:Item=Body(embed=True)as in:
fromtypingimportAnnotatedfromfastapiimportBody,FastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Annotated[Item,Body(embed=True)]):results={"item_id":item_id,"item":item}returnresults🤓 Other versions and variants
Tip
Prefer to use theAnnotated version if possible.
fromfastapiimportBody,FastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item=Body(embed=True)):results={"item_id":item_id,"item":item}returnresultsIn this caseFastAPI will expect a body like:
{"item":{"name":"Foo","description":"The pretender","price":42.0,"tax":3.2}}instead of:
{"name":"Foo","description":"The pretender","price":42.0,"tax":3.2}Recap¶
You can add multiple body parameters to yourpath operation function, even though a request can only have a single body.
ButFastAPI will handle it, give you the correct data in your function, and validate and document the correct schema in thepath operation.
You can also declare singular values to be received as part of the body.
And you can instructFastAPI to embed the body in a key even when there is only a single parameter declared.







