Page cover image

🍎Unit 10: Path Parameters and Validations

Introduction

The Annotated type, introduced in Python 3.9 from the typing module, allows for extending type hints with Python objects, which can be particularly useful for providing extra metadata or validation in FastAPI.

With the Annotated type, you can add metadata to your path parameters, making your API self-documenting and enabling automatic request validation. This is particularly useful for enhancing the functionality of path parameters with validations or constraints directly in your FastAPI endpoints.


Path Parameters

Let's take a quick look of using query parameter in FastAPI:

from fastapi import FastAPI, Query, Path
from typing import Annotated

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(
    item_id: Annotated[int, Path(title="The ID of the item to get")],
    q: Annotated[str | None, Query(alias="item-query")] = None,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

In the above program, the title is a metadata of the item_id path parameter. And you should note that the query parameter q is defined by an alias item-query, it thus makes the URL to this API endpoint is as follows:

http://127.0.0.1:8000/items/111?item-query=Sample

Order the parameters

Considering the following error program that produces an error message Non-default argument follows default argument since Python does not allow you to put a value with a default value before a value that doesn't have one.

// NOTE: THIS ERROR PROGRAM IS USED FOR DEMONSTRATION

from fastapi import FastAPI, Query, Path
from typing import Annotated

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(
    item_id: int = None,
    ,
):
    results = {"item_id": item_id}
    print(q)
    if q:
        results.update({"q": q})
    return results

To overcome this issue, you can re-order them, and have the value without a default value (the query parameter q) first. But it doesn't matter for FastAPI. It will detect the parameters by their names, types and default declarations (Query, Path, etc), since it doesn't care about the order.

Number validations with Annotated

Let's take a look in the below program:

from fastapi import FastAPI, Query, Path
from typing import Annotated

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(
    item_id: Annotated[int, Path(title="The ID of the item to get", )],
    q: Annotated[str | None, Query(alias="item-query")],
):
    results = {"item_id": item_id}
    print(q)
    if q:
        results.update({"q": q})
    return results

Program explanation:

  • item_id: This is a path parameter. It's expected to be an integer (int) between 1 and 1000 (inclusive). The Path function provides extra information and validation for this parameter.

  • q: This is a query parameter. It's expected to be a string (str) or None. The Query function provides an alias for this parameter, so in the URL it will be item-query instead of q.

The explanation is generated by KamiMind.ai

You can declare numeric validations by using following syntaxes:

  • gt: greater than

  • ge: greater than or equal

  • lt: less than

  • le: less than or equal

Let's take a look at another example:

from fastapi import FastAPI, Path, Query
from typing import Annotated

app = FastAPI()

@app.get("/items/{item_id}")
async def read_items(
    *,
    item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
    q: str,
    size: Annotated[float, Query(gt=0, lt=10.5)],
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

You should note that:

  • Number validations also work for float values.

  • gt is more strictly than ge. So, 0.5 would be a valid value, but 0.0 or 0 would not.


Summary

Using Annotated with FastAPI allows for sophisticated validation and metadata enhancements directly in the function signatures of your API endpoints. This can significantly improve the robustness, readability, and documentation of your API by leveraging Python's type hints and FastAPI's powerful validation capabilities.

Last updated