Making the list interactive
============================

So far, our TODO list application is not very useful, since it's static. You can't update items,
nor add or remove them.

Receiving incoming data
-----------------------

Let's start by implementing a route handler that handles the creation of new items.
In the previous step you used the ``get`` decorator, which responds to the ``GET``
HTTP method. In this case we want to react to ``POST`` requests, so we are going to use
the corresponding ``post`` decorator.

.. literalinclude:: /examples/todo_app/create/dict.py
    :language: python
    :linenos:

Request data can be received via the ``data`` keyword. Litestar will recognize this, and
supply the data being sent with the request via this parameter. As with the query
parameters in the previous chapter, we use the type annotations to configure what type
of data we expect to receive, and set up validation. In this case, Litestar will expect
request data in the form of JSON and use the type annotation we gave it to convert it
into the correct format.

.. seealso::

    * :doc:`/usage/requests`


Using the interactive documentation to test a route
++++++++++++++++++++++++++++++++++++++++++++++++++++

Since our example now uses the ``POST`` HTTP method, you can no longer simply visit the
URL in our browser and get a response. Instead, you can use the interactive
documentation to send a ``POST`` request. Because of the OpenAPI schema generated by
Litestar, Swagger will know exactly what kind of data to send. In this example, it will
send a simple JSON object.

.. figure:: images/swagger-post-dict-response.png

    Sending a sample request to our ``add_item`` route reveals a successful response


Improving the example with dataclasses
++++++++++++++++++++++++++++++++++++++

As in the previous chapter, this too can be improved by using
:doc:`dataclasses <python:library/dataclasses>` instead of plain dicts.

.. literalinclude:: /examples/todo_app/create/dataclass.py
    :language: python
    :linenos:


This is not only easier on the eyes and adds more structure to the code, but also gives
better interactive documentation; it will now present us with the field names and
default values for the dataclass we have defined:

.. figure:: images/swagger-dict-vs-dataclass.png

    Documentation for the ``add_item`` route with ``data`` typed as a ``dict`` vs
    ``dataclass``

Using a dataclass also gives you better validation: omitting a key such as ``title``
will result in a useful error response:


.. figure:: images/swagger-dataclass-bad-body.png

    Sending a request without a ``title`` key fails


Create dynamic routes using path parameters
-------------------------------------------

The next task on the list is updating an item's status. For this, a way to refer to a
specific item on the list is needed. This could be done using query parameters, but
there's an easier, and more semantically coherent way of expressing this: path
parameters.

.. code-block:: python

    @get("/{name:str}")
    async def greeter(name: str) -> str:
        return "Hello, " + name


So far all the paths in your application are static, meaning they are expressed by a
constant string which does not change. In fact, the only path used so far is ``/``.

Path parameters allow you to construct dynamic paths and later refer to the dynamically
captured parts. This may sound complex at first, but it's actually quite simple; you can
think of it as a regular expression that's being used on the requested path.

Path parameters consist of two parts: an expression inside the path, describing the
parameter, and a corresponding function parameter of the same name in the route handler
function, which will receive the path parameter's value.

In the above example, a path parameter ``name:str`` is declared, which means that now,
a request to the path ``/john`` can be made, and the ``greeter`` function will be called
as ``greeter(name="john")``, similar to how query parameters are injected.


.. tip::
    Just like query parameters, path parameters can convert and validate their values as
    well. This is configured using the ``:type`` colon annotation, similar to type
    annotations. For example, ``value:str`` will receive values as a string, while
    ``value:int`` will try to convert it into an integer.

    A full list of supported types can be found here:
    :ref:`usage/routing/parameters:supported path parameter types`


By using this pattern and combining it with those from the earlier section about
receiving data you can now set up a route handler that takes in the title of a
TODO item, an updated item in form of a dataclass instance, and updates the item in the
list.


.. literalinclude:: /examples/todo_app/update.py
    :language: python


.. seealso::

    * :ref:`usage/routing/parameters:path parameters`
