Todos nuestros servicios necesitan tener una Swagger UI para presentar su archivo OpenAPI actual al usuario. Dado que nuestro backend está completamente construido con Rust, alojar esta Swagger UI también se realiza mediante un proceso en Rust.
Por eso, para convertir a la Swagger UI en un ciudadano de primera clase en el ecosistema Rust, decidimos reempaquetar Swagger UI como un módulo de Rust. De este modo, dependabot puede detectar actualizaciones del proyecto subyacente y traer esas dependencias a nuestros proyectos.
Esto también tiene el beneficio de que, cada vez que esta dependencia se actualiza, ejecutamos nuestra canalización CI/CD para comprobar si la interfaz de usuario sigue funcionando correctamente para nosotros.
La Swagger UI se empaqueta a través de GitHub. Por tanto, determinar la versión actual es simplemente otra llamada contra la API de GitHub. De esta manera podemos decidir si es necesario actualizar o no. Si se ha publicado una nueva versión, descargamos los archivos JS y CSS minificados y actualizamos nuestro repositorio local de Rust con las nuevas dependencias.
Después de actualizar esos archivos, también aumentamos la versión del módulo a la misma versión que la publicación en GitHub. De este modo, la versión en cargo siempre coincide con la versión en GitHub.
Todo el código necesario para este procedimiento está en la definición de la acción de GitHub.
Usar este crate es bastante sencillo. Los recursos estáticos se exponen como rutas de axum y pueden fusionarse con una definición de rutas existente. Para implementar esas rutas, necesitas especificar un prefijo para las rutas, así como una definición de API. La definición de la API puede ser un archivo YAML en línea o un enlace externo a la definición de la API.
Aquí hay un ejemplo de cómo usar el crate con una definición OpenAPI en línea.
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();
}
Enlace en crates.io: https://crates.io/crates/swagger-ui-dist
Repositorio en GitHub: https://github.com/apimeister/swagger-ui-dist-rs/