mirror of
https://github.com/rjNemo/fastapi
synced 2026-06-12 13:36:41 +00:00
✨ Multi-value query parameters and duplicate headers (#95)
* 📝 Document multi-value query parameters * ✨ Document and test multiple query values * ✨ Document receiving duplicate headers
This commit is contained in:
parent
4f852878d6
commit
c64f8346ae
6 changed files with 179 additions and 0 deletions
BIN
docs/img/tutorial/query-params-str-validations/image02.png
Normal file
BIN
docs/img/tutorial/query-params-str-validations/image02.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
10
docs/src/header_params/tutorial003.py
Normal file
10
docs/src/header_params/tutorial003.py
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from fastapi import FastAPI, Header
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/items/")
|
||||||
|
async def read_items(x_token: List[str] = Header(None)):
|
||||||
|
return {"X-Token values": x_token}
|
||||||
11
docs/src/query_params_str_validations/tutorial011.py
Normal file
11
docs/src/query_params_str_validations/tutorial011.py
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from fastapi import FastAPI, Query
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/items/")
|
||||||
|
async def read_items(q: List[str] = Query(None)):
|
||||||
|
query_items = {"q": q}
|
||||||
|
return query_items
|
||||||
|
|
@ -47,6 +47,39 @@ If for some reason you need to disable automatic conversion of underscores to hy
|
||||||
!!! warning
|
!!! warning
|
||||||
Before setting `convert_underscores` to `False`, bear in mind that some HTTP proxies and servers disallow the usage of headers with underscores.
|
Before setting `convert_underscores` to `False`, bear in mind that some HTTP proxies and servers disallow the usage of headers with underscores.
|
||||||
|
|
||||||
|
|
||||||
|
## Duplicate headers
|
||||||
|
|
||||||
|
It is possible to receive duplicate headers. That means, the same header with multiple values.
|
||||||
|
|
||||||
|
You can define those cases using a list in the type declaration.
|
||||||
|
|
||||||
|
You will receive all the values from the duplicate header as a Python `list`.
|
||||||
|
|
||||||
|
For example, to declare a header of `X-Token` that can appear more than once, you can write:
|
||||||
|
|
||||||
|
```Python hl_lines="9"
|
||||||
|
{!./src/header_params/tutorial003.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you communicate with that *path operation* sending two HTTP headers like:
|
||||||
|
|
||||||
|
```
|
||||||
|
X-Token: foo
|
||||||
|
X-Token: bar
|
||||||
|
```
|
||||||
|
|
||||||
|
The response would be like:
|
||||||
|
|
||||||
|
```JSON
|
||||||
|
{
|
||||||
|
"X-Token values": [
|
||||||
|
"bar",
|
||||||
|
"foo"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Recap
|
## Recap
|
||||||
|
|
||||||
Declare headers with `Header`, using the same common pattern as `Query`, `Path` and `Cookie`.
|
Declare headers with `Header`, using the same common pattern as `Query`, `Path` and `Cookie`.
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,43 @@ So, when you need to declare a value as required while using `Query`, you can us
|
||||||
|
|
||||||
This will let **FastAPI** know that this parameter is required.
|
This will let **FastAPI** know that this parameter is required.
|
||||||
|
|
||||||
|
## 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 other way, to receive multiple values.
|
||||||
|
|
||||||
|
For example, to declare a query parameter `q` that can appear multiple times in the URL, you can write:
|
||||||
|
|
||||||
|
```Python hl_lines="9"
|
||||||
|
{!./src/query_params_str_validations/tutorial011.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, with a URL like:
|
||||||
|
|
||||||
|
```
|
||||||
|
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`.
|
||||||
|
|
||||||
|
So, the response to that URL would be:
|
||||||
|
|
||||||
|
```JSON
|
||||||
|
{
|
||||||
|
"q": [
|
||||||
|
"foo",
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
To declare a query parameter with a type of `list`, like in the example above, you need to explicitly use `Query`, otherwise it would be interpreted as a request body.
|
||||||
|
|
||||||
|
|
||||||
|
The interactive API docs will update accordingly, to allow multiple values:
|
||||||
|
|
||||||
|
<img src="/img/tutorial/query-params-str-validations/image02.png">
|
||||||
|
|
||||||
## Declare more metadata
|
## Declare more metadata
|
||||||
|
|
||||||
You can add more information about the parameter.
|
You can add more information about the parameter.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
from starlette.testclient import TestClient
|
||||||
|
|
||||||
|
from query_params_str_validations.tutorial011 import app
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
openapi_schema = {
|
||||||
|
"openapi": "3.0.2",
|
||||||
|
"info": {"title": "Fast API", "version": "0.1.0"},
|
||||||
|
"paths": {
|
||||||
|
"/items/": {
|
||||||
|
"get": {
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful Response",
|
||||||
|
"content": {"application/json": {"schema": {}}},
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"description": "Validation Error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"summary": "Read Items Get",
|
||||||
|
"operationId": "read_items_items__get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"required": False,
|
||||||
|
"schema": {
|
||||||
|
"title": "Q",
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "string"},
|
||||||
|
},
|
||||||
|
"name": "q",
|
||||||
|
"in": "query",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"ValidationError": {
|
||||||
|
"title": "ValidationError",
|
||||||
|
"required": ["loc", "msg", "type"],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"loc": {
|
||||||
|
"title": "Location",
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "string"},
|
||||||
|
},
|
||||||
|
"msg": {"title": "Message", "type": "string"},
|
||||||
|
"type": {"title": "Error Type", "type": "string"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"HTTPValidationError": {
|
||||||
|
"title": "HTTPValidationError",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"detail": {
|
||||||
|
"title": "Detail",
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/components/schemas/ValidationError"},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_openapi_schema():
|
||||||
|
response = client.get("/openapi.json")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == openapi_schema
|
||||||
|
|
||||||
|
|
||||||
|
def test_multi_query_values():
|
||||||
|
url = "/items/?q=foo&q=bar"
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == {"q": ["foo", "bar"]}
|
||||||
Loading…
Reference in a new issue