Path Parameters
Path parameters allow you to capture dynamic segments of a URL and use them as arguments in your path operation functions. FastAPI uses Python type hints to automatically parse, validate, and document these parameters.
In this tutorial, you will build an API that manages items and users, using path parameters to identify specific resources and applying constraints to ensure data integrity.
Prerequisites
To follow this tutorial, you need FastAPI installed. You will also use Annotated from the typing module (or typing_extensions for older Python versions) to declare your parameters.
Step 1: Define Basic Path Parameters
You can declare path "parameters" or "variables" with the same syntax used by Python formatted strings. Use curly braces {} in the path of your decorator.
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
In this example, the value of the path parameter item_id will be passed to your function as the argument item_id. If you run this and go to /items/3, you will see:
{"item_id": 3}
FastAPI uses the int type hint to convert the string from the URL into a Python integer. If you visit /items/foo, FastAPI will return an error because "foo" is not an integer.
Step 2: Add Metadata and Validation with Path
To add more information or validation to your path parameters, use the Path class from fastapi.params (usually imported from fastapi). The recommended way to do this is using Annotated.
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", description="The unique identifier for the item")],
):
return {"item_id": item_id}
The Path function creates an instance of fastapi.params.Path which inherits from fastapi.params.Param. This metadata is used by FastAPI to generate the OpenAPI schema and is visible in the interactive documentation at /docs.
Step 3: Apply Numeric Validations
You can enforce numeric constraints using parameters like ge (greater than or equal), gt (greater than), le (less than or equal), and lt (less than).
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, le=1000)],
):
return {"item_id": item_id}
In this code:
ge=1ensures theitem_idis at least 1.le=1000ensures theitem_idis no more than 1000.
If a user requests /items/0 or /items/1001, FastAPI will return a 422 Unprocessable Entity error.
Step 4: Apply String Validations
If your path parameter is a string, you can use min_length, max_length, and pattern (which replaces the deprecated regex parameter).
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/users/{username}")
async def read_user(
username: Annotated[str, Path(min_length=3, max_length=15, pattern="^[a-z0-9_-]+$")],
):
return {"username": username}
The pattern parameter ensures the username only contains lowercase letters, numbers, underscores, or hyphens.
Step 5: Capture Paths with Slashes
By default, path parameters do not match segments containing forward slashes /. If you need to capture a sub-path (like a file path), use the :path converter provided by the underlying Starlette integration.
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/files/{file_path:path}")
async def read_file(file_path: str = Path()):
return {"file_path": file_path}
If you visit /files/images/profile.png, the file_path variable will contain the string "images/profile.png".
Important Constraints
When using Path, keep the following rules in mind:
- Path parameters are always required: Unlike query parameters, path parameters cannot be optional because they are part of the URL structure.
- No default values: Because they are required, you cannot provide a default value to the
Path()function. Thefastapi.params.Pathclass explicitly asserts that the default value must be...(Ellipsis).# This will raise an AssertionError in FastAPI
# item_id: int = Path(default=10) - Ordering: If you use the traditional default value syntax (e.g.,
item_id: int = Path(...)) instead ofAnnotated, and you have other parameters without defaults after it, Python will complain. You can solve this by using*as the first argument of your function to force keyword arguments.
Complete Example
Here is a complete working example combining these concepts:
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, description="Must be a positive integer")
],
q: str | None = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
By following these steps, you have created a robust API endpoint that validates its input and provides clear documentation for its consumers. Next, you might want to explore Query Parameters to handle optional filters and search criteria.