Re-packaging the Swagger UI as a Rust module

created: martedì, mag 21, 2024

Tutti i nostri servizi devono avere una Swagger UI per presentare all’utente il loro attuale file OpenAPI. Poiché il nostro backend è completamente costruito con Rust, l’hosting di questa Swagger UI avviene anch’esso tramite un processo Rust.

Quindi, per rendere il Swagger UI un elemento di primo livello nell’ecosistema Rust, abbiamo deciso di reimballare il Swagger-UI come modulo Rust. In questo modo, dependabot può rilevare aggiornamenti del progetto sottostante e integrare queste dipendenze nei nostri progetti.

Questo ha anche il vantaggio che ogni volta che questa dipendenza viene aggiornata, eseguiamo la nostra pipeline CI/CD per verificare se l’interfaccia utente è ancora compatibile per noi.

How it is build

Il Swagger UI viene confezionato tramite github. Quindi determinare la versione attuale è solo un’altra chiamata contro l’API di Github. In questo modo possiamo decidere se sono necessari aggiornamenti o meno. Se è stata rilasciata una nuova versione, scarichiamo i file JS e CSS minificati e aggiorniamo il nostro repository Rust locale con le nuove dipendenze.

Dopo che questi file sono stati aggiornati, aumentiamo anche la versione del modulo alla stessa versione del rilascio su github. In questo modo, la versione cargo corrisponde sempre alla versione github.

Tutto il codice necessario per questa procedura è nella definizione dell’azione github.

How to use it

Usare questo crate è piuttosto semplice. Le risorse statiche sono esposte come rotte axum e possono essere unite a una definizione di rotta esistente. Per implementare queste rotte, è necessario specificare un prefisso per le rotte, così come una definizione API. La definizione API può essere un file YAML inline o un link esterno alla definizione API.

Qui un esempio di come usare il crate con una definizione OpenAPI inline.

use axum::Router;
use swagger_ui_dist::{ApiDefinition, OpenApiSource};

#[tokio::main]
async fn main() {
    let api_def = ApiDefinition {
        uri_prefix: "/api",
        api_definition: OpenApiSource::Inline(include_str!("petstore.yaml")),
        title: Some("My Super Duper API"),
    };
    let app = Router::new().merge(swagger_ui_dist::generate_routes(api_def));
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    println!("listening on http://localhost:3000/api");
    axum::serve(listener, app).await.unwrap();
}

crate.io link: https://crates.io/crates/swagger-ui-dist

github repo: https://github.com/apimeister/swagger-ui-dist-rs/