In the last article, we used Query to add rules to query parameters. Path works exactly the same way, but for path parameters. Same idea, different target.
Let's bring in Path the same way we brought in Query.
from typing import Annotated, Optionalfrom fastapi import FastAPI, Path, Queryapp = FastAPI()@app.get("/blog/{blog_id}")async def get_blog( blog_id: Annotated[int, Path(title="The ID of the blog to fetch")], q: Annotated[Optional[str], Query(max_length=50)] = None,): return {"blog_id": blog_id, "q": q}Let's review:
Path(title=...)adds a title that shows up in the auto-generated docs. Sametitleyou've seen withQuery.blog_idis still typed asint, so/blog/abcwill fail automatically.One thing that does not change: path parameters are always required. You cannot give them a default. They are in the URL, so they must be there.
Numeric validations
Here is where Path gets interesting. You can add number constraints directly on the parameter.
@app.get("/blog/{blog_id}")async def get_blog( blog_id: Annotated[int, Path(title="Blog ID", ge=1)],): return {"blog_id": blog_id}ge=1 means "greater than or equal to 1". Hit /blog/0 and FastAPI will reject it before your function even runs.
The full set of options:
gt- greater thange- greater than or equallt- less thanle- less than or equal
You can combine them to set a range:
python
blog_id: Annotated[int, Path(ge=1, le=9999)]Works on float too. gt=0.0 means the value must be positive but can be a decimal like 0.5. ge=0.0 would also allow 0 itself.
Path parameters cannot be made optional, even if you try. Declaring blog_id: Optional[int] = None with Path(...) will not make it optional. FastAPI ignores the default for path parameters. If it is in the URL pattern, it is required, full stop.
⚠️ Coming up: We've been validating individual parameters one by one. What if you have a bunch of query parameters that belong together? Next up: Query Parameter Models.
