Use Built-in Mods
=================

**Note: This tutorial covers experimental features. The functionality and interfaces may
change in future versions.**

In this tutorial, we will learn how to utilize built-in mods to augment the behavior of
a ``ClientApp``. Mods (sometimes also called Modifiers) allow us to perform operations
before and after a task is processed in the ``ClientApp``.

What are Mods?
--------------

A Mod is a callable that wraps around a ``ClientApp``. It can manipulate or inspect the
incoming ``Message`` and the resulting outgoing ``Message``. The signature for a ``Mod``
is as follows:

.. code-block:: python

    ClientApp = Callable[[Message, Context], Message]
    Mod = Callable[[Message, Context, ClientApp], Message]

A typical mod function might look something like this:

.. code-block:: python

    def example_mod(msg: Message, ctx: Context, nxt: ClientApp) -> Message:
        # Do something with incoming Message (or Context)
        # before passing to the inner ``ClientApp``
        msg = nxt(msg, ctx)
        # Do something with outgoing Message (or Context)
        # before returning
        return msg

Using Mods
----------

To use mods in your ``ClientApp``, you can follow these steps:

1. Import the required mods
~~~~~~~~~~~~~~~~~~~~~~~~~~~

First, import the built-in mod you intend to use:

.. code-block:: python

    import flwr as fl
    from flwr.client.mod import example_mod_1, example_mod_2

2. Define your client function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Define your client function (``client_fn``) that will be wrapped by the mod(s):

.. code-block:: python

    def client_fn(cid):
        # Your client code goes here.
        return  # your client

3. Create the ``ClientApp`` with mods
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Create your ``ClientApp`` and pass the mods as a list to the ``mods`` argument. The
order in which you provide the mods matters:

.. code-block:: python

    app = fl.client.ClientApp(
        client_fn=client_fn,
        mods=[
            example_mod_1,  # Mod 1
            example_mod_2,  # Mod 2
        ],
    )

Order of execution
------------------

When the ``ClientApp`` runs, the mods are executed in the order they are provided in the
list:

1. ``example_mod_1`` (outermost mod)
2. ``example_mod_2`` (next mod)
3. Message handler (core function that handles the incoming ``Message`` and returns the
   outgoing ``Message``)
4. ``example_mod_2`` (on the way back)
5. ``example_mod_1`` (outermost mod on the way back)

Each mod has a chance to inspect and modify the incoming ``Message`` before passing it
to the next mod, and likewise with the outgoing ``Message`` before returning it up the
stack.

Conclusion
----------

By following this guide, you have learned how to effectively use mods to enhance your
``ClientApp``'s functionality. Remember that the order of mods is crucial and affects
how the input and output are processed.

Enjoy building a more robust and flexible ``ClientApp`` with mods!
