> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squarecloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Listeners

> Aprende a usar listeners en tu aplicación con el SDK de python de squarecloud.

A veces resulta muy útil tener listeners para las peticiones, lo que te permite implementar funcionalidades que deben ejecutarse cada vez que "algo" ocurre en tu aplicación.

Para este propósito se han añadido dos tipos de listeners.

## Capture Listener

Por ejemplo, imagina que cada vez que se realiza una petición a la ruta '/logs', mi código ejecuta una tarea que comprueba si los nuevos logs difieren de los anteriores. Bueno, veamos cómo se puede hacer esto:

```python theme={null}
import squarecloud as square
from squarecloud import Endpoint

@app.capture(endpoint=Endpoint.logs())
async def on_logs_request(before, after):
    if after != before:
        print(f'New logs!!! {after}')

async def main():
    client = square.Client('your api key')
    app = await client.app('application_id')

    await app.logs()  # True
    await app.logs()  # False
```

Como se ve arriba, al usar el decorador app.capture sobre una función, esta función será llamada cada vez que se realice una petición al endpoint especificado en el decorador. Los endpoints aceptados son `APP_STATUS`, `LOGS` o `BACKUP`. Esta función debe recibir dos parámetros:

* `before`(representa el estado antes de la petición)
* `after`(representa el estado después de la petición)

El tipo de dato devuelto por `before` y `after` depende de qué endpoint esté "escuchando" el listener. Si es la ruta **APP\_STATUS**, recibirá un `StatusData`, **LOGS** recibirá un `LogsData` y **BACKUP** recibirá un `BackupData`.

Como habrás notado en el ejemplo anterior, la primera vez que ocurre la comparación entre los logs, `after != before` devuelve True. Esto sucede precisamente porque after es igual a `LogsData(logs='')`, ya que aún no hay nada almacenado en la caché internamente.

<Accordion title="Información adicional sobre este decorador">
  * Si usas discord.py o algún fork (probablemente lo uses), debes
    saber que lo que diferencia los eventos es el nombre
    de las funciones que el decorador envuelve, pero aquí es diferente. Para saber
    a qué
    ruta de la API debe "escuchar" el decorador, usamos el parámetro `endpopint`, que
    recibe una clase `Endpoint`, por lo que el nombre de la función que el decorador
    envuelve depende de ti.
  * La función que el decorador envuelve puede ser en realidad cualquier cosa que sea
    un callable. Esto incluye funciones normales, corrutinas e incluso
    clases (se llamará a `__init__`).
  * Si el endpoint no es un \[Endpoint.app\_status()], \[Endpoint.logs()] o \[Endpoint.backup()],
    solo se devolverá un parámetro `response` (de tipo `squarecloud.http.Response`).
</Accordion>

<Tip>
  Puedes usar el parámetro `avoid_listener=True` para que el listener de la aplicación no sea llamado.
</Tip>

## Request Listener

Los "request listeners" hacen prácticamente lo mismo. Pero aquí usas el \[Client], y el retorno de todos los endpoints son objetos `squarecloud.http.Response`.

```python theme={null}
import squarecloud as square
from squarecloud import Endpoint

@client.on_request(endpoint=Endpoint.logs())
async def on_logs_request(response):
    print(1, response)

async def main():
    client = square.Client('your api key')
    await client.get_logs(app_id='application_id')  # 1, Response(success)
```

## Pasar argumentos adicionales

Puedes pasar a algunos métodos un argumento de palabra clave llamado `extra`, y este será pasado a tu listener

```python theme={null}
import squarecloud as square
from squarecloud import Endpoint

@client.on_request(Endpoint.status())
async def get_extra_param(before, after, extra: dict[str, str]):
    print(extra)

async def main():
    client = square.Client('your api key')
    await client.app_status('application_id', extra={'name': 'robertinho'})
```

<Tip>Puedes obtener algunas funcionalidades geniales en los listeners usando pydantic en tu proyecto, echa un vistazo a [using pydantic](./using_pydantic)</Tip>
