diff --git a/docs/img/tutorial/query-params-schema/image01.png b/docs/img/tutorial/query-params-schema/image01.png new file mode 100644 index 000000000..901341f89 Binary files /dev/null and b/docs/img/tutorial/query-params-schema/image01.png differ diff --git a/docs/index.md b/docs/index.md index 39d40509c..3fc9b6067 100644 --- a/docs/index.md +++ b/docs/index.md @@ -279,7 +279,7 @@ Try changing the line with: ![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) -For a more complete example including more features, [see the tutorial](). +For a more complete example including more features, [see the tutorial](tutorial/intro/). **Spoiler alert**: the tutorial, although very short, includes: diff --git a/docs/tutorial/first-steps.md b/docs/tutorial/first-steps.md index a09a1442d..5572fc2e9 100644 --- a/docs/tutorial/first-steps.md +++ b/docs/tutorial/first-steps.md @@ -57,6 +57,33 @@ You will see the alternative automatic documentation (provided by http://127.0.0.1:8000/openapi.json. + +It will show a JSON starting with something like: + +```JSON +{ + "openapi": "3.0.2", + "info": { + "title": "Fast API", + "version": "0.1.0" + }, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + + + +... +``` + ## Recap, step by step ### Step 1: import `FastAPI` diff --git a/docs/tutorial/query-params-schema.md b/docs/tutorial/query-params-schema.md new file mode 100644 index 000000000..30b115f23 --- /dev/null +++ b/docs/tutorial/query-params-schema.md @@ -0,0 +1,181 @@ +**FastAPI** allows you to declare additonal information and validation for your parameters. + +Let's take this application as example: + +```Python hl_lines="7" +{!./tutorial/src/query-params-schema/tutorial001.py!} +``` + +The query parameter `q` is of type `str`, and by default is `None`, so it is optional. + +## Additional validation + +We are going to enforce that even though `q` is optional, whenever it is provided, it **doesn't exceed a length of 50 characters**. + + +### Import `Query` + +To achieve that, first import `Query` from `fastapi`: + +```Python hl_lines="1" +{!./tutorial/src/query-params-schema/tutorial002.py!} +``` + +## Use `Query` as the default value + +And now use it as the default value of your parameter, setting the parameter `max_length` to 50: + +```Python hl_lines="7" +{!./tutorial/src/query-params-schema/tutorial002.py!} +``` + +As we have to replace the default value `None` with `Query(None)`, the first parameter to `Query` serves the same purpose of defining that default value. + +So: + +```Python +q: str = Query(None) +``` + +...makes the parameter optional, the same as: + +```Python +q: str = None +``` + +But it declares it explicitly as being a query parameter. + +And then, we can pass more parameters to `Query`. In this case, the `max_length` parameter that applies to strings: + +```Python +q: str = Query(None, max_length=50) +``` + +This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema endpoint. + + +## Add more validations + +You can also add a parameter `min_length`: + +```Python hl_lines="7" +{!./tutorial/src/query-params-schema/tutorial003.py!} +``` + +## Add regular expressions + +You can define a regular expression that the parameter should match: + +```Python hl_lines="8" +{!./tutorial/src/query-params-schema/tutorial004.py!} +``` + +This specific regular expression checks that the received parameter value: + +* `^`: starts with the following characters, doesn't have characters before. +* `fixedquery`: has the exact value `fixedquery`. +* `$`: ends there, doesn't have any more characters after `fixedquery`. + +If you feel lost with all these **"regular expression"** ideas, don't worry. They are a hard topic for many people. You can still do a lot of stuff without needing regular expressions yet. + +But whenever you need them and go and learn them, know that you can already use them directly in **FastAPI**. + +## Default values + +The same way that you can pass `None` as the first argument to be used as the default value, you can pass other values. + +Let's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `"fixedquery"`: + +```Python hl_lines="7" +{!./tutorial/src/query-params-schema/tutorial005.py!} +``` + +!!! note + Having a default value also makes the parameter optional. + +## Make it required + +When we don't need to declare more validations or metadata, we can make the `q` query parameter required just by not declaring a default value, like: + +```Python +q: str +``` + +instead of: + +```Python +q: str = None +``` + +But we are now declaring it with `Query`, for example like: + +```Python +q: str = Query(None, min_length=3) +``` + +So, when you need to declare a value as required while using `Query`, you can use `...` as the first argument: + +```Python hl_lines="7" +{!./tutorial/src/query-params-schema/tutorial006.py!} +``` + +!!! info + If you hadn't seen that `...` before: it is a a special single value, it is part of Python and is called "Ellipsis". + +This will let **FastAPI** know that this parameter is required. + +## Declare more metadata + +You can add more information about the parameter. + +That information will be included in the generated OpenAPI and used by the documentation user interfaces and external tools. + +You can add a `title`: + +```Python hl_lines="7" +{!./tutorial/src/query-params-schema/tutorial007.py!} +``` + +And a `description`: + +```Python hl_lines="11" +{!./tutorial/src/query-params-schema/tutorial008.py!} +``` + +## Alias parameters + +Imagine that you want the parameter to be `item-query`. + +Like in: + +``` +http://127.0.0.1:8000/items/?item-query=foobaritems +``` + +But `item-query` is not a valid Python variable name. + +The closest would be `item_query`. + +But you still need it to be exactly `item-query`... + +Then you can declare an `alias`, and that alias is what will be used to find the parameter value: + +```Python hl_lines="7" +{!./tutorial/src/query-params-schema/tutorial009.py!} +``` + +## Deprecating parameters + +Now let's say you don't like this parameter anymore. + +You have to leave it there a while because there are clients using it, but you want the docs to clearly show it as deprecated. + +Then pass the parameter `deprecated=True` to `Query`: + +```Python hl_lines="16" +{!./tutorial/src/query-params-schema/tutorial010.py!} +``` + +The docs will show it like this: + + diff --git a/docs/tutorial/src/query-params-schema/tutorial001.py b/docs/tutorial/src/query-params-schema/tutorial001.py new file mode 100644 index 000000000..b06c33c3e --- /dev/null +++ b/docs/tutorial/src/query-params-schema/tutorial001.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str = None): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs/tutorial/src/query-params-schema/tutorial002.py b/docs/tutorial/src/query-params-schema/tutorial002.py new file mode 100644 index 000000000..183180cd7 --- /dev/null +++ b/docs/tutorial/src/query-params-schema/tutorial002.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str = Query(None, max_length=50)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs/tutorial/src/query-params-schema/tutorial003.py b/docs/tutorial/src/query-params-schema/tutorial003.py new file mode 100644 index 000000000..311ece816 --- /dev/null +++ b/docs/tutorial/src/query-params-schema/tutorial003.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str = Query(None, min_length=3, max_length=50)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs/tutorial/src/query-params-schema/tutorial004.py b/docs/tutorial/src/query-params-schema/tutorial004.py new file mode 100644 index 000000000..785db44c0 --- /dev/null +++ b/docs/tutorial/src/query-params-schema/tutorial004.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items( + q: str = Query(None, min_length=3, max_length=50, regex="^fixedquery$") +): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs/tutorial/src/query-params-schema/tutorial005.py b/docs/tutorial/src/query-params-schema/tutorial005.py new file mode 100644 index 000000000..22eb3acba --- /dev/null +++ b/docs/tutorial/src/query-params-schema/tutorial005.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str = Query("fixedquery", min_length=3)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs/tutorial/src/query-params-schema/tutorial006.py b/docs/tutorial/src/query-params-schema/tutorial006.py new file mode 100644 index 000000000..720bf07f1 --- /dev/null +++ b/docs/tutorial/src/query-params-schema/tutorial006.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str = Query(..., min_length=3)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs/tutorial/src/query-params-schema/tutorial007.py b/docs/tutorial/src/query-params-schema/tutorial007.py new file mode 100644 index 000000000..76b9ea811 --- /dev/null +++ b/docs/tutorial/src/query-params-schema/tutorial007.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str = Query(None, title="Query string", min_length=3)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs/tutorial/src/query-params-schema/tutorial008.py b/docs/tutorial/src/query-params-schema/tutorial008.py new file mode 100644 index 000000000..339f80e93 --- /dev/null +++ b/docs/tutorial/src/query-params-schema/tutorial008.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items( + q: str = Query( + None, + title="Query string", + description="Query string for the items to search in the database that have a good match", + min_length=3, + ) +): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs/tutorial/src/query-params-schema/tutorial009.py b/docs/tutorial/src/query-params-schema/tutorial009.py new file mode 100644 index 000000000..7f5010014 --- /dev/null +++ b/docs/tutorial/src/query-params-schema/tutorial009.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str = Query(None, alias="item-query")): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs/tutorial/src/query-params-schema/tutorial010.py b/docs/tutorial/src/query-params-schema/tutorial010.py new file mode 100644 index 000000000..051656c76 --- /dev/null +++ b/docs/tutorial/src/query-params-schema/tutorial010.py @@ -0,0 +1,22 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items( + q: str = Query( + None, + alias="item-query", + title="Query string", + description="Query string for the items to search in the database that have a good match", + min_length=3, + max_length=50, + regex="^fixedquery$", + deprecated=True, + ) +): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/mkdocs.yml b/mkdocs.yml index 089fe9492..2a4aca4e1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,6 +22,7 @@ nav: - Path Parameters: 'tutorial/path-params.md' - Query Parameters: 'tutorial/query-params.md' - Request Body: 'tutorial/body.md' + - Query Parameters with toppings: 'tutorial/query-params-schema.md' - Concurrency and async / await: 'async.md' - Deployment: 'deployment.md'