Path Parameters and Validation
In FastAPI, path parameters are variables defined within the URL path of a route. While FastAPI automatically extracts these parameters based on the path template (e.g., /items/{item_id}), the Path class and its corresponding factory function allow you to add validation constraints and metadata to these parameters.
The Path Class and Factory
The Path implementation consists of two main parts in the fastapi.params and fastapi.param_functions modules:
fastapi.params.Path: A class that inherits fromParam(which itself inherits from Pydantic'sFieldInfo). It explicitly sets its location toParamTypes.path.fastapi.param_functions.Path: A factory function that returns an instance of thePathclass. This is the primary interface used by developers.
Mandatory Requirement
Unlike query parameters or body fields, path parameters are part of the URL structure and are therefore always required. The Path class enforces this in its constructor:
# fastapi/params.py
class Path(Param):
in_ = ParamTypes.path
def __init__(
self,
default: Any = ...,
# ... other arguments
):
assert default is ..., "Path parameters cannot have a default value"
super().__init__(
default=default,
# ...
)
The use of ... (Ellipsis) as the default value signifies to FastAPI and Pydantic that the field is required.
Validation Constraints
The Path class supports several validation parameters inherited from Param. These constraints are applied during the request parsing phase.
Numeric Validations
For parameters typed as int or float, you can use numeric constraints:
gt: Greater thange: Greater than or equal tolt: Less thanle: Less than or equal to
Example from docs_src/path_params_numeric_validations/tutorial004_an_py310.py:
@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,
):
return {"item_id": item_id, "q": q}
String Validations
For parameters typed as str, you can constrain the length or format:
min_lengthandmax_length: Define the size limits of the string.pattern: A regular expression that the string must match (replaces the deprecatedregexparameter).
Example from tests/main.py:
@app.get("/path/param-min_maxlength/{item_id}")
def get_path_param_min_max_length(item_id: str = Path(max_length=3, min_length=2)):
return item_id
Metadata and Documentation
The Path class allows you to provide additional information that is used to generate the OpenAPI schema (available at /docs).
title: A short name for the parameter.description: A detailed explanation of what the parameter represents.examples: A list of example values to show in the documentation.deprecated: A boolean or string indicating the parameter is no longer recommended for use.
These fields do not affect validation but are critical for API discoverability and client generation.
Usage Patterns
There are two primary ways to apply Path validation in your route handlers.
Using Annotated (Recommended)
The modern approach uses Python's Annotated type. This keeps the function signature clean and separates the type hint from the validation logic.
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/users/{user_id}")
async def get_user(user_id: Annotated[int, Path(gt=0, description="The unique ID of the user")]):
return {"user_id": user_id}
Using Default Values
In older versions of FastAPI or specific use cases, you can set the default value of the parameter to the result of the Path() function.
@app.get("/users/{user_id}")
async def get_user(user_id: int = Path(..., gt=0)):
return {"user_id": user_id}
Note that when using this pattern, the first argument to Path() must be ... to indicate the parameter is required, as path parameters cannot have actual default values.
Implementation Details
The Param base class in fastapi/params.py handles the consolidation of these validation arguments. It maps parameters like regex to pattern for Pydantic v2 compatibility and manages the json_schema_extra dictionary for custom OpenAPI extensions.
# fastapi/params.py
class Param(FieldInfo):
def __init__(
self,
default: Any = Undefined,
# ...
pattern: str | None = None,
regex: str | None = None,
# ...
):
# ...
if regex is not None:
warnings.warn(
"`regex` has been deprecated, please use `pattern` instead",
category=FastAPIDeprecationWarning,
stacklevel=4,
)
# ...
kwargs["pattern"] = pattern or regex
super().__init__(**use_kwargs)
This inheritance structure ensures that Path parameters behave consistently with other parameter types (like Query or Header) while maintaining the specific constraints required for URL path segments.