Resource URLs such as /users/42 are the backbone of REST APIs, and typed parameters make them safe to use.
Put a name in braces in the path and give the function a parameter with the same name: @app.get("/items/{item_id}") with def read_item(item_id: int). FastAPI extracts that URL segment, and the type hint decides what happens next:
- For
/items/42, the string"42"is converted, soitem_idis the int42. - For
/items/abc, conversion fails and the client gets a 422 response whose JSON body says which parameter was wrong and why. Your function never runs.
This is the central FastAPI idea: the type hint is documentation, parsing and validation in one. int, float, str, bool, UUID, date and datetime all work out of the box.
When only a fixed set of values is valid, use an Enum that also subclasses str. FastAPI validates against the members, the docs show a dropdown, and your function receives the enum member, so compare with Color.red or read .value.
Path parameters are always required: a URL either has the segment or it matches a different route. A segment can't contain /, unless you use the path converter, {file_path:path}, which matches the rest of the URL including slashes.
Two practical notes. First, route order: with /users/me and /users/{user_id}, declare /users/me first or me is captured as a user id. Second, Pydantic's default conversion is lenient where it's unambiguous ("007" becomes 7) but strict about losing information: "3.5" is rejected for an int rather than truncated.
Example
from enum import Enum
from fastapi import FastAPI
from fastapi.testclient import TestClient
class Color(str, Enum):
red = "red"
green = "green"
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id, "type": type(item_id).__name__}
@app.get("/colors/{color}")
def read_color(color: Color):
return {"color": color.value, "is_red": color is Color.red}
@app.get("/files/{file_path:path}")
def read_file(file_path: str):
return {"path": file_path}
c = TestClient(app)
print(c.get("/items/42").json()) # {'item_id': 42, 'type': 'int'}
print(c.get("/items/abc").status_code) # 422
print(c.get("/colors/blue").status_code) # 422: not an enum member
print(c.get("/files/docs/a.txt").json()) # {'path': 'docs/a.txt'}Remember
- {name} in the path + a parameter with the same name = path parameter
- The type hint converts the value; invalid input gets a 422 before your code runs
- Use a str Enum to restrict a parameter to fixed values
- {name:path} captures the rest of the URL including slashes
Watch out for
- Declaring /users/{user_id} before /users/me, so 'me' never reaches its own route.