Fastapi Query Params Validation
FastAPI allows you to declare additional validation rules and metadata for query parameters, such as string length limits, regex matching, etc. Through `Query` and `Annotated`, you can enhance parameter validation without changing function logic.
* * *
## Basic Validation
The following example adds a maximum length limit for the query parameter `q`:
## Example
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# Use Annotated + Query to add validation
q: Annotated[str | None, Query(max_length=50)]=None,
):
results ={"items": [{"item_id": "Foo"},{"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
Code explanation:
| Part | Description |
| --- | --- |
| `Annotated[str | None, ...]` | Type annotation indicating `q` can be string or None |
| `Query(max_length=50)` | Validation rule, `q` has maximum length of 50 characters |
| `= None` | Default value, making the parameter optional |
> FastAPI recommends using the `Annotated` approach to declare validation, rather than using `Query` as a default value. With the `Annotated` approach, the function's default value is the actual default value, which is more intuitive in Python and has better support from editors and type checking tools.
* * *
## Adding More Validation
You can add multiple validation rules simultaneously:
## Example
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# Limit minimum length, maximum length, and regex pattern simultaneously
q: Annotated[str | None, Query(min_length=3, max_length=50, pattern="^fixedquery$")]=None,
):
results ={"items": [{"item_id": "Foo"},{"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
String validation parameters:
| Parameter | Type | Description |
| --- | --- | --- |
| `min_length` | `int` | Minimum length |
| `max_length` | `int` | Maximum length |
| `pattern` | `str` | Regex pattern matching |
Meaning of regex pattern `^fixedquery$`:
* `^` -- Must start with the following characters
* `fixedquery` -- Value must exactly equal `fixedquery`
* `$` -- End here, no other characters allowed after
* * *
## Validation with Default Values
You can set both default values and validation rules for query parameters:
## Example
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# Default value is "fixedquery", with minimum length requirement of 3
q: Annotated[str, Query(min_length=3)]="fixedquery",
):
results ={"items": [{"item_id": "Foo"},{"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
> Any type of default value (including non-`None` values) makes the parameter optional. Parameters without default values and without `Query(default=...)` are required.
* * *
## Required Parameters
When using `Query`, if no default value is declared, the parameter is required:
## Example
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# No = None, so q is a required parameter
q: Annotated[str, Query(min_length=3)],
):
results ={"items": [{"item_id": "Foo"},{"item_id": "Bar"}]}
results.update({"q": q})
return results
### Required but Can Be None
Sometimes you need the client to provide a value, but the value can be `None`:
## Example
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# Client must provide q parameter, but value can be None
q: Annotated[str | None, Query(min_length=3)],
):
results ={"items": [{"item_id": "Foo"},{"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
* * *
## Query Parameter Lists / Multiple Values
Using `Query` you can declare receiving multiple values for a query parameter:
## Example
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# q can appear multiple times in URL, values will be collected as list
q: Annotated[list | None, Query()]=None,
):
query_items ={"q": q}
return query_items
Access **http://127.0.0.1:8000/items/?q=foo&q=bar**, returns:
{"q": ["foo", "bar"]}
> To declare a query parameter of type `list`, you must explicitly use `Query()`, otherwise FastAPI will interpret it as a request body.
* * *
## Declaring Metadata
`Query` also supports adding metadata to parameters, which will appear in API documentation:
## Example
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Annotated[str | None, Query(
title="Query string",# Parameter title
description="Query string for filtering items",# Parameter description
min_length=3,
max_length=50,
alias="item-query",# Parameter name alias in URL
deprecated=True,# Mark as deprecated
)]=None,
):
results ={"items": [{"item_id": "Foo"},{"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
Metadata parameter description:
| Parameter | Description | Use Case |
| --- | --- | --- |
| `alias` | Parameter name alias in URL | When parameter name contains hyphens (like `item-query`), which is not a valid Python variable name |
| `title` | Parameter title | Display parameter title in documentation |
| `description` | Parameter description | Display detailed parameter description in documentation |
| `deprecated` | Mark as deprecated | Parameter can still be used, but will be marked as "deprecated" in documentation |
| `include_in_schema` | Whether to appear in API documentation | Set to `False` to hide parameter |
* * *
## Excluding Parameters from OpenAPI
If a query parameter should not appear in API documentation:
## Example
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# hidden_query won't appear in API documentation, but can still be used
hidden_query: Annotated[str | None, Query(include_in_schema=False)]=None,
):
if hidden_query:
return{"hidden_query": hidden_query}
return{"items": [{"item_id": "Foo"}]}
* * *
## Summary
Key points of query parameter validation:
* Use `Annotated` + `Query` to declare validation rules (recommended approach)
* String validation: `min_length`, `max_length`, `pattern`
* No default value = required parameter, has default value = optional parameter
* `alias` for parameter names in URL that are not valid Python variable names
* `deprecated=True` to mark obsolete parameters
* Use `list` to receive multiple query parameters with the same name
YouTip