Reconditionner Swagger UI en tant que module Rust

created: mardi, mai 21, 2024

Tous nos services doivent disposer d’une Swagger UI pour présenter à l’utilisateur leur fichier OpenAPI actuel. Puisque notre backend est entièrement construit en Rust, l’hébergement de cette Swagger UI est également réalisé via un processus Rust.

Ainsi, pour faire du Swagger UI un acteur de premier ordre dans l’écosystème Rust, nous avons décidé de reconditionner Swagger UI en tant que module Rust. De cette manière, dependabot peut repérer les mises à jour du projet sous-jacent et intégrer ces dépendances dans nos projets.

Cela a aussi l’avantage que chaque fois que cette dépendance est mise à jour, nous lançons notre pipeline CI/CD pour vérifier si l’interface utilisateur est toujours fonctionnelle pour nous.

Comment c’est construit

La Swagger UI est empaquetée via GitHub. Ainsi, déterminer la version actuelle se fait simplement par un autre appel à l’API GitHub. De cette façon, nous pouvons décider si une mise à jour est nécessaire ou non. Si une nouvelle version est sortie, nous téléchargeons les fichiers JS et CSS minifiés et mettons à jour notre dépôt Rust local avec les nouvelles dépendances.

Après la mise à jour de ces fichiers, nous augmentons également la version du module pour qu’elle corresponde à la version de la release GitHub. Ainsi, la version dans cargo correspond toujours à la version GitHub.

Tout le code nécessaire à cette procédure se trouve dans la définition de l’action GitHub.

Comment l’utiliser

Utiliser ce crate est assez simple. Les ressources statiques sont exposées sous forme de routes axum et peuvent être fusionnées avec une définition de route existante. Pour implémenter ces routes, vous devez spécifier un préfixe pour les routes ainsi qu’une définition d’API. La définition d’API peut être un fichier YAML inline ou un lien externe vers la définition de l’API.

Voici un exemple d’utilisation du crate avec une définition 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();
}

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

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