1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
Parameters
===========
Path Parameters
---------------
Path :term:`parameters <parameter>` are parameters declared as part of the ``path`` component of
the URL. They are declared using a simple syntax ``{param_name:param_type}`` :
.. literalinclude:: /examples/parameters/path_parameters_1.py
:language: python
:caption: Defining a path parameter in a route handler
In the above there are two components:
1. The path :term:`parameter` is defined in the :class:`@get() <.handlers.get>` :term:`decorator`, which declares both
the parameter's name (``user_id``) and type (:class:`int`).
2. The :term:`decorated <decorator>` function ``get_user`` defines a parameter with the same name as the
parameter defined in the ``path`` :term:`kwarg <argument>`.
The correlation of parameter name ensures that the value of the path parameter will be injected into
the function when it is called.
Supported Path Parameter Types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Currently, the following types are supported:
* ``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.
The types declared in the path :term:`parameter` and the function do not need to match 1:1 - as long as
parameter inside the function declaration is typed with a "higher" type to which the lower type can be coerced,
this is fine. For example, consider this:
.. literalinclude:: /examples/parameters/path_parameters_2.py
:language: python
:caption: Coercing path parameters into different types
The :term:`parameter` defined inside the ``path`` :term:`kwarg <argument>` is typed as :class:`int` , because the value
passed as part of the request will be a timestamp in milliseconds without any decimals. The parameter in
the function declaration though is typed as :class:`datetime.datetime`.
This works because the int value will be automatically coerced from an :class:`int` into a :class:`~datetime.datetime`.
Thus, when the function is called it will be called with a :class:`~datetime.datetime`-typed parameter.
.. note:: You only need to define the :term:`parameter` in the function declaration if it is actually used inside the
function. If the path parameter is part of the path, but the function does not use it, it is fine to omit
it. It will still be validated and added to the OpenAPI schema correctly.
The Parameter function
----------------------
:func:`~.params.Parameter` is a helper function wrapping a :term:`parameter` with extra information to be
added to the OpenAPI schema.
Extra validation and documentation for path params
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to add validation or enhance the OpenAPI documentation generated for a given path :term:`parameter`,
you can do so using the `the parameter function`_:
.. literalinclude:: /examples/parameters/path_parameters_3.py
:language: python
:caption: Adding extra validation and documentation to a path parameter
In the above example, :func:`~.params.Parameter` is used to restrict the value of :paramref:`~.params.Parameter.version`
to a range between 1 and 10, and then set the :paramref:`~.params.Parameter.title`,
:paramref:`~.params.Parameter.description`, :paramref:`~.params.Parameter.examples`, and
:paramref:`externalDocs <.params.Parameter.external_docs>` sections of the OpenAPI schema.
Query Parameters
----------------
Query :term:`parameters <parameter>` are defined as :term:`keyword arguments <argument>` to handler functions.
Every :term:`keyword argument <argument>` that is not otherwise specified (for example as a
:ref:`path parameter <usage/routing/parameters:path parameters>`) will be interpreted as a query parameter.
.. literalinclude:: /examples/parameters/query_params.py
:language: python
:caption: Defining query parameters in a route handler
.. admonition:: Technical details
:class: info
These :term:`parameters <parameter>` 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.
This ability allows you to use any number of schema/modelling libraries, including Pydantic, Msgspec, Attrs, and Dataclasses, and it will
follow the same kind of validation and parsing as you would get from these libraries.
Query :term:`parameters <parameter>` come in three basic types:
- Required
- Required with a default value
- Optional with a default value
Query parameters are **required** by default. If one such a parameter has no value,
a :exc:`~.exceptions.http_exceptions.ValidationException` will be raised.
Default values
~~~~~~~~~~~~~~
In this example, ``param`` will have the value ``"hello"`` if it is not specified in the request.
If it is passed as a query :term:`parameter` however, it will be overwritten:
.. literalinclude:: /examples/parameters/query_params_default.py
:language: python
:caption: Defining a default value for a query parameter
Optional :term:`parameters <parameter>`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Instead of only setting a default value, it is also possible to make a query parameter entirely optional.
Here, we give a default value of ``None`` , but still declare the type of the query parameter
to be a :class:`string <str>`. This means that this parameter is not required.
If it is given, it has to be a :class:`string <str>`.
If it is not given, it will have a default value of ``None``
.. literalinclude:: /examples/parameters/query_params_optional.py
:language: python
:caption: Defining an optional query parameter
Type coercion
-------------
It is possible to coerce query :term:`parameters <parameter>` into different types.
A query starts out as a :class:`string <str>`, but its values can be parsed into all kinds of types.
.. literalinclude:: /examples/parameters/query_params_types.py
:language: python
:caption: Coercing query parameters into different types
Alternative names and constraints
---------------------------------
Sometimes you might want to "remap" query :term:`parameters <parameter>` to allow a different name in the URL
than what is being used in the handler function. This can be done by making use of :func:`~.params.Parameter`.
.. literalinclude:: /examples/parameters/query_params_remap.py
:language: python
:caption: Remapping query parameters to different names
Here, we remap from ``snake_case`` in the handler function to ``camelCase`` in the URL.
This means that for the URL ``http://127.0.0.1:8000?camelCase=foo`` , the value of ``camelCase``
will be used for the value of the ``snake_case`` parameter.
:func:`~.params.Parameter` also allows us to define additional constraints:
.. literalinclude:: /examples/parameters/query_params_constraints.py
:language: python
:caption: Constraints on query parameters
In this case, ``param`` is validated to be an *integer larger than 5*.
Header and Cookie Parameters
----------------------------
Unlike *Query* :term:`parameters <parameter>`, *Header* and *Cookie* parameters have to be
declared using `the parameter function`_ , for example:
.. literalinclude:: /examples/parameters/header_and_cookie_parameters.py
:language: python
:caption: Defining header and cookie parameters
As you can see in the above, header parameters are declared using the ``header``
:term:`kwargs <argument>` and cookie parameters using the ``cookie`` :term:`kwarg <argument>`.
Aside form this difference they work the same as query parameters.
Layered Parameters
------------------
As part of Litestar's :ref:`layered architecture <usage/applications:layered architecture>`, you can declare
:term:`parameters <parameter>` not only as part of 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 <parameter>` 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. Now, examine these more closely.
* ``app_param`` is a cookie parameter with the key ``special-cookie``. We type it as :class:`str` by passing
this as an arg to the :func:`~.params.Parameter` function. This is required for us to get typing in the OpenAPI doc.
Additionally, this parameter is assumed to be required because it is not explicitly set as ``False`` on
:paramref:`~.params.Parameter.required`.
This is important because the route handler function does not declare a parameter called ``app_param`` at all,
but it will still require this param to be sent as part of the request of validation will fail.
* ``router_param`` is a header parameter with the key ``MyHeader``. Because it is set as ``False`` on
:paramref:`~.params.Parameter.required`, it will not fail validation if not present unless explicitly declared by a
route handler - and in this case it is.
Thus, it is actually required for the router handler function that declares it as an :class:`str` and not an
``str | None``. If a :class:`string <str>` value is provided, it will be tested against the provided regex.
* ``controller_param`` is a query param with the key ``controller_param``. It has an :paramref:`~.params.Parameter.lt`
set to ``100`` defined on the controller, which means the provided value must be less than 100.
Yet the route handler redeclares it with an :paramref:`~.params.Parameter.lt` set to ``50``,
which means for the route handler this value must be less than 50.
* ``local_param`` is a route handler local :ref:`query parameter <usage/routing/parameters:query parameters>`, and
``path_param`` is a :ref:`path parameter <usage/routing/parameters:path parameters>`.
.. note:: You cannot declare path :term:`parameters <parameter>` in different application layers. The reason for this
is to ensure simplicity - otherwise parameter resolution becomes very difficult to do correctly.
|