Difficulty: Beginner
Path parameters are dynamic segments of a URL that capture values from the request path. In FastAPI, you define them using curly braces in the path string and matching function parameters. For example, @app.get("/users/{user_id}") captures the value at that position in the URL and passes it to the handler function as user_id.
FastAPI automatically converts path parameter values to the type specified in the function signature. If you declare user_id: int, FastAPI will convert the string from the URL to an integer. If the conversion fails (for example, the client sends /users/abc when int is expected), FastAPI automatically returns a 422 Unprocessable Entity error with a clear error message. This automatic type conversion and validation is one of FastAPI's most useful features.
You can have multiple path parameters in a single route. For example, @app.get("/users/{user_id}/posts/{post_id}") captures both user_id and post_id. Each parameter in the path must have a corresponding function parameter with the same name.
Route order matters in FastAPI. Routes are matched in the order they are defined. If you have both @app.get("/users/me") and @app.get("/users/{user_id}"), the /users/me route must be defined first. Otherwise, /users/me would match the {user_id} parameter, with 'me' as the value. FastAPI processes routes top-to-bottom and uses the first match.
For more complex path parameter validation, you can use FastAPI's Path function. It allows you to add constraints like minimum/maximum values for integers, minimum/maximum lengths for strings, and regex patterns. For example, Path(ge=1) ensures the parameter is greater than or equal to 1.
FastAPI also supports path parameters that contain forward slashes using the special :path converter. Normally, a path parameter captures only a single path segment (between slashes). But with {file_path:path}, you can capture the entire remaining path, including slashes. This is useful for file paths or nested resource identifiers.
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id}
@app.get("/posts/{post_slug}")
def get_post(post_slug: str):
return {"slug": post_slug}
# GET /users/42 -> {"user_id": 42}
# GET /users/abc -> 422 Error (not a valid int)
# GET /posts/hello-world -> {"slug": "hello-world"}
The type hint determines how FastAPI converts the path segment. int expects a number, str accepts any string. Invalid types trigger automatic 422 validation errors.
from fastapi import FastAPI
app = FastAPI()
# Fixed path MUST come before parameterized path
@app.get("/users/me")
def get_current_user():
return {"user": "current authenticated user"}
@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id}
# GET /users/me -> {"user": "current authenticated user"}
# GET /users/42 -> {"user_id": 42}
# If the order were reversed, /users/me would try to
# parse 'me' as an int and return a 422 error!
FastAPI matches routes in order of definition. Fixed paths like /users/me must be declared before parameterized paths like /users/{user_id} to avoid the parameter capturing the literal string 'me'.
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
def get_item(
item_id: int = Path(
title="The ID of the item",
description="Must be a positive integer",
ge=1, # greater than or equal to 1
le=10000, # less than or equal to 10000
)
):
return {"item_id": item_id}
# GET /items/0 -> 422 Error (must be >= 1)
# GET /items/5 -> {"item_id": 5}
# GET /items/99999 -> 422 Error (must be <= 10000)
@app.get("/files/{file_path:path}")
def get_file(file_path: str):
"""Captures paths with slashes"""
return {"path": file_path}
# GET /files/home/user/doc.txt -> {"path": "home/user/doc.txt"}
Path() adds metadata and validation constraints to path parameters. The :path converter allows capturing path segments that contain forward slashes, useful for file paths.
Path Parameters, Type Conversion, Path Validation, Multiple Params, Order Matters