]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
📝 Update docs for Query Params and String Validations, remove obsolete Ellipsis docs...
authorSebastián Ramírez <tiangolo@gmail.com>
Sat, 15 Feb 2025 16:23:59 +0000 (17:23 +0100)
committerGitHub <noreply@github.com>
Sat, 15 Feb 2025 16:23:59 +0000 (17:23 +0100)
17 files changed:
docs/de/docs/tutorial/query-params-str-validations.md
docs/em/docs/tutorial/query-params-str-validations.md
docs/en/docs/tutorial/query-params-str-validations.md
docs/es/docs/tutorial/query-params-str-validations.md
docs/ru/docs/tutorial/query-params-str-validations.md
docs/zh/docs/tutorial/query-params-str-validations.md
docs_src/query_params_str_validations/tutorial006b.py [deleted file]
docs_src/query_params_str_validations/tutorial006b_an.py [deleted file]
docs_src/query_params_str_validations/tutorial006b_an_py39.py [deleted file]
docs_src/query_params_str_validations/tutorial006c.py
docs_src/query_params_str_validations/tutorial006c_an.py
docs_src/query_params_str_validations/tutorial006c_an_py310.py
docs_src/query_params_str_validations/tutorial006c_an_py39.py
docs_src/query_params_str_validations/tutorial006c_py310.py
docs_src/query_params_str_validations/tutorial006d.py [deleted file]
docs_src/query_params_str_validations/tutorial006d_an.py [deleted file]
docs_src/query_params_str_validations/tutorial006d_an_py39.py [deleted file]

index f181d501c8367908742273aaf2e8943043110403..de8879ce8c11533271d024dd96b2299217662fe7 100644 (file)
@@ -315,22 +315,6 @@ Wenn Sie einen Parameter erforderlich machen wollen, während Sie `Query` verwen
 
 {* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
 
-### Erforderlich mit Ellipse (`...`)
-
-Es gibt eine Alternative, die explizit deklariert, dass ein Wert erforderlich ist. Sie können als Default das <abbr title='Zeichenfolge, die einen Wert direkt darstellt, etwa 1, "hallowelt", True, None'>Literal</abbr> `...` setzen:
-
-{* ../../docs_src/query_params_str_validations/tutorial006b_an_py39.py hl[9] *}
-
-/// info
-
-Falls Sie das `...` bisher noch nicht gesehen haben: Es ist ein spezieller einzelner Wert, <a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">Teil von Python und wird „Ellipsis“ genannt</a> (Deutsch: Ellipse).
-
-Es wird von Pydantic und FastAPI verwendet, um explizit zu deklarieren, dass ein Wert erforderlich ist.
-
-///
-
-Dies wird **FastAPI** wissen lassen, dass dieser Parameter erforderlich ist.
-
 ### Erforderlich, kann `None` sein
 
 Sie können deklarieren, dass ein Parameter `None` akzeptiert, aber dennoch erforderlich ist. Das zwingt Clients, den Wert zu senden, selbst wenn er `None` ist.
index dbaab5735dcada18ec7dfd9b25e9d06a163551d4..fd077bf8f7a5b0a0022b608d9f71a0b34342f484 100644 (file)
@@ -148,22 +148,6 @@ q: Union[str, None] = Query(default=None, min_length=3)
 
 {* ../../docs_src/query_params_str_validations/tutorial006.py hl[7] *}
 
-### ✔ ⏮️ ❕ (`...`)
-
-📤 🎛 🌌 🎯 📣 👈 💲 ✔. 👆 💪 ⚒ `default` 🔢 🔑 💲 `...`:
-
-{* ../../docs_src/query_params_str_validations/tutorial006b.py hl[7] *}
-
-/// info
-
-🚥 👆 🚫 👀 👈 `...` ⏭: ⚫️ 🎁 👁 💲, ⚫️ <a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">🍕 🐍 &amp; 🤙 "❕"</a>.
-
-⚫️ ⚙️ Pydantic &amp; FastAPI 🎯 📣 👈 💲 ✔.
-
-///
-
-👉 🔜 ➡️ **FastAPI** 💭 👈 👉 🔢 ✔.
-
 ### ✔ ⏮️ `None`
 
 👆 💪 📣 👈 🔢 💪 🚫 `None`, ✋️ 👈 ⚫️ ✔. 👉 🔜 ⚡ 👩‍💻 📨 💲, 🚥 💲 `None`.
@@ -178,18 +162,6 @@ Pydantic, ❔ ⚫️❔ 🏋️ 🌐 💽 🔬 &amp; 🛠️ FastAPI, ✔️ 
 
 ///
 
-### ⚙️ Pydantic `Required` ↩️ ❕ (`...`)
-
-🚥 👆 💭 😬 ⚙️ `...`, 👆 💪 🗄 &amp; ⚙️ `Required` ⚪️➡️ Pydantic:
-
-{* ../../docs_src/query_params_str_validations/tutorial006d.py hl[2,8] *}
-
-/// tip
-
-💭 👈 🌅 💼, 🕐❔ 🕳 🚚, 👆 💪 🎯 🚫 `default` 🔢, 👆 🛎 🚫 ✔️ ⚙️ `...` 🚫 `Required`.
-
-///
-
 ## 🔢 🔢 📇 / 💗 💲
 
 🕐❔ 👆 🔬 🔢 🔢 🎯 ⏮️ `Query` 👆 💪 📣 ⚫️ 📨 📇 💲, ⚖️ 🙆‍♀ 🎏 🌌, 📨 💗 💲.
index 1bf16334d2a74e2261bb15adc6835e93a9000bdc..5110991861cdb753a57ba7ecf1aa0a8e0919cba3 100644 (file)
@@ -6,13 +6,13 @@ Let's take this application as example:
 
 {* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
 
-The query parameter `q` is of type `Union[str, None]` (or `str | None` in Python 3.10), 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.
 
 /// note
 
 FastAPI will know that the value of `q` is not required because of the default value `= None`.
 
-The `Union` in `Union[str, None]` will allow your editor to give you better support and detect errors.
+Having `str | None` will allow your editor to give you better support and detect errors.
 
 ///
 
@@ -25,29 +25,9 @@ We are going to enforce that even though `q` is optional, whenever it is provide
 To achieve that, first import:
 
 * `Query` from `fastapi`
-* `Annotated` from `typing` (or from `typing_extensions` in Python below 3.9)
+* `Annotated` from `typing`
 
-//// tab | Python 3.10+
-
-In Python 3.9 or above, `Annotated` is part of the standard library, so you can import it from `typing`.
-
-```Python hl_lines="1  3"
-{!> ../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-In versions of Python below Python 3.9 you import `Annotated` from `typing_extensions`.
-
-It will already be installed with FastAPI.
-
-```Python hl_lines="3-4"
-{!> ../../docs_src/query_params_str_validations/tutorial002_an.py!}
-```
-
-////
+{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
 
 /// info
 
@@ -145,54 +125,23 @@ As in this case (without using `Annotated`) we have to replace the default value
 
 So:
 
-```Python
-q: Union[str, None] = Query(default=None)
-```
-
-...makes the parameter optional, with a default value of `None`, the same as:
-
-```Python
-q: Union[str, None] = None
-```
-
-And in Python 3.10 and above:
-
 ```Python
 q: str | None = Query(default=None)
 ```
 
 ...makes the parameter optional, with a default value of `None`, the same as:
 
-```Python
-q: str | None = None
-```
-
-But the `Query` versions declare it explicitly as being a query parameter.
-
-/// info
-
-Keep in mind that the most important part to make a parameter optional is the part:
 
 ```Python
-= None
-```
-
-or the:
-
-```Python
-= Query(default=None)
+q: str | None = 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.
-
-///
+But the `Query` version declares it explicitly as being a query parameter.
 
 Then, we can pass more parameters to `Query`. In this case, the `max_length` parameter that applies to strings:
 
 ```Python
-q: Union[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*.
@@ -201,7 +150,7 @@ This will validate the data, show a clear error when the data is not valid, and
 
 Keep in mind that when using `Query` inside of `Annotated` you cannot use the `default` parameter for `Query`.
 
-Instead use the actual default value of the function parameter. Otherwise, it would be inconsistent.
+Instead, use the actual default value of the function parameter. Otherwise, it would be inconsistent.
 
 For example, this is not allowed:
 
@@ -255,7 +204,7 @@ This specific regular expression pattern checks that the received parameter valu
 
 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**.
+Now you know that whenever you need them you can use them in **FastAPI**.
 
 ### Pydantic v1 `regex` instead of `pattern`
 
@@ -296,7 +245,7 @@ q: str
 instead of:
 
 ```Python
-q: Union[str, None] = None
+q: str | None = None
 ```
 
 But we are now declaring it with `Query`, for example like:
@@ -304,15 +253,7 @@ But we are now declaring it with `Query`, for example like:
 //// tab | Annotated
 
 ```Python
-q: Annotated[Union[str, None], Query(min_length=3)] = None
-```
-
-////
-
-//// tab | non-Annotated
-
-```Python
-q: Union[str, None] = Query(default=None, min_length=3)
+q: Annotated[str | None, Query(min_length=3)] = None
 ```
 
 ////
@@ -321,42 +262,14 @@ So, when you need to declare a value as required while using `Query`, you can si
 
 {* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
 
-### Required with Ellipsis (`...`)
-
-There's an alternative way to explicitly declare that a value is required. You can set the default to the literal value `...`:
-
-{* ../../docs_src/query_params_str_validations/tutorial006b_an_py39.py hl[9] *}
-
-/// info
-
-If you hadn't seen that `...` before: it is a special single value, it is <a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">part of Python and is called "Ellipsis"</a>.
-
-It is used by Pydantic and FastAPI to explicitly declare that a value is required.
-
-///
-
-This will let **FastAPI** know that this parameter is required.
-
 ### Required, can be `None`
 
 You can declare that a parameter can accept `None`, but that it's still required. This would force clients to send a value, even if the value is `None`.
 
-To do that, you can declare that `None` is a valid type but still use `...` as the default:
+To do that, you can declare that `None` is a valid type but simply do not declare a default value:
 
 {* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
 
-/// tip
-
-Pydantic, which is what powers all the data validation and serialization in FastAPI, has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about <a href="https://docs.pydantic.dev/2.3/usage/models/#required-optional-fields" class="external-link" target="_blank">Required fields</a>.
-
-///
-
-/// tip
-
-Remember that in most of the cases, when something is required, you can simply omit the default, so you normally don't have to use `...`.
-
-///
-
 ## Query parameter list / multiple values
 
 When you define a query parameter explicitly with `Query` you can also declare it to receive a list of values, or said in another way, to receive multiple values.
@@ -396,7 +309,7 @@ The interactive API docs will update accordingly, to allow multiple values:
 
 ### Query parameter list / multiple values with defaults
 
-And 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] *}
 
@@ -419,7 +332,7 @@ the default of `q` will be: `["foo", "bar"]` and your response will be:
 
 #### Using just `list`
 
-You can also use `list` directly instead of `List[str]` (or `list[str]` in Python 3.9+):
+You can also use `list` directly instead of `list[str]`:
 
 {* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
 
@@ -427,7 +340,7 @@ You can also use `list` directly instead of `List[str]` (or `list[str]` in Pytho
 
 Keep in mind that in this case, FastAPI won't check the contents of the list.
 
-For example, `List[int]` would check (and document) that the contents of the list are integers. But `list` alone wouldn't.
+For example, `list[int]` would check (and document) that the contents of the list are integers. But `list` alone wouldn't.
 
 ///
 
index f378b9dce256ebbe9e181ff945c98fa2badb8ce3..9cb76156f0ca181c3054e87e923df06873de3466 100644 (file)
@@ -321,22 +321,6 @@ Así que, cuando necesites declarar un valor como requerido mientras usas `Query
 
 {* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
 
-### Requerido con Puntos suspensivos (`...`)
-
-Hay una manera alternativa de declarar explícitamente que un valor es requerido. Puedes establecer el valor por defecto al valor literal `...`:
-
-{* ../../docs_src/query_params_str_validations/tutorial006b_an_py39.py hl[9] *}
-
-/// info | Información
-
-Si no habías visto eso `...` antes: es un valor especial único, es <a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">parte de Python y se llama "Ellipsis"</a>.
-
-Se usa por Pydantic y FastAPI para declarar explícitamente que un valor es requerido.
-
-///
-
-Esto le permitirá a **FastAPI** saber que este parámetro es requerido.
-
 ### Requerido, puede ser `None`
 
 Puedes declarar que un parámetro puede aceptar `None`, pero que aún así es requerido. Esto obligaría a los clientes a enviar un valor, incluso si el valor es `None`.
index 32a98ff220b16a04da7fe0e9e6df2d360ea6d1f8..13b7015db50036e9ff60c6c2af88fc5b8a5b0ff7 100644 (file)
@@ -291,22 +291,6 @@ q: Union[str, None] = Query(default=None, min_length=3)
 
 {* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
 
-### Обязательный параметр с Ellipsis (`...`)
-
-Альтернативный способ указать обязательность параметра запроса - это указать параметр `default` через многоточие `...`:
-
-{* ../../docs_src/query_params_str_validations/tutorial006b_an_py39.py hl[9] *}
-
-/// info | Дополнительная информация
-
-Если вы ранее не сталкивались с `...`: это специальное значение, <a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">часть языка Python и называется "Ellipsis"</a>.
-
-Используется в Pydantic и FastAPI для определения, что значение требуется обязательно.
-
-///
-
-Таким образом, **FastAPI** определяет, что параметр является обязательным.
-
 ### Обязательный параметр с `None`
 
 Вы можете определить, что параметр может принимать `None`, но всё ещё является обязательным. Это может потребоваться для того, чтобы пользователи явно указали параметр, даже если его значение будет `None`.
@@ -321,18 +305,6 @@ Pydantic, мощь которого используется в FastAPI для 
 
 ///
 
-### Использование Pydantic's `Required` вместо Ellipsis (`...`)
-
-Если вас смущает `...`, вы можете использовать `Required` из Pydantic:
-
-{* ../../docs_src/query_params_str_validations/tutorial006d_an_py39.py hl[4,10] *}
-
-/// tip | Подсказка
-
-Запомните, когда вам необходимо объявить query-параметр обязательным, вы можете просто не указывать параметр `default`. Таким образом, вам редко придётся использовать `...` или `Required`.
-
-///
-
 ## Множество значений для query-параметра
 
 Для query-параметра `Query` можно указать, что он принимает список значений (множество значений).
index 2fba671f7c9f25684ce3392b7938bb8247dc9d51..c2f9a7e9f09ee2cacc83e84a067236de650ac4aa 100644 (file)
@@ -108,21 +108,6 @@ q: Union[str, None] = Query(default=None, min_length=3)
 
 {* ../../docs_src/query_params_str_validations/tutorial006.py hl[7] *}
 
-### 使用省略号(`...`)声明必需参数
-
-有另一种方法可以显式的声明一个值是必需的,即将默认参数的默认值设为 `...` :
-
-{* ../../docs_src/query_params_str_validations/tutorial006b.py hl[7] *}
-
-/// info
-
-如果你之前没见过 `...` 这种用法:它是一个特殊的单独值,它是 <a href="https://docs.python.org/zh-cn/3/library/constants.html#Ellipsis" class="external-link" target="_blank">Python 的一部分并且被称为“Ellipsis”(意为省略号 —— 译者注)</a>。
-Pydantic 和 FastAPI 使用它来显式的声明需要一个值。
-
-///
-
-这将使 **FastAPI** 知道此查询参数是必需的。
-
 ### 使用`None`声明必需参数
 
 你可以声明一个参数可以接收`None`值,但它仍然是必需的。这将强制客户端发送一个值,即使该值是`None`。
@@ -137,18 +122,6 @@ Pydantic 是 FastAPI 中所有数据验证和序列化的核心,当你在没
 
 ///
 
-### 使用Pydantic中的`Required`代替省略号(`...`)
-
-如果你觉得使用 `...` 不舒服,你也可以从 Pydantic 导入并使用 `Required`:
-
-{* ../../docs_src/query_params_str_validations/tutorial006d.py hl[2,8] *}
-
-/// tip
-
-请记住,在大多数情况下,当你需要某些东西时,可以简单地省略 `default` 参数,因此你通常不必使用 `...` 或 `Required`
-
-///
-
 ## 查询参数列表 / 多个值
 
 当你使用 `Query` 显式地定义查询参数时,你还可以声明它去接收一组值,或换句话来说,接收多个值。
diff --git a/docs_src/query_params_str_validations/tutorial006b.py b/docs_src/query_params_str_validations/tutorial006b.py
deleted file mode 100644 (file)
index a8d69c8..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: str = Query(default=..., min_length=3)):
-    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
-    if q:
-        results.update({"q": q})
-    return results
diff --git a/docs_src/query_params_str_validations/tutorial006b_an.py b/docs_src/query_params_str_validations/tutorial006b_an.py
deleted file mode 100644 (file)
index ea3b025..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-from fastapi import FastAPI, Query
-from typing_extensions import Annotated
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Annotated[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_src/query_params_str_validations/tutorial006b_an_py39.py b/docs_src/query_params_str_validations/tutorial006b_an_py39.py
deleted file mode 100644 (file)
index 687a9f5..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Annotated
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Annotated[str, Query(min_length=3)] = ...):
-    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
-    if q:
-        results.update({"q": q})
-    return results
index 2ac148c94f6234122d201bc2d6a7a227bf550574..0a0e820da34ca31378963e337169305d30cdfa38 100644 (file)
@@ -6,7 +6,7 @@ app = FastAPI()
 
 
 @app.get("/items/")
-async def read_items(q: Union[str, None] = Query(default=..., min_length=3)):
+async def read_items(q: Union[str, None] = Query(min_length=3)):
     results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
     if q:
         results.update({"q": q})
index 10bf26a577943629bb9614f87b1077e6410aac35..55c4f4adca66b628174bd7e260d5514c158b64bd 100644 (file)
@@ -7,7 +7,7 @@ app = FastAPI()
 
 
 @app.get("/items/")
-async def read_items(q: Annotated[Union[str, None], Query(min_length=3)] = ...):
+async def read_items(q: Annotated[Union[str, None], Query(min_length=3)]):
     results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
     if q:
         results.update({"q": q})
index 1ab0a7d53dbd274c0adbf40b95f284a444e4c686..2995d9c9798d677f8e2c3a78639f1921f7e41da0 100644 (file)
@@ -6,7 +6,7 @@ app = FastAPI()
 
 
 @app.get("/items/")
-async def read_items(q: Annotated[str | None, Query(min_length=3)] = ...):
+async def read_items(q: Annotated[str | None, Query(min_length=3)]):
     results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
     if q:
         results.update({"q": q})
index ac127333188dc60fb87e843258775f2216db37ec..76a1cd49ac9622349c3368eb153091c2ffa8daa2 100644 (file)
@@ -6,7 +6,7 @@ app = FastAPI()
 
 
 @app.get("/items/")
-async def read_items(q: Annotated[Union[str, None], Query(min_length=3)] = ...):
+async def read_items(q: Annotated[Union[str, None], Query(min_length=3)]):
     results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
     if q:
         results.update({"q": q})
index 82dd9e5d7c30c32945187068fe607b4ca295ce4f..88b499c7afc7c056dbfbad5c341d8b339bf973ee 100644 (file)
@@ -4,7 +4,7 @@ app = FastAPI()
 
 
 @app.get("/items/")
-async def read_items(q: str | None = Query(default=..., min_length=3)):
+async def read_items(q: str | None = Query(min_length=3)):
     results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
     if q:
         results.update({"q": q})
diff --git a/docs_src/query_params_str_validations/tutorial006d.py b/docs_src/query_params_str_validations/tutorial006d.py
deleted file mode 100644 (file)
index a8d69c8..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: str = Query(default=..., min_length=3)):
-    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
-    if q:
-        results.update({"q": q})
-    return results
diff --git a/docs_src/query_params_str_validations/tutorial006d_an.py b/docs_src/query_params_str_validations/tutorial006d_an.py
deleted file mode 100644 (file)
index ea3b025..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-from fastapi import FastAPI, Query
-from typing_extensions import Annotated
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Annotated[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_src/query_params_str_validations/tutorial006d_an_py39.py b/docs_src/query_params_str_validations/tutorial006d_an_py39.py
deleted file mode 100644 (file)
index 687a9f5..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Annotated
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Annotated[str, Query(min_length=3)] = ...):
-    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
-    if q:
-        results.update({"q": q})
-    return results