Skip to content

Path Parameters

Path parameters are those, as the name suggests, parameters that are part of a URL (path) definition.

You can declare the path parameters (you can think of them as variables) using the same python syntax for strings.

from esmerald import Esmerald, Gateway, JSONResponse, get


@get("/users/{user_id}")
async def read_user(user_id: str) -> JSONResponse: ...


app = Esmerald(
    routes=[
        Gateway(read_user),
    ]
)

As you can see, the user_id declared in the path was also passed and provided in the function user. This is how you must declare path parameters in Esmerald.

You can now access the URL:

http://127.0.0.1/users/1

Declaration of the parameters

Esmerald being developed on top of Lilya also means that it allows two different syntaxes for the declaration of the parameters.

from esmerald import Esmerald, Gateway, JSONResponse, get


@get("/users/{user_id}")
async def read_user(user_id: str) -> JSONResponse: ...


app = Esmerald(
    routes=[
        Gateway(read_user),
    ]
)
from esmerald import Esmerald, Gateway, JSONResponse, get


@get("/users/<user_id>")
async def read_user(user_id: str) -> JSONResponse: ...


app = Esmerald(
    routes=[
        Gateway(read_user),
    ]
)

Esmerald allows the use of {} and <> syntaxes. Both work in an equal way and the reasoning for that is only to allow the users to choose their own preference.

Default parameters

When declaring a controller with path parameters, if no type is specified in the string declaration, Esmerald will assume it will be of type string.

from esmerald import Esmerald, Gateway, JSONResponse, get


@get("/users/{user_id}")
async def read_user(user_id: str) -> JSONResponse: ...


app = Esmerald(
    routes=[
        Gateway(read_user),
    ]
)

If you wish to specifiy exactly the type for the path parameter, you can do it by liteally specifiying the type of the parameter.

from esmerald import Esmerald, Gateway, JSONResponse, get


@get("/users/{user_id:int}")
async def read_user(user_id: int) -> JSONResponse: ...


app = Esmerald(
    routes=[
        Gateway(read_user),
    ]
)

This will make sure it will enforce the type int and throws an error if an invalid integer is provided.

When providing the path parameters with a proper typing, this will also make sure the OpenAPI documentation will have the right type for you to test.

Custom typing and transformers

What if you need to create a custom typing that is not natively supported by Esmerald? Well, Esmerald has your back with the transformers.

This will make sure you have your own transformer for your own unique typing and Esmerald can understand it.

Since Esmerald is built on top of Lilya, that means it also supports natively the same types.

You can check here for more details.

Enums

Esmerald also supports Enum types as typing. Yes, that's right, natively Esmerald handles Enums for you. This will trigger automatic validations of Esmerald in case a wrong value is provided.

from enum import Enum

from esmerald import Esmerald, Gateway, JSONResponse, get


class UserEnum(Enum):
    user = "user"
    admin = "admin"


@get("/users/{user_type}")
async def read_user(user_type: UserEnum) -> JSONResponse: ...


app = Esmerald(
    routes=[
        Gateway(read_user),
    ]
)

You can now call:

http://127.0.0.1/users/admin

If you, for example, provide something like this:

http://127.0.0.1/users/something

And since something is not declared in the Enum type, you will get an error similar to this:

{
    "detail": "Validation failed for http://127.0.0.1/users/something with method GET.",
    "errors": [
        {
            "type": "enum",
            "loc": ["item_type"],
            "msg": "Input should be 'user' or 'admin'",
            "input": "something",
            "ctx": {"expected": "'user' or 'admin'"},
            "url": "https://errors.pydantic.dev/2.8/v/enum",
        }
    ],
}