KAHIBARO
Discord Login Register

8.3. Path Parameters

Why Path Parameters Matter

In a web API, URLs are more than just addresses. They also carry information.
For example:

The changing parts like 1, 12345, 2024 are path parameters.
In FastAPI, path parameters let you define dynamic routes where part of the URL is a variable.

Without path parameters, you would need a different route for every user or product, which is impossible.

Path parameters = parts of the URL path that act as variables and are required for the route to match.

Basic Path Parameters in FastAPI

Defining a simple path parameter

Start with a minimal FastAPI app:

python
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int):
    return {"item_id": item_id}

Explanation:

json
{"item_id": 10}

If you try /items/abc, FastAPI returns a 422 Unprocessable Entity error, because abc is not an integer.

FastAPI uses Python type hints on path parameters for automatic validation and conversion.

Path parameter vs query parameter

To see the difference:

python
@app.get("/users/{user_id}")
def read_user(user_id: int, details: bool = False):
    return {"user_id": user_id, "details": details}

Examples:

Path parameters are part of the path and are required.
Query parameters are after ? and are usually optional.

Multiple and Typed Path Parameters

Multiple path parameters

You can have more than one path parameter:

python
@app.get("/users/{user_id}/orders/{order_id}")
def read_user_order(user_id: int, order_id: int):
    return {"user_id": user_id, "order_id": order_id}

Request: /users/3/orders/99
Response:

json
{"user_id": 3, "order_id": 99}

Different types for path parameters

You can use any type that FastAPI can handle. Common ones:

TypeExample URLPython value
str/items/book"book"
int/items/1010
float/prices/9.999.99
bool/feature/trueTrue
UUID/files/uuid-hereUUID object
date/reports/2024-08-27date object

Example with different types:

python
from datetime import date
from uuid import UUID
@app.get("/reports/{report_date}")
def read_report(report_date: date):
    return {"report_date": report_date}
@app.get("/files/{file_id}")
def read_file(file_id: UUID):
    return {"file_id": file_id}

Requests:

Path Order and Routing Rules

Static vs dynamic paths

FastAPI decides which function to call based on the path patterns.

Consider:

python
@app.get("/users/me")
def read_current_user():
    return {"user": "current user"}
@app.get("/users/{user_id}")
def read_user(user_id: int):
    return {"user_id": user_id}

Requests:

Important detail: static paths are matched before dynamic paths.
So /users/me is not captured by /users/{user_id}.

If you only had:

python
@app.get("/users/{user_id}")
def read_user(user_id: str):
    return {"user_id": user_id}

Then /users/me would match this route, with user_id = "me".

Path parameter name and function argument name

The name inside {} must match exactly the function parameter name.

Correct:

python
@app.get("/items/{item_id}")
def read_item(item_id: int):
    return {"item_id": item_id}

Incorrect:

python
@app.get("/items/{item_id}")
def read_item(id: int):  # Does NOT match
    return {"id": id}

FastAPI will raise an error at startup, because it cannot find a function parameter named item_id.

Path parameter name in the URL and function parameter name must be identical.

Path Converters and Validation

Path parameter types using colon syntax

FastAPI builds on Starlette and supports type conversion inside the path string:

python
@app.get("/items/{item_id}")
def read_item(item_id: int):
    return {"item_id": item_id}

You usually rely on the function type hint item_id: int.
There is also a Starlette-style path converter syntax, but in FastAPI you almost always use Python types only.

Keep to:

python
@app.get("/items/{item_id}")
def read_item(item_id: int): ...

rather than Django-style path("items/<int:item_id>/"). FastAPI does not use that pattern.

Validating path parameters with Path()

You can add extra constraints with Path:

python
from fastapi import Path
@app.get("/items/{item_id}")
def read_item(
    item_id: int = Path(
        ..., ge=1, le=1000, description="The ID must be between 1 and 1000"
    )
):
    return {"item_id": item_id}

Examples:

Common numeric constraints:

ArgumentMeaning
gtgreater than
gegreater than or equal
ltless than
leless than or equal

You can also enforce a minimum or maximum length on string parameters:

python
@app.get("/users/{username}")
def read_user(
    username: str = Path(..., min_length=3, max_length=20, regex="^[a-zA-Z0-9_]+$")
):
    return {"username": username}

Here:

Request /users/ab will fail with a 422 error, because it is too short.

Documenting path parameters

Path also lets you add descriptions, titles, and examples that show up in the OpenAPI docs:

python
@app.get("/products/{product_id}")
def read_product(
    product_id: int = Path(
        ...,
        title="Product ID",
        description="The numeric ID of the product to retrieve",
        example=123,
    )
):
    return {"product_id": product_id}

When you visit /docs, you will see this extra information for the product_id parameter.

Special Path Segment: `path` Type

Sometimes you want a path parameter that includes slashes, such as a file path:

Normal path parameters stop at the next /. To include slashes inside a parameter, use the special path converter:

python
@app.get("/files/{file_path:path}")
def read_file(file_path: str):
    return {"file_path": file_path}

Requests:

Without :path, FastAPI would try to match different segments separately and would not treat the whole rest as one variable.

Use {name:path} when the parameter must capture multiple segments with slashes.

Practical Design Examples with Path Parameters

Example 1: Basic blog URLs

Imagine a simple blog API:

python
@app.get("/posts/{post_id}")
def get_post(post_id: int):
    return {"post_id": post_id}
@app.get("/users/{user_id}/posts")
def list_user_posts(user_id: int):
    return {"user_id": user_id, "posts": []}
@app.get("/users/{user_id}/posts/{post_id}")
def get_user_post(user_id: int, post_id: int):
    return {"user_id": user_id, "post_id": post_id}

Paths:

Example 2: Products with category and product code

python
@app.get("/categories/{category_name}/products/{product_code}")
def get_category_product(category_name: str, product_code: str):
    return {
        "category": category_name,
        "product_code": product_code,
    }

Requests:

Example 3: Date-based resources

Using date conversion:

python
from datetime import date
@app.get("/reports/{year}/{month}/{day}")
def daily_report(year: int, month: int, day: int):
    return {"date": f"{year:04d}-{month:02d}-{day:02d}"}
@app.get("/reports/{report_date}")
def daily_report_date(report_date: date):
    return {"date": report_date}

Two styles:

Common Pitfalls and Tips

Pitfall 1: Wrong parameter name

Wrong:

python
@app.get("/orders/{order_id}")
def get_order(id: int):
    return {"id": id}

FastAPI error at startup, because {order_id} has no matching function parameter.

Fix:

python
@app.get("/orders/{order_id}")
def get_order(order_id: int):
    return {"order_id": order_id}

Pitfall 2: Conflicting routes

Example:

python
@app.get("/items/{item_id}")
def get_item(item_id: int): ...
@app.get("/items/special")
def get_special_item(): ...

This works, because /items/special is static and will be matched before /items/{item_id}.

But if you reverse them, it still works, because FastAPI still gives priority to the more specific path pattern. The important point is to avoid ambiguous patterns, such as:

python
@app.get("/files/{name}")
def get_file(name: str): ...
@app.get("/files/{file_path:path}")
def get_file_path(file_path: str): ...

Here, /files/a/b clearly matches the path version, but /files/test is ambiguous conceptually. FastAPI will still pick one, but this can be confusing. Avoid overlapping patterns when possible.

Pitfall 3: Using path parameters where query parameters are better

If a value is optional or more like a filter, use a query parameter, not a path parameter.

Better:

Not recommended:

Tip: Combine validation and documentation

Use Path to combine validation and docs in a clear way:

python
from fastapi import Path
@app.get("/orders/{order_id}")
def get_order(
    order_id: int = Path(
        ...,
        ge=1,
        description="Positive integer ID of the order",
        example=42,
    )
):
    return {"order_id": order_id}

Summary

These basics of path parameters are essential for building clear and predictable FastAPI APIs.

Views: 8

Comments

Please login to add a comment.

Don't have an account? Register now!