From 710df85566a4525d71855f817214e3630f62c366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 14 Dec 2018 19:17:17 +0400 Subject: [PATCH] :memo: Add body multiple parameters docs --- docs/tutorial/body-multiple-params.md | 167 ++++++++++++++++++ .../path-params-numeric-validations.md | 5 + .../src/body-multiple-params/tutorial001.py | 26 +++ .../src/body-multiple-params/tutorial002.py | 22 +++ .../src/body-multiple-params/tutorial003.py | 24 +++ .../src/body-multiple-params/tutorial004.py | 31 ++++ .../src/body-multiple-params/tutorial005.py | 17 ++ mkdocs.yml | 5 +- 8 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 docs/tutorial/body-multiple-params.md create mode 100644 docs/tutorial/src/body-multiple-params/tutorial001.py create mode 100644 docs/tutorial/src/body-multiple-params/tutorial002.py create mode 100644 docs/tutorial/src/body-multiple-params/tutorial003.py create mode 100644 docs/tutorial/src/body-multiple-params/tutorial004.py create mode 100644 docs/tutorial/src/body-multiple-params/tutorial005.py diff --git a/docs/tutorial/body-multiple-params.md b/docs/tutorial/body-multiple-params.md new file mode 100644 index 000000000..c95cfca97 --- /dev/null +++ b/docs/tutorial/body-multiple-params.md @@ -0,0 +1,167 @@ +Now that we have seen how to use `Path` and `Query`, let's see more advanced uses of request body declarations. + +## Mix `Path`, `Query` and body parameters + +First, of course, you can mix `Path`, `Query` and request body parameter declarations freely and **FastAPI** will know what to do. + +```Python hl_lines="17 18 19" +{!./tutorial/src/body-multiple-params/tutorial001.py!} +``` + +!!! note + Notice that, in this case, the `item` that would be taken from the body is optional. As it has a `None` default value. + + +## Multiple body parameters + +In the previous example, the endpoint would expect a JSON body with the attributes of an `Item`, like: + +```JSON +{ + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2 +} +``` + +But you can also declare multiple body parameters, e.g. `item` and `user`: + +```Python hl_lines="20" +{!./tutorial/src/body-multiple-params/tutorial002.py!} +``` + +In this case, **FastAPI** will notice that there are more than one body parameter in the function (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: + +```JSON +{ + "item": { + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2 + }, + "user": { + "username": "dave", + "full_name": "Dave Grohl" + } +} +``` + +!!! note + Notice that even though the `item` was declared the same way as before, it is now expected to be inside of the body with a key `item`. + + +**FastAPI** will do the automatic conversion from the request, so that the parameter `item` receives it's specific content and the same for `user`. + +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 a `Query` and `Path` to define extra data for query and path parameters, **FastAPI** provides an equivalent `Body`. + +For example, extending the previous model, you could decide that you want to have another key `importance` in the same body, besides the `item` and `user`. + +If you declare it as is, because it is a singular value, **FastAPI** will assume that it is a query parameter. + +But you can instruct **FastAPI** to treat it as another body key using `Body`: + + +```Python hl_lines="21" +{!./tutorial/src/body-multiple-params/tutorial003.py!} +``` + +In this case, **FastAPI** will expect a body like: + + +```JSON +{ + "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 a `Query`, you can just do: + +```Python +q: str = None +``` + +as in: + +```Python hl_lines="25" +{!./tutorial/src/body-multiple-params/tutorial004.py!} +``` + +!!! info + `Body` also has all the same extra validation and metadata parameters as `Query`,`Path` and others you will see later. + + +## Embed a single body parameter + +Let's say you only have a single `item` body parameter from a Pydantic model `Item`. + +By default, **FastAPI** will then expect its body directly. + +But if you want it to expect a JSON with a key `item` and inside of it the model contents, as it does when you declare extra body parameters, you can use the special `Body` parameter `embed`: + +```Python +item: Item = Body(..., embed=True) +``` + +as in: + +```Python hl_lines="15" +{!./tutorial/src/body-multiple-params/tutorial005.py!} +``` + +In this case **FastAPI** will expect a body like: + +```JSON hl_lines="2" +{ + "item": { + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2 + } +} +``` + +instead of: + +```JSON +{ + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2 +} +``` + +## Recap + +You can add multiple body parameters to your function endpoint, even though a request can only have a single body. + +But **FastAPI** will handle it, give you the correct data in your function, and validate and document the correct schema in the endpoint. + +You can also declare singular values to be received as part of the body. + +And you can instruct **FastAPI** to embed the body in a key even when there is only a single parameter declared. diff --git a/docs/tutorial/path-params-numeric-validations.md b/docs/tutorial/path-params-numeric-validations.md index 58ef304da..eade3da02 100644 --- a/docs/tutorial/path-params-numeric-validations.md +++ b/docs/tutorial/path-params-numeric-validations.md @@ -101,3 +101,8 @@ And you can also declare numeric validations: * `ge`: `g`reater than or `e`qual * `lt`: `l`ess `t`han * `le`: `l`ess than or `e`qual + +!!! info + `Query`, `Path` and others you will see later are subclasses of a common `Param` class (that you don't need to use). + + And all of them share the same all these same parameters of additional validation and metadata you have seen. \ No newline at end of file diff --git a/docs/tutorial/src/body-multiple-params/tutorial001.py b/docs/tutorial/src/body-multiple-params/tutorial001.py new file mode 100644 index 000000000..7918a2f96 --- /dev/null +++ b/docs/tutorial/src/body-multiple-params/tutorial001.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI, Path +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str = None + price: float + tax: float = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000), + q: str, + item: Item = None, +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + if item: + results.update({"item": item}) + return results diff --git a/docs/tutorial/src/body-multiple-params/tutorial002.py b/docs/tutorial/src/body-multiple-params/tutorial002.py new file mode 100644 index 000000000..5c9e8344d --- /dev/null +++ b/docs/tutorial/src/body-multiple-params/tutorial002.py @@ -0,0 +1,22 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str = None + price: float + tax: float = None + + +class User(BaseModel): + username: str + full_name: str = None + + +@app.put("/items/{item_id}") +async def update_item(*, item_id: int, item: Item, user: User): + results = {"item_id": item_id, "item": item, "user": user} + return results diff --git a/docs/tutorial/src/body-multiple-params/tutorial003.py b/docs/tutorial/src/body-multiple-params/tutorial003.py new file mode 100644 index 000000000..301f1a862 --- /dev/null +++ b/docs/tutorial/src/body-multiple-params/tutorial003.py @@ -0,0 +1,24 @@ +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str = None + price: float + tax: float = None + + +class User(BaseModel): + username: str + full_name: str = None + + +@app.put("/items/{item_id}") +async def update_item( + *, item_id: int, item: Item, user: User, importance: int = Body(...) +): + results = {"item_id": item_id, "item": item, "user": user, "importance": importance} + return results diff --git a/docs/tutorial/src/body-multiple-params/tutorial004.py b/docs/tutorial/src/body-multiple-params/tutorial004.py new file mode 100644 index 000000000..359b33ccc --- /dev/null +++ b/docs/tutorial/src/body-multiple-params/tutorial004.py @@ -0,0 +1,31 @@ +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str = None + price: float + tax: float = None + + +class User(BaseModel): + username: str + full_name: str = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Item, + user: User, + importance: int = Body(..., gt=0), + q: str = None +): + results = {"item_id": item_id, "item": item, "user": user, "importance": importance} + if q: + results.update({"q": q}) + return results diff --git a/docs/tutorial/src/body-multiple-params/tutorial005.py b/docs/tutorial/src/body-multiple-params/tutorial005.py new file mode 100644 index 000000000..61f1b2917 --- /dev/null +++ b/docs/tutorial/src/body-multiple-params/tutorial005.py @@ -0,0 +1,17 @@ +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str = None + price: float + tax: float = None + + +@app.put("/items/{item_id}") +async def update_item(*, item_id: int, item: Item = Body(..., embed=True)): + results = {"item_id": item_id, "item": item} + return results diff --git a/mkdocs.yml b/mkdocs.yml index a88c6f445..855ea596b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,8 +22,9 @@ nav: - Path Parameters: 'tutorial/path-params.md' - Query Parameters: 'tutorial/query-params.md' - Request Body: 'tutorial/body.md' - - Query Parameters - string validations: 'tutorial/query-params-str-validations.md' - - Path Parameters - numeric validations: 'tutorial/path-params-numeric-validations.md' + - Query Parameters - String Validations: 'tutorial/query-params-str-validations.md' + - Path Parameters - Numeric Validations: 'tutorial/path-params-numeric-validations.md' + - Body - Multiple Parameters: 'tutorial/body-multiple-params.md' - Concurrency and async / await: 'async.md' - Deployment: 'deployment.md'