Browse Source

docs: clarify required query params that can represent None

pull/14750/head
Alberto Zambrano 6 months ago
parent
commit
1cc2ded7d9
  1. 77
      docs/en/docs/tutorial/query-params-str-validations.md

77
docs/en/docs/tutorial/query-params-str-validations.md

@ -4,7 +4,7 @@
Let's take this application as example: Let's take this application as example:
{_ ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] _} {* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
The query parameter `q` is of type `str | None`, that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required. The query parameter `q` is of type `str | None`, that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required.
@ -24,10 +24,10 @@ We are going to enforce that even though `q` is optional, whenever it is provide
To achieve that, first import: To achieve that, first import:
- `Query` from `fastapi` * `Query` from `fastapi`
- `Annotated` from `typing` * `Annotated` from `typing`
{_ ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] _} {* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
/// info /// info
@ -35,13 +35,13 @@ FastAPI added support for `Annotated` (and started recommending it) in version 0
If you have an older version, you would get errors when trying to use `Annotated`. If you have an older version, you would get errors when trying to use `Annotated`.
Make sure you [Upgrade the FastAPI version](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=\_blank} to at least 0.95.1 before using `Annotated`. Make sure you [Upgrade the FastAPI version](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} to at least 0.95.1 before using `Annotated`.
/// ///
## Use `Annotated` in the type for the `q` parameter { #use-annotated-in-the-type-for-the-q-parameter } ## Use `Annotated` in the type for the `q` parameter { #use-annotated-in-the-type-for-the-q-parameter }
Remember I told you before that `Annotated` can be used to add metadata to your parameters in the [Python Types Intro](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=\_blank}? Remember I told you before that `Annotated` can be used to add metadata to your parameters in the [Python Types Intro](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
Now it's the time to use it with FastAPI. 🚀 Now it's the time to use it with FastAPI. 🚀
@ -89,7 +89,7 @@ Now let's jump to the fun stuff. 🎉
Now that we have this `Annotated` where we can put more information (in this case some additional validation), add `Query` inside of `Annotated`, and set the parameter `max_length` to `50`: Now that we have this `Annotated` where we can put more information (in this case some additional validation), add `Query` inside of `Annotated`, and set the parameter `max_length` to `50`:
{_ ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] _} {* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
Notice that the default value is still `None`, so the parameter is still optional. Notice that the default value is still `None`, so the parameter is still optional.
@ -103,9 +103,9 @@ Here we are using `Query()` because this is a **query parameter**. Later we will
FastAPI will now: FastAPI will now:
- **Validate** the data making sure that the max length is 50 characters * **Validate** the data making sure that the max length is 50 characters
- Show a **clear error** for the client when the data is not valid * Show a **clear error** for the client when the data is not valid
- **Document** the parameter in the OpenAPI schema _path operation_ (so it will show up in the **automatic docs UI**) * **Document** the parameter in the OpenAPI schema *path operation* (so it will show up in the **automatic docs UI**)
## Alternative (old): `Query` as the default value { #alternative-old-query-as-the-default-value } ## Alternative (old): `Query` as the default value { #alternative-old-query-as-the-default-value }
@ -119,7 +119,7 @@ For new code and whenever possible, use `Annotated` as explained above. There ar
This is how you would use `Query()` as the default value of your function parameter, setting the parameter `max_length` to 50: This is how you would use `Query()` as the default value of your function parameter, setting the parameter `max_length` to 50:
{_ ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] _} {* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
As in this case (without using `Annotated`) we have to replace the default value `None` in the function with `Query()`, we now need to set the default value with the parameter `Query(default=None)`, it serves the same purpose of defining that default value (at least for FastAPI). As in this case (without using `Annotated`) we have to replace the default value `None` in the function with `Query()`, we now need to set the default value with the parameter `Query(default=None)`, it serves the same purpose of defining that default value (at least for FastAPI).
@ -131,6 +131,7 @@ q: str | None = Query(default=None)
...makes the parameter optional, with a default value of `None`, the same as: ...makes the parameter optional, with a default value of `None`, the same as:
```Python ```Python
q: str | None = None q: str | None = None
``` ```
@ -143,7 +144,7 @@ Then, we can pass more parameters to `Query`. In this case, the `max_length` par
q: str | None = Query(default=None, max_length=50) q: str | None = Query(default=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 _path operation_. This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema *path operation*.
### `Query` as the default value or in `Annotated` { #query-as-the-default-value-or-in-annotated } ### `Query` as the default value or in `Annotated` { #query-as-the-default-value-or-in-annotated }
@ -187,19 +188,19 @@ Because `Annotated` can have more than one metadata annotation, you could now ev
You can also add a parameter `min_length`: You can also add a parameter `min_length`:
{_ ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] _} {* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
## Add regular expressions { #add-regular-expressions } ## Add regular expressions { #add-regular-expressions }
You can define a <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">regular expression</abbr> `pattern` that the parameter should match: You can define a <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">regular expression</abbr> `pattern` that the parameter should match:
{_ ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] _} {* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
This specific regular expression pattern checks that the received parameter value: This specific regular expression pattern checks that the received parameter value:
- `^`: starts with the following characters, doesn't have characters before. * `^`: starts with the following characters, doesn't have characters before.
- `fixedquery`: has the exact value `fixedquery`. * `fixedquery`: has the exact value `fixedquery`.
- `$`: ends there, doesn't have any more characters after `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. 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.
@ -211,7 +212,7 @@ You can, of course, use default values other than `None`.
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"`: 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"`:
{_ ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] _} {* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
/// note /// note
@ -241,7 +242,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
So, when you need to declare a value as required while using `Query`, you can simply not declare a default value: So, when you need to declare a value as required while using `Query`, you can simply not declare a default value:
{_ ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] _} {* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
### Required, can be `None` { #required-can-be-none } ### Required, can be `None` { #required-can-be-none }
@ -262,7 +263,7 @@ When you define a query parameter explicitly with `Query` you can also declare i
For example, to declare a query parameter `q` that can appear multiple times in the URL, you can write: For example, to declare a query parameter `q` that can appear multiple times in the URL, you can write:
{_ ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] _} {* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
Then, with a URL like: Then, with a URL like:
@ -270,7 +271,7 @@ Then, with a URL like:
http://localhost:8000/items/?q=foo&q=bar http://localhost:8000/items/?q=foo&q=bar
``` ```
you would receive the multiple `q` _query parameters'_ values (`foo` and `bar`) in a Python `list` inside your _path operation function_, in the _function parameter_ `q`. you would receive the multiple `q` *query parameters'* values (`foo` and `bar`) in a Python `list` inside your *path operation function*, in the *function parameter* `q`.
So, the response to that URL would be: So, the response to that URL would be:
@ -297,7 +298,7 @@ The interactive API docs will update accordingly, to allow multiple values:
You can also define a default `list` of values if none are provided: You can also define a default `list` of values if none are provided:
{_ ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] _} {* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
If you go to: If you go to:
@ -320,7 +321,7 @@ the default of `q` will be: `["foo", "bar"]` and your response will be:
You can also use `list` directly instead of `list[str]`: You can also use `list` directly instead of `list[str]`:
{_ ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] _} {* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
/// note /// note
@ -346,11 +347,11 @@ Some of them might not show all the extra information declared yet, although in
You can add a `title`: You can add a `title`:
{_ ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] _} {* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
And a `description`: And a `description`:
{_ ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] _} {* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
## Alias parameters { #alias-parameters } ## Alias parameters { #alias-parameters }
@ -370,7 +371,7 @@ 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: Then you can declare an `alias`, and that alias is what will be used to find the parameter value:
{_ ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] _} {* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
## Deprecating parameters { #deprecating-parameters } ## Deprecating parameters { #deprecating-parameters }
@ -380,7 +381,7 @@ You have to leave it there a while because there are clients using it, but you w
Then pass the parameter `deprecated=True` to `Query`: Then pass the parameter `deprecated=True` to `Query`:
{_ ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] _} {* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
The docs will show it like this: The docs will show it like this:
@ -390,7 +391,7 @@ The docs will show it like this:
To exclude a query parameter from the generated OpenAPI schema (and thus, from the automatic documentation systems), set the parameter `include_in_schema` of `Query` to `False`: To exclude a query parameter from the generated OpenAPI schema (and thus, from the automatic documentation systems), set the parameter `include_in_schema` of `Query` to `False`:
{_ ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] _} {* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
## Custom Validation { #custom-validation } ## Custom Validation { #custom-validation }
@ -408,7 +409,7 @@ Pydantic also has <a href="https://docs.pydantic.dev/latest/concepts/validators/
For example, this custom validator checks that the item ID starts with `isbn-` for an <abbr title="ISBN means International Standard Book Number">ISBN</abbr> book number or with `imdb-` for an <abbr title="IMDB (Internet Movie Database) is a website with information about movies">IMDB</abbr> movie URL ID: For example, this custom validator checks that the item ID starts with `isbn-` for an <abbr title="ISBN means International Standard Book Number">ISBN</abbr> book number or with `imdb-` for an <abbr title="IMDB (Internet Movie Database) is a website with information about movies">IMDB</abbr> movie URL ID:
{_ ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] _} {* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
/// info /// info
@ -436,7 +437,7 @@ But if you're curious about this specific code example and you're still entertai
Did you notice? a string using `value.startswith()` can take a tuple, and it will check each value in the tuple: Did you notice? a string using `value.startswith()` can take a tuple, and it will check each value in the tuple:
{_ ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] _} {* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
#### A Random Item { #a-random-item } #### A Random Item { #a-random-item }
@ -452,7 +453,7 @@ So, if the user didn't provide an item ID, they will still receive a random sugg
...we do all this in a **single simple line**. 🤯 Don't you love Python? 🐍 ...we do all this in a **single simple line**. 🤯 Don't you love Python? 🐍
{_ ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] _} {* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
## Recap { #recap } ## Recap { #recap }
@ -460,16 +461,16 @@ You can declare additional validations and metadata for your parameters.
Generic validations and metadata: Generic validations and metadata:
- `alias` * `alias`
- `title` * `title`
- `description` * `description`
- `deprecated` * `deprecated`
Validations specific for strings: Validations specific for strings:
- `min_length` * `min_length`
- `max_length` * `max_length`
- `pattern` * `pattern`
Custom validations using `AfterValidator`. Custom validations using `AfterValidator`.

Loading…
Cancel
Save