Path Parameters and Numeric Validations
In the same way that you can declare more validations and metadata for query parameters with Query, you can declare the same type of validations and metadata for path parameters with Path.
Import Path
Section titled “Import Path”First, import Path from fastapi, and import Annotated:
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[str | None, Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return resultsDeclare metadata
Section titled “Declare metadata”You can declare all the same parameters as for Query.
For example, to declare a title metadata value for the path parameter item_id you can type:
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[str | None, Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return resultsOrder the parameters as you need
Section titled “Order the parameters as you need”Let's say that you want to declare the query parameter q as a required str.
And you don't need to declare anything else for that parameter, so you don't really need to use Query.
But you still need to use Path for the item_id path parameter. And you don't want to use Annotated for some reason.
Python will complain if you put a value with a "default" before a value that doesn't have a "default".
But you can re-order them, and have the value without a default (the query parameter q) first.
It doesn't matter for FastAPI. It will detect the parameters by their names, types and default declarations (Query, Path, etc), it doesn't care about the order.
So, you can declare your function as:
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return resultsBut keep in mind that if you use Annotated, you won't have this problem, it won't matter as you're not using the function parameter default values for Query() or Path().
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return resultsOrder the parameters as you need, tricks
Section titled “Order the parameters as you need, tricks”Here's a small trick that can be handy, but you won't need it often.
If you want to:
- declare the
qquery parameter without aQuerynor any default value - declare the path parameter
item_idusingPath - have them in a different order
- not use
Annotated
...Python has a little special syntax for that.
Pass *, as the first parameter of the function.
Python won't do anything with that *, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as kwargsFrom: K-ey W-ord Arg-uments. Even if they don't have a default value.
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return resultsBetter with Annotated
Section titled “Better with Annotated”Keep in mind that if you use Annotated, as you are not using function parameter default values, you won't have this problem, and you probably won't need to use *.
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return resultsNumber validations: greater than or equal
Section titled “Number validations: greater than or equal”With Query and Path (and others you'll see later) you can declare number constraints.
Here, with ge=1, item_id will need to be an integer number "greater than or equal" to 1.
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return resultsNumber validations: greater than and less than or equal
Section titled “Number validations: greater than and less than or equal”The same applies for:
gt:greaterthanle:less than orequal
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)],
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return resultsNumber validations: floats, greater than and less than
Section titled “Number validations: floats, greater than and less than”Number validations also work for float values.
Here's where it becomes important to be able to declare gtgreater than and not just gegreater than or equal. As with it you can require, for example, that a value must be greater than 0, even if it is less than 1.
So, 0.5 would be a valid value. But 0.0 or 0 would not.
And the same for ltless than.
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
q: str,
size: Annotated[float, Query(gt=0, lt=10.5)],
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if size:
results.update({"size": size})
return resultsWith Query, Path (and others you haven't seen yet) you can declare metadata and string validations in the same ways as with Query Parameters and String Validations.
And you can also declare numeric validations:
gt:greaterthange:greater than orequallt:lessthanle:less than orequal