use thiserror::Error;
#[derive(Debug, Error)]
pub enum OpenApiError {
#[error("OpenAPI build error: {0}")]
Build(String),
#[error("JSON serialize error: {0}")]
Serialize(String),
}
pub struct OpenApiBuilder {
title: String,
version: String,
description: Option<String>,
}
impl OpenApiBuilder {
pub fn new(title: impl Into<String>, version: impl Into<String>) -> Self {
Self {
title: title.into(),
version: version.into(),
description: None,
}
}
pub fn description(mut self, desc: impl Into<String>) -> Self {
self.description = Some(desc.into());
self
}
pub fn build(self) -> utoipa::openapi::Info {
let mut info = utoipa::openapi::Info::default();
info.title = self.title;
info.version = self.version;
info.description = self.description;
info
}
pub fn to_json(self) -> Result<String, OpenApiError> {
let info = self.build();
serde_json::to_string_pretty(&info).map_err(|e| OpenApiError::Serialize(e.to_string()))
}
pub fn validate(self) -> Result<(), OpenApiError> {
let info = self.build();
if info.title.is_empty() {
return Err(OpenApiError::Build("title is empty".into()));
}
if info.version.is_empty() {
return Err(OpenApiError::Build("version is empty".into()));
}
Ok(())
}
}
#[cfg(feature = "swagger-ui")]
pub fn swagger_ui_routes() -> axum::Router {
utoipa_swagger_ui::SwaggerUi::new("/docs/{_:.*}")
.url("/api-docs/openapi.json", utoipa::OpenApi::default())
.into()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_openapi_build() {
let info = OpenApiBuilder::new("Test API", "1.0.0").build();
assert_eq!(info.title, "Test API");
assert_eq!(info.version, "1.0.0");
}
#[test]
fn test_openapi_to_json() {
let json = OpenApiBuilder::new("Test API", "1.0.0").to_json().unwrap();
assert!(json.contains("Test API"));
assert!(json.contains("1.0.0"));
}
#[test]
fn test_openapi_validate() {
let result = OpenApiBuilder::new("Test", "1.0").validate();
assert!(result.is_ok());
}
#[test]
fn test_openapi_validate_empty_title() {
let result = OpenApiBuilder::new("", "1.0").validate();
assert!(result.is_err());
}
#[test]
fn test_openapi_error_display() {
let err = OpenApiError::Build("test error".into());
assert_eq!(err.to_string(), "OpenAPI build error: test error");
}
}