Neuverpackung der Swagger UI als Rust-Modul

created: Dienstag, Mai 21, 2024

Alle unsere Services müssen eine Swagger UI haben, um ihre aktuelle OpenAPI-Datei dem Benutzer darzustellen. Da unser Backend vollständig in Rust erstellt ist, wird das Hosting dieser Swagger UI ebenfalls durch einen Rust-Prozess übernommen.

Um die Swagger UI zu einem erstklassigen Mitglied im Rust-Ökosystem zu machen, haben wir beschlossen, die Swagger-UI als Rust-Modul neu zu verpacken. Auf diese Weise kann dependabot Updates des zugrunde liegenden Projekts erkennen und diese Abhängigkeiten in unsere Projekte übernehmen.

Das hat außerdem den Vorteil, dass jedes Mal, wenn diese Abhängigkeit aktualisiert wird, unsere CI/CD-Pipeline ausgeführt wird, um zu prüfen, ob die UI weiterhin für uns funktioniert.

Wie es aufgebaut ist

Die Swagger UI wird über GitHub verpackt bereitgestellt. Daher ist die Ermittlung der aktuellen Version lediglich ein weiterer Aufruf der GitHub-API. Auf diese Weise können wir entscheiden, ob ein Update erforderlich ist oder nicht. Wenn eine neue Version veröffentlicht wurde, laden wir die minifizierten JS- und CSS-Dateien herunter und aktualisieren unser lokales Rust-Repo mit den neuen Abhängigkeiten.

Nachdem diese Dateien aktualisiert wurden, erhöhen wir auch die Modulversion auf die gleiche Version wie das GitHub-Release. So stimmt die Cargo-Version immer mit der GitHub-Version überein.

Der gesamte Code, der für dieses Verfahren erforderlich ist, befindet sich in der GitHub Action-Definition.

Wie man es verwendet

Die Verwendung dieses Crates ist recht einfach. Die statischen Ressourcen werden als Axum-Routen bereitgestellt und können mit einer bestehenden Routen-Definition zusammengeführt werden. Um diese Routen zu implementieren, müssen Sie ein Präfix für die Routen sowie eine API-Definition angeben. Die API-Definition kann entweder eine inline YAML-Datei oder ein externer Link zur API-Definition sein.

Hier ein Beispiel, wie man das Crate mit einer inline OpenAPI-Definition verwendet.

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();
}

Crates.io-Link: https://crates.io/crates/swagger-ui-dist

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