use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OpenApiConfig {
pub openapi_version: String,
pub info: ApiInfo,
pub servers: Vec<ServerConfig>,
pub security_schemes: HashMap<String, SecurityScheme>,
pub tags: Vec<TagConfig>,
pub external_docs: Option<ExternalDocs>,
pub include_examples: bool,
pub nullable_optional: bool,
pub custom_schemas: HashMap<String, String>,
pub export: ExportConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiInfo {
pub title: String,
pub description: Option<String>,
pub version: String,
pub terms_of_service: Option<String>,
pub contact: Option<Contact>,
pub license: Option<License>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Contact {
pub name: Option<String>,
pub url: Option<String>,
pub email: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct License {
pub name: String,
pub url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
pub url: String,
pub description: Option<String>,
pub variables: Option<HashMap<String, ServerVariable>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerVariable {
pub default: String,
pub description: Option<String>,
pub r#enum: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum SecurityScheme {
#[serde(rename = "http")]
Http {
scheme: String,
bearer_format: Option<String>,
},
#[serde(rename = "apiKey")]
ApiKey { name: String, r#in: String },
#[serde(rename = "oauth2")]
OAuth2 { flows: OAuth2Flows },
#[serde(rename = "openIdConnect")]
OpenIdConnect { open_id_connect_url: String },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OAuth2Flows {
pub authorization_code: Option<OAuth2Flow>,
pub implicit: Option<OAuth2Flow>,
pub password: Option<OAuth2Flow>,
pub client_credentials: Option<OAuth2Flow>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OAuth2Flow {
pub authorization_url: Option<String>,
pub token_url: Option<String>,
pub refresh_url: Option<String>,
pub scopes: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TagConfig {
pub name: String,
pub description: Option<String>,
pub external_docs: Option<ExternalDocs>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExternalDocs {
pub url: String,
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExportConfig {
pub formats: Vec<ExportFormat>,
pub validate: bool,
pub pretty_print: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ExportFormat {
Json,
Yaml,
Postman,
Insomnia,
}
impl Default for OpenApiConfig {
fn default() -> Self {
Self {
openapi_version: "3.0.3".to_string(),
info: ApiInfo {
title: "API Documentation".to_string(),
description: Some("Auto-generated API documentation".to_string()),
version: "1.0.0".to_string(),
terms_of_service: None,
contact: None,
license: Some(License {
name: "MIT".to_string(),
url: Some("https://opensource.org/licenses/MIT".to_string()),
}),
},
servers: vec![ServerConfig {
url: "http://localhost:3000".to_string(),
description: Some("Development server".to_string()),
variables: None,
}],
security_schemes: {
let mut schemes = HashMap::new();
schemes.insert(
"bearerAuth".to_string(),
SecurityScheme::Http {
scheme: "bearer".to_string(),
bearer_format: Some("JWT".to_string()),
},
);
schemes
},
tags: Vec::new(),
external_docs: None,
include_examples: true,
nullable_optional: true,
custom_schemas: HashMap::new(),
export: ExportConfig {
formats: vec![ExportFormat::Json, ExportFormat::Yaml],
validate: true,
pretty_print: true,
},
}
}
}
impl OpenApiConfig {
pub fn new(title: &str, version: &str) -> Self {
let mut config = Self::default();
config.info.title = title.to_string();
config.info.version = version.to_string();
config
}
pub fn add_server(mut self, url: &str, description: Option<&str>) -> Self {
self.servers.push(ServerConfig {
url: url.to_string(),
description: description.map(|s| s.to_string()),
variables: None,
});
self
}
pub fn add_security_scheme(mut self, name: &str, scheme: SecurityScheme) -> Self {
self.security_schemes.insert(name.to_string(), scheme);
self
}
pub fn add_tag(mut self, name: &str, description: Option<&str>) -> Self {
self.tags.push(TagConfig {
name: name.to_string(),
description: description.map(|s| s.to_string()),
external_docs: None,
});
self
}
}