Handler è un concetto fondamentale del framework Salvo, che può essere semplicemente inteso come un'unità di elaborazione delle richieste con due principali utilizzi:
Come endpoint: Gli oggetti che implementano Handler
possono essere inseriti nel sistema di routing come punti finali per elaborare le richieste. Quando si utilizza la macro #[handler]
, una funzione può essere usata direttamente come endpoint; mentre con la macro #[endpoint]
, oltre a fungere da endpoint, viene generata automaticamente la documentazione OpenAPI (questo aspetto sarà approfondito in seguito).
Come middleware: Lo stesso Handler
può essere utilizzato come middleware per elaborare le richieste prima o dopo che raggiungano l'endpoint finale.
Il flusso di elaborazione delle richieste in Salvo può essere visto come una "pipeline": la richiesta passa prima attraverso una serie di middleware (elaborazione verticale), poi raggiunge l'endpoint corrispondente (elaborazione orizzontale). Sia i middleware che gli endpoint sono implementazioni di Handler
, garantendo coerenza e flessibilità al sistema.
L'essenza del modello a cipolla risiede nel posizionamento di ctrl.call_next()
prima e dopo, realizzando un flusso bidirezionale di elaborazione delle richieste e risposte, permettendo a ogni middleware di partecipare all'intero ciclo richiesta-risposta.
Handler è l'oggetto responsabile dell'elaborazione delle richieste Request. È un Trait che contiene un metodo asincrono handle
:
La funzione handle
ha per default quattro parametri: &mut Request, &mut Depot, &mut Response, &mut FlowCtrl
. Depot è un'area di memorizzazione temporanea per dati relativi alla richiesta corrente.
A seconda dell'uso, può fungere da middleware (hoop), elaborando la richiesta prima o dopo che raggiunga l'Handler finale, ad esempio per autenticazione, compressione dati, ecc.
I middleware vengono aggiunti tramite la funzione hoop
del Router
e influenzano il Router
corrente e tutti i suoi discendenti.
Handler
può anche essere usato come goal
, partecipando al routing ed eseguendo l'elaborazione finale.
Handler
come middleware (hoop)Come middleware, Handler
può essere aggiunto a tre tipi di oggetti:
Service
: tutte le richieste passano attraverso i suoi middleware.
Router
: solo le richieste che corrispondono al routing passano attraverso i middleware definiti nel Service
e quelli raccolti lungo il percorso.
Catcher
: elabora le richieste solo in caso di errore, quando non è stata scritta un'informazione di errore personalizzata.
Handler
: supporta l'aggiunta di middleware per logica pre o post elaborazione.
#[handler]
#[handler]
semplifica notevolmente la scrittura del codice e ne aumenta la flessibilità.
Applicata a una funzione, la fa implementare Handler
:
Equivale a:
Con #[handler]
, il codice è molto più semplice:
#[async_trait]
.Writer
o Scribe
possono essere restituiti direttamente. &'static str
implementa Scribe
, quindi può essere restituito direttamente.#[handler]
può essere applicata anche agli impl
di struct
per implementare Handler
, dove la funzione handle
diventa l'implementazione specifica:
In Salvo, Handler
può restituire Result
, purché Ok
e Err
implementino il trait Writer
.
Con la funzionalità anyhow
attiva, anyhow::Error
implementa Writer
e viene mappato su InternalServerError
.
Per errori personalizzati, è possibile personalizzare l'output: