Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Rust: costruire API REST

Rust: come implementare API REST, servizi web in genere e microservizi per strutturare le nostre architetture
Rust: come implementare API REST, servizi web in genere e microservizi per strutturare le nostre architetture
Link copiato negli appunti

Sinora, parlando di Rust abbiamo visto il lato client della Rete. È giusto ora vedere quello server che al giorno d'oggi può portare grandi risultati permettendo di implementare API REST, servizi web in genere e tanti microservizi per strutturare le nostre architetture. Analizziamo un framework di nome warp che si sposa perfettamente con la programmazione asincrona di cui abbiamo già parlato. Scopriremo, in questa lezione e nelle successive, che questo framework modulare è ricco di componenti che contemplano server, router, filtri e qualsiasi altro meccanismo per poter rispondere alle richieste dei client. Pertanto potrà essere impiegato a partire dagli usi minimali fino a scenari estremamente articolati.

Preparazione del progetto Rust

Approcciamo direttamente lo sviluppo di una API, non molto estesa ma che sarà in grado di mettere in luce i principali meccanismi di warp in attesa di approfondirla al meglio. Predisponiamo un progetto cargo di nome esempio-api con:

$ cargo new esempio-api

e aggiungiamo entrambe le dipendenze di cui abbiamo bisogno:

$ cargo add warp
$ cargo add tokio

A questo punto facciamo partire il nostro primo server con il seguente codice:

use warp::Filter;
#[tokio::main]
async fn main() {
    let raddoppia = warp::path!("raddoppia" / i16)
        .map(|valore| format!("Il doppio di {} è {}", valore, valore*2));
    warp::serve(raddoppia)
        .run(([127, 0, 0, 1], 8080))
        .await;
}

Il codice crea un servizio, di un solo metodo, accessibile sulla porta 8080 in locale (indirizzo localhost) che se invocato nel percorso /raddoppia seguito da un numero intero restituisce un messaggio in cui si esplicita il valore doppio del numero passato. Se ad esempio viene invocato http://localhost:8080/raddoppia/5 viene restituito "Il doppio di 5 è 10."

Il codice Rust è diviso in due parti racchiuse in uno stesso main:

  • la prima definisce un metodo della API (l'unico al momento) che si forma con warp::path. In tal caso si indica che il path inizierà con /raddoppia e proseguirà con un numero intero a 16 bit. Il map introduce il codice costituito dalla closure che raddoppia un valore passato e lo immette in un messaggio;
  • il secondo pezzo lancia il server (warp::serve(raddoppia)) indicando indirizzo e porta di ascolto e stabilendo che l'unico codice implementato sarà proprio raddoppia.

Per provare il codice possiamo agire da browser o con altri strumenti di test HTTP come il tradizionale curl attivato con il comando:

curl localhost:8080/raddoppia/23

restituisce

Il doppio di 23 è 46

Il routing

E se volessimo aggiungere un altro tipo di risposta da invocare su un indirizzo diverso ma senza compromettere raddoppia? Dovremmo implementare un po' di routing tra le richieste in modo che, al riconoscimento di un percorso, Warp saprebbe quale funzionalità applicare. Supponiamo di aggiungere anche il percorso /ciao che, se invocato seguito da una stringa che rappresenta un nome, viene restituito un messaggio di saluto all'indirizzo di questo nome:

use warp::Filter;
#[tokio::main]
async fn main() {
    let raddoppia = warp::path!("raddoppia" / i16)
        .map(|valore| format!("Il doppio di {} è {}", valore, valore*2));
    let ciao = warp::path!("ciao" / String)
        .map(|nome| format!("Ciao {}", nome));
    let router = raddoppia.or(ciao);
    warp::serve(router)
        .run(([127, 0, 0, 1], 8080))
        .await;
}

Notiamo che raddoppia è rimasta identica ma abbiamo aggiunto il metodo ciao. Quest'ultimo è simile al precedente solo che consiste in un semplice esercizio di saluto.

La cosa interessante è che abbiamo creato il router, componente che con or scandisce che la risposta sarà gestita o da una funzione o dall'altra a seconda del formato della richiesta. In qualsiasi altro caso non verrà fornita risposta. Notiamo inoltre che il router è stato passato a warp::serve che così sarà a conoscenza di entrambi gli indirizzi.

Pertanto potremo provare le seguenti risposte:

$ curl localhost:8080/raddoppia/23
Il doppio di 23 è 46
$ curl localhost:8080/ciao/Simone
Ciao Simone

Un aspetto che scopriamo di Warp è che dispone in questo caso di molte funzioni per la concatenazione di funzionalità e questo rende il codice molto flessibile ma anche comodo da interpretare.

Questo meccanismo permette di definire anche i metodi stessi. Vediamo questa rappresentazione di un metodo HTTP/POST (versione esemplificativa da completare):

warp::post()
        .and(warp::path("v1"))
        .and(warp::path("prodotti"))
        .and(warp::path::end())
        .and(...)
        .and(...);

Vediamo che si usa il metodo post e si va poi a definire con un elenco di and i vari blocchi del percorso ed in fondo c'è spazio per varie funzioni di conversione ed elaborazione.

Tutto ciò verrà approfondito nei prossimi esempi della guida Rust.

Ti consigliamo anche