FastAPI Basics • Lesson 6

Path Parameters and Numeric Validations

Learn to add validation constraints to path parameters using Path(). Set numeric ranges, add documentation, and create robust path parameter validation.

🎯 What You'll Learn

  • Add validation constraints to path parameters
  • Use Path() for advanced path parameter configuration
  • Set numeric ranges for integer path parameters
  • Add parameter documentation and metadata
  • Combine Query and Path validations in the same endpoint

Path Parameters and Numeric Validations

🎯 What You'll Learn

Following the official FastAPI tutorial, you'll learn how to add validation constraints, metadata, and documentation to your path parameters using FastAPI's Path function.

By the end of this lesson, you'll understand how to:

  • Add validation constraints to path parameters
  • Use Path() for advanced path parameter configuration
  • Set numeric ranges for integer path parameters
  • Add parameter documentation and metadata
  • Combine Query and Path validations in the same endpoint

🛠️ The Path Function

Just like Query for query parameters, FastAPI provides the Path function to add metadata and validation constraints to path parameters.

Basic Path vs Advanced Path

Basic approach:

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

Advanced approach with Path:

from fastapi import Path

@app.get("/items/{item_id}")
def read_item(item_id: int = Path(ge=1)):
    return {"item_id": item_id}

🔢 Numeric Validation Constraints

Basic Numeric Constraints

from fastapi import FastAPI, Path

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: int = Path(ge=1)):
    return {"item_id": item_id}

Validation:

  • /items/1 ✅ Valid (ge=1 means >= 1)
  • /items/0 ❌ Invalid (less than 1)
  • /items/-5 ❌ Invalid (less than 1)

Multiple Constraints

@app.get("/items/{item_id}")
def read_item(
    item_id: int = Path(title="Item ID", description="The ID of the item", ge=1, le=1000)
):
    return {"item_id": item_id}

Available numeric constraints:

  • ge: Greater than or equal
  • gt: Greater than
  • le: Less than or equal
  • lt: Less than

💡 Official Tutorial Examples

Example 1: Basic Path Validation

From the official tutorial:

from fastapi import FastAPI, Path

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: int = Path(ge=1)):
    return {"item_id": item_id}

Example 2: Path with Metadata

@app.get("/items/{item_id}")
def read_item(
    item_id: int = Path(title="Item ID", description="The ID of the item to get", ge=0, le=1000)
):
    return {"item_id": item_id}

Example 3: Combining Path and Query Validations

@app.get("/items/{item_id}")
def read_item(
    item_id: int = Path(title="Item ID", description="The ID of the item to get", ge=0, le=1000),
    q: str | None = Query(default=None, alias="item-query")
):
    return {"item_id": item_id, "q": q}

🎨 Path Parameter Features

Validation Constraints

  • ge: Greater than or equal (≥)
  • gt: Greater than (>)
  • le: Less than or equal (≤)
  • lt: Less than (<)

Metadata and Documentation

  • title: Parameter title in docs
  • description: Parameter description
  • deprecated: Mark parameter as deprecated
  • include_in_schema: Include/exclude from OpenAPI schema
  • example: Example value for documentation

Example with Full Metadata

@app.get("/products/{product_id}")
def get_product(
    product_id: int = Path(
        title="Product ID",
        description="The unique identifier for the product",
        example=42,
        ge=1,
        le=999999
    )
):
    return {"product_id": product_id}

🔄 Order Matters: Path Before Query

When combining Path and Query parameters, you need to be careful about parameter order:

# ✅ Correct - Path parameter first
@app.get("/items/{item_id}")
def read_item(
    item_id: int = Path(ge=1),
    q: str | None = Query(default=None)
):
    return {"item_id": item_id, "q": q}

# ❌ Wrong - Query parameter before Path (syntax error)
@app.get("/items/{item_id}")
def read_item(
    q: str | None = Query(default=None),
    item_id: int = Path(ge=1)  # SyntaxError!
):
    return {"item_id": item_id, "q": q}

Solution: Use * to Separate

@app.get("/items/{item_id}")
def read_item(
    *,  # This allows any order after the *
    item_id: int = Path(ge=1),
    q: str | None = Query(default=None)
):
    return {"item_id": item_id, "q": q}

🌟 Advanced Path Validation

Float Path Parameters

@app.get("/prices/{price}")
def get_price_info(
    price: float = Path(gt=0.0, le=10000.0, description="Price in USD")
):
    return {"price": price, "currency": "USD"}

String Path Parameters with Validation

@app.get("/users/{username}")
def get_user(
    username: str = Path(
        min_length=3,
        max_length=20,
        regex="^[a-zA-Z0-9_]+$",
        description="Username (alphanumeric and underscore only)"
    )
):
    return {"username": username}

✨ Best Practices

1. Use Reasonable Constraints

# ✅ Good - realistic ID range
@app.get("/items/{item_id}")
def read_item(item_id: int = Path(ge=1, le=999999)):
    pass

# ❌ Avoid - unrealistic constraints
@app.get("/items/{item_id}")
def read_item(item_id: int = Path(ge=1000000, le=1000001)):
    pass

2. Add Helpful Documentation

# ✅ Good - clear documentation
@app.get("/products/{product_id}")
def get_product(
    product_id: int = Path(
        title="Product ID",
        description="The unique identifier for the product in our catalog",
        ge=1
    )
):
    pass

3. Use Appropriate Data Types

# ✅ Good - int for IDs
@app.get("/users/{user_id}")
def get_user(user_id: int = Path(ge=1)):
    pass

# ✅ Good - str for usernames
@app.get("/users/{username}")
def get_user(username: str = Path(min_length=3)):
    pass

🚫 Common Beginner Mistakes

Mistake 1: Wrong Parameter Order

# ❌ Wrong - Query before Path
@app.get("/items/{item_id}")
def read_item(q: str = Query(), item_id: int = Path()):  # SyntaxError
    pass

# ✅ Correct - Path first, or use *
@app.get("/items/{item_id}")
def read_item(*, item_id: int = Path(), q: str = Query()):
    pass

Mistake 2: Forgetting to Import Path

# ❌ Wrong - Path not imported
@app.get("/items/{item_id}")
def read_item(item_id: int = Path(ge=1)):  # NameError
    pass

# ✅ Correct - import Path
from fastapi import Path

Mistake 3: Unrealistic Constraints

# ❌ Wrong - impossible to satisfy
@app.get("/items/{item_id}")
def read_item(item_id: int = Path(ge=100, le=10)):  # ge > le!
    pass

# ✅ Correct - logical constraints
@app.get("/items/{item_id}")
def read_item(item_id: int = Path(ge=1, le=1000)):
    pass

🎉 What's Next?

Congratulations! You now understand how to add powerful validation and documentation to your path parameters. Combined with query parameter validation, you can create robust, well-documented APIs.

You've learned:

  • How to use Path() for advanced path parameter configuration
  • Adding numeric validation constraints (ge, le, gt, lt)
  • Including parameter documentation and metadata
  • Combining Path and Query validations in the same endpoint

Coming up next: Body - Multiple Parameters - learning how to handle multiple request body parameters and combine them with path and query parameters!

📖 Additional Resources

💡 Hint

Import Path from fastapi and use it like: item_id: int = Path(ge=1, le=1000). This adds validation constraints to your path parameters!

Ready to Practice?

Now that you understand the theory, let's put it into practice with hands-on coding!

Start Interactive Lesson