In our last lesson, we built our very first endpoints and even peeked at the auto-generated docs. We saw a static path "/".
Practice Lab:
Path parameters are the dynamic parts of your URL. Picture a blog website. The URL /blog/23 should fetch the blog with id 23, and /blog/45 should fetch a different one. The number keeps changing, but the structure stays the same. That changing piece is our path parameter.
from fastapi import FastAPIapp = FastAPI()@app.get("/blog/{blog_id}")async def read_blog(blog_id): return {"blog_id": blog_id}Let's review this:
The
{blog_id}inside the path is our path parameter. The curly braces tell FastAPI that this part is dynamic.The same name
blog_idis received as an argument in our function.Whatever value we put in the URL, FastAPI hands it over to our function.
Hit http://127.0.0.1:8000/blog/23 and you get back {"blog_id":"23"}.
Did you notice something fishy? The 23 came back as a string "23", not a number. This is exactly where our type hints come into play (remember the very first article on type hints? š¤).
Adding a type hint
@app.get("/blog/{blog_id}")async def read_blog(blog_id: int): return {"blog_id": blog_id}Now FastAPI does two favors for us:
It converts the value to an integer. So
/blog/23returns{"blog_id": 23}(notice the quotes are gone now).It validates the value. If someone hits
/blog/abc, FastAPI does not crash. It politely returns a clean error saying the value is not a valid integer.
So with a single : int, we got parsing and validation for free. Not bad.
More validations with Path
Let's get greedy. We know that no blog has an id of 0 or a negative number. So we want to enforce that blog_id is always positive. FastAPI gives us Path for exactly this.
from typing import Annotatedfrom fastapi import FastAPI, Pathapp = FastAPI()@app.get("/blog/{blog_id}")async def read_blog( blog_id: Annotated[int, Path(title="The ID of the blog to fetch", gt=0)],): return {"blog_id": blog_id}Let's review:
Annotatedlets us attach extra information to our type. The type is stillint, we are just bolting on more details.Path(...)carries the metadata and the validation rules.titleis a short description that shows up in our auto-generated docs (the ones we saw in the last article).gt=0means greater than 0. Now if someone hits/blog/0or/blog/-5, they get a validation error instead of a wrong result.
The numeric validation rules you will use the most:
gt- greater thange- greater than or equallt- less thanle- less than or equal
So if our blog ids live between 1 and 1000, we can write Path(gt=0, le=1000) and FastAPI guards both ends for us.
A quick note on ordering
Python complains if you put an argument with a default before one without a default. You might hit this when mixing path and query parameters. The good news is that with Annotated, this problem disappears. FastAPI figures out parameters by their name and type, not their position, so you can order them however you like.
Gotcha: A path parameter is always required. It is literally a part of the URL, so even if you set a default value or None, FastAPI will still demand it. There is no such thing as an optional path parameter. š
ā ļø Do not confuse path parameters with query parameters. Path parameters are baked into the path itself (/blog/23). Query parameters come after the ? (/blog?limit=10). They look similar in code but they are different beasts, and we will cover query parameters in the next article.
