Parameters ========== .. _parameter-types: Request parameters are parts of the request that can be injected into a handler function or dependency. They allow type-coercion, validation, and will show up in the generated OpenAPI schema. There are for request parameter types supported, which can be specified in two different forms: +--------+----------------------------+---------------------------------------------------------------------------+ | Type | Short form | :class:`~typing.Annotated` Form | +========+============================+===========================================================================+ | query | :data:`.params.FromQuery` | :class:`Annotated[\, QueryParameter()] <.params.QueryParameter>` | +--------+----------------------------+---------------------------------------------------------------------------+ | path | :data:`.params.FromPath` | :class:`Annotated[\, PathParameter()] <.params.PathParameter>` | +--------+----------------------------+---------------------------------------------------------------------------+ | header | :data:`.params.FromHeader` | :class:`Annotated[\, HeaderParameter()] <.params.HeaderParameter>` | +--------+----------------------------+---------------------------------------------------------------------------+ | cookie | :data:`.params.FromCookie` | :class:`Annotated[\, CookieParameter()] <.params.CookieParameter>` | +--------+----------------------------+---------------------------------------------------------------------------+ Parameter declarations ---------------------- Each parameter source has two equivalent declaration forms: a marker type alias for the common case, and an :class:`~typing.Annotated` form for when extra configuration is needed: .. tab-set:: .. tab-item:: Marker form .. code-block:: python from litestar import get from litestar.params import FromCookie, FromHeader, FromPath, FromQuery @get("/{user_id:int}") async def handler( user_id: FromPath[int], limit: FromQuery[int], token: FromHeader[str], session: FromCookie[str], ) -> None: ... .. tab-item:: Annotated form .. code-block:: python from typing_extensions import Annotated from litestar import get from litestar.params import ( CookieParameter, HeaderParameter, PathParameter, QueryParameter, ) @get("/{user_id:int}") async def handler( user_id: Annotated[int, PathParameter(ge=1)], limit: Annotated[int, QueryParameter(gt=0, le=100)], token: Annotated[str, HeaderParameter(name="X-API-KEY")], session: Annotated[str, CookieParameter(name="session-id")], ) -> None: ... The two forms are equivalent: ``FromQuery[T]`` is just an alias for ``Annotated[T, QueryParameter()]``. Prefer the marker form when no extra configuration is needed. .. admonition:: Technical details :class: info These :term:`parameters ` will be parsed from the function signature and used to generate an internal data model. This model in turn will be used to validate the parameters and generate the OpenAPI schema .. seealso:: :doc:`/topics/explicit_declarations` Optional, required and nullable ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Just like function parameters in Python, request parameters can be required, optional or have a default value. - Parameters declared without any default are required - Parameters declared with a default are optional - Parameters declared with ``| None`` are *nullable*, i.e. the may take a ``None`` value; they are still required, unless they are given a default value Defaults work exactly like defaults in regular function parameters: If the value is missing from the request, the handler is called with the default: .. literalinclude:: /examples/parameters/query_params_default.py :language: python :caption: Defining a default value for a query parameter Marking a parameter optional means the type itself permits :obj:`None`: .. literalinclude:: /examples/parameters/query_params_optional.py :language: python :caption: Defining an optional query parameter .. important:: Path parameters are always required because they are part of the URL itself. You can only get a "missing" path parameter when the same handler is registered against :ref:`multiple paths ` (e.g. ``["/items", "/items/{id:int}"]``), in which case the handler-side default fills in for the path without the slot. Parameter types --------------- Path parameters ~~~~~~~~~~~~~~~ Path :term:`parameters ` are declared as part of the ``path`` component of the URL using the syntax ``{param_name:param_type}``. The handler function receives the value via a parameter of the same name, declared with :data:`~.params.FromPath`: .. literalinclude:: /examples/parameters/path_parameters_1.py :language: python :caption: Defining a path parameter in a route handler There are two components to declaring a path parameter: 1. In the :class:`@get() <.handlers.get>` :term:`decorator`, the path component declares both the parameter's name (``user_id``) and type (:class:`int`) 2. In the handler signature, ``user_id`` is declared as :data:`FromPath[int] <.params.FromPath>`, which tells Litestar to inject the matching path value Two characteristics are unique to path parameters: - The URL slot defines the structurally required type via the ``:type`` suffix (see :ref:`usage/routing/parameters:supported path parameter types` below). Litestar coerces the captured string into this type before passing it to the handler, and the handler-side type annotation can request a further coercion (see :ref:`usage/routing/parameters:type coercion`). - Path parameters cannot be declared on application :ref:`layers ` .. tip:: You only need to declare the path :term:`parameter` in the function signature if the handler actually uses it. If the path parameter is part of the path but the function does not consume it, you can omit it from the signature; it will still be validated and added to the OpenAPI schema. Supported path parameter types ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The following types are supported in the ``{name:type}`` slot: * ``date``: Accepts date strings and time stamps. * ``datetime``: Accepts date-time strings and time stamps. * ``decimal``: Accepts decimal values and floats. * :class:`float`: Accepts ints and floats. * :class:`int`: Accepts ints and floats. * :class:`path`: Accepts valid POSIX paths. * :class:`str`: Accepts all string values. * ``time``: Accepts time strings with optional timezone compatible with standard (Pydantic/Msgspec) datetime formats. * ``timedelta``: Accepts duration strings compatible with the standard (Pydantic/Msgspec) timedelta formats. * ``uuid``: Accepts all uuid values. Query parameters ~~~~~~~~~~~~~~~~ Query :term:`parameters ` are declared as :term:`parameters ` on the handler function, typed with :data:`~.params.FromQuery` or ``Annotated[, QueryParameter()]``. .. literalinclude:: /examples/parameters/query_params.py :language: python :caption: Defining a query parameter in a route handler Header parameters ~~~~~~~~~~~~~~~~~ Header :term:`parameters ` are declared with :data:`~.params.FromHeader` or ``Annotated[, HeaderParameter()]``. The handler-side parameter name is used as the header name by default; HTTP headers are matched case-insensitively, so ``token: FromHeader[str]`` matches both ``Token`` and ``token`` on the wire. In practice, most headers you care about have names that are not valid Python identifiers (e.g. ``X-API-KEY``, ``Content-Type``). In those cases, switch to :class:`~typing.Annotated` and set ``name=`` on :class:`~.params.HeaderParameter`: .. code-block:: python from typing_extensions import Annotated from litestar.params import HeaderParameter async def handler(token: Annotated[str, HeaderParameter(name="X-API-KEY")]) -> None: ... Cookie parameters ~~~~~~~~~~~~~~~~~ Cookie :term:`parameters ` are declared with :data:`~.params.FromCookie` or ``Annotated[, CookieParameter()]``. The handler-side parameter name is used as the cookie name by default: .. code-block:: python from typing_extensions import Annotated from litestar.params import CookieParameter async def handler(session: Annotated[str, CookieParameter(name="session-id")]) -> None: ... A combined example showing both header and cookie parameters alongside a path parameter: .. literalinclude:: /examples/parameters/header_and_cookie_parameters.py :language: python :caption: Defining header and cookie parameters Type coercion ------------- Every parameter starts life on the wire as a string (or for path parameters, a string captured by the URL slot). Litestar coerces that raw value into the inner type of the marker (``FromQuery[int]``, ``FromHeader[float]``, ``FromPath[datetime]``, …) before passing it to the handler: .. literalinclude:: /examples/parameters/query_params_types.py :language: python :caption: Coercing query parameters into different types Path parameters additionally support coercion via the path-slot type itself. The handler-side type does not need to match the slot type one-to-one — if the slot captures an :class:`int` and the handler asks for a :class:`~datetime.datetime`, Litestar applies the second conversion: .. literalinclude:: /examples/parameters/path_parameters_2.py :language: python :caption: Coercing a path parameter into a different type The same conversion rules apply to header and cookie parameters: ``FromHeader[int]`` will parse the header value as an integer, ``FromCookie[datetime]`` will parse the cookie as a datetime, and so on. Aliasing -------- By default, the name of the function parameter is used to retrieve the parameter data from the request. To decouple the two, for example to receive ``camelCase`` query keys while keeping ``snake_case`` Python parameter names, or to declare an ``X-``-prefixed header, pass ``name="..."`` to the matching specifier class: .. literalinclude:: /examples/parameters/query_params_remap.py :language: python :caption: Remapping a query parameter to a different URL name A request to ``http://127.0.0.1:8000?camelCase=foo`` will be received as ``snake_case="foo"`` inside the handler. The same pattern applies to :class:`~.params.HeaderParameter`,:class:`~.params.CookieParameter` and :class:`~.params.PathParameter`. Validation constraints ---------------------- All parameters can be given certain validation constraints, that will be validated when a request is received, and represented in the OpenAPI schema. Currently supported constraints are: ``gt``, ``ge``, ``lt``, ``le``, ``multiple_of``, ``min_length``, ``max_length``, ``min_items``, ``max_items``, and ``pattern``. A value that does not satisfy the constraint raises :exc:`~.exceptions.http_exceptions.ValidationException`: .. literalinclude:: /examples/parameters/query_params_constraints.py :language: python :caption: Constraining a query parameter to integers larger than 5 OpenAPI metadata ---------------- Parameters can extend or alter their OpenAPI schema, e.g. to customize their title, add a description or examples: .. literalinclude:: /examples/parameters/path_parameters_3.py :language: python :caption: Adding OpenAPI metadata to a path parameter Customizing enum schemas ------------------------ By default, the OpenAPI schema generated for an enum-typed parameter uses the enum's docstring for the description section of the schema. Overriding the description via :attr:`~.params.KwargDefinition.description` would change it for every parameter sharing that enum, because only one schema is generated per enum. To get distinct descriptions, also pass :attr:`~.params.KwargDefinition.schema_component_key` so a separate schema component is generated per parameter: .. literalinclude:: /examples/parameters/query_params_enum.py :language: python :caption: Distinct OpenAPI components for parameters sharing the same enum type In the above example, the schema for ``q1`` references a "q1" schema component with description "This is q1"; the schema for ``q2`` references the shared "MyEnum" component with description "My enum accepts two values"; and the schema for ``q3`` references a "q3" component with description "This is q3". Without the :attr:`~.params.KwargDefinition.schema_component_key` arguments on ``q1`` and ``q3``, all three would share the same "MyEnum" component with description "This is q1" — whichever description was processed first wins. Layered Parameters ------------------ As part of Litestar's :ref:`layered architecture `, you can declare :term:`parameters ` not only on individual route handler functions, but also on other layers of the application: .. literalinclude:: /examples/parameters/layered_parameters.py :language: python :caption: Declaring parameters on different layers of the application In the above we declare :term:`parameters ` on the :class:`Litestar app <.app.Litestar>`, :class:`router <.router.Router>`, and :class:`controller <.controller.Controller>` layers in addition to those declared in the route handler. Examine these more closely: * ``app_param`` is a cookie parameter with the key ``special-cookie``, declared via :class:`~.params.CookieParameter` on the :class:`Litestar app <.app.Litestar>` with ``annotation=str``. ``required=False`` makes it optional; without that argument it would be required by default. Because the route handler function does not declare ``app_param`` at all, the parameter is still extracted and validated at the application level even though the handler never sees it. * ``router_param`` is a header parameter with the key ``MyHeader``, declared via :class:`~.params.HeaderParameter` on the router. It is declared ``required=False`` on the router, so it does not fail validation if absent — unless the handler explicitly opts in by re-declaring it (as this one does). The handler types it as :class:`FromHeader[str] <.params.FromHeader>` (rather than ``str | None``), making it required at the handler level. If a value *is* provided, it is also tested against the router-declared regex. * ``controller_param`` is a query parameter with the key ``controller_param``, declared via :class:`~.params.QueryParameter` on the controller with ``lt=100`` (value must be less than 100). The handler redeclares it with ``Annotated[int, QueryParameter(lt=50)]``, tightening the constraint to less than 50 for this particular route. * ``local_param`` is a route-handler-local :ref:`query parameter ` (``FromQuery[str]``), and ``path_param`` is a :ref:`path parameter ` (``FromPath[int]``). .. _deprecated-parameter-styles: Deprecated declaration styles ----------------------------- Earlier 2.x releases accepted several other ways of declaring handler parameters. These continue to work for the remainder of the 2.x line, but they now emit a :class:`~.exceptions.LitestarDeprecationWarning` and will be removed in 3.0. .. list-table:: :header-rows: 1 :widths: 45 55 * - Deprecated - Use instead * - ``def h(name: str)`` *(implicit query parameter)* - ``def h(name: FromQuery[str])`` * - ``def h(user_id: int)`` *(implicit path parameter)* - ``def h(user_id: FromPath[int])`` * - ``Annotated[str, Parameter(query="alias")]`` - ``Annotated[str, QueryParameter(name="alias")]`` * - ``Annotated[str, Parameter(header="X-API-KEY")]`` - ``Annotated[str, HeaderParameter(name="X-API-KEY")]`` * - ``Annotated[str, Parameter(cookie="session")]`` - ``Annotated[str, CookieParameter(name="session")]`` * - ``name: str = Parameter(...)`` *(default-value style)* - ``name: Annotated[str, QueryParameter(...)]`` The :func:`~.params.Parameter` function itself is **not** removed and can still be used to attach pure metadata (``description``, ``gt``, etc.) when wrapped in :class:`~typing.Annotated`. Only its ``header``, ``cookie``, and ``query`` keyword arguments are deprecated — passing any of those emits a :exc:`DeprecationWarning` independently of the handler-level warning.