use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OpenApiSpec {
pub openapi: String,
pub info: ApiInfo,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub servers: Vec<Server>,
#[serde(default)]
pub paths: HashMap<String, PathItem>,
#[serde(skip_serializing_if = "Option::is_none")]
pub components: Option<Components>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub security: Vec<SecurityRequirement>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub tags: Vec<Tag>,
#[serde(rename = "externalDocs", skip_serializing_if = "Option::is_none")]
pub external_docs: Option<ExternalDocumentation>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiInfo {
pub title: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "termsOfService", skip_serializing_if = "Option::is_none")]
pub terms_of_service: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub contact: Option<Contact>,
#[serde(skip_serializing_if = "Option::is_none")]
pub license: Option<License>,
pub version: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Contact {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct License {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Server {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub variables: Option<HashMap<String, ServerVariable>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerVariable {
pub default: String,
#[serde(rename = "enum", skip_serializing_if = "Option::is_none")]
pub enum_values: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PathItem {
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub get: Option<Operation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub put: Option<Operation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub post: Option<Operation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub delete: Option<Operation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<Operation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub head: Option<Operation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub patch: Option<Operation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trace: Option<Operation>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub parameters: Vec<Parameter>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Operation {
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub tags: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "externalDocs", skip_serializing_if = "Option::is_none")]
pub external_docs: Option<ExternalDocumentation>,
#[serde(rename = "operationId", skip_serializing_if = "Option::is_none")]
pub operation_id: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub parameters: Vec<Parameter>,
#[serde(rename = "requestBody", skip_serializing_if = "Option::is_none")]
pub request_body: Option<RequestBody>,
#[serde(default)]
pub responses: HashMap<String, Response>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub security: Vec<SecurityRequirement>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub servers: Vec<Server>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deprecated: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Parameter {
pub name: String,
#[serde(rename = "in")]
pub location: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub required: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deprecated: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub schema: Option<Schema>,
#[serde(skip_serializing_if = "Option::is_none")]
pub example: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RequestBody {
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub content: HashMap<String, MediaType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub required: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Response {
pub description: String,
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
pub headers: HashMap<String, Header>,
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
pub content: HashMap<String, MediaType>,
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
pub links: HashMap<String, Link>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Header {
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub required: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deprecated: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub schema: Option<Schema>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediaType {
#[serde(skip_serializing_if = "Option::is_none")]
pub schema: Option<Schema>,
#[serde(skip_serializing_if = "Option::is_none")]
pub example: Option<serde_json::Value>,
#[serde(skip_serializing_if = "HashMap::is_empty")]
pub examples: HashMap<String, Example>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Example {
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<serde_json::Value>,
#[serde(rename = "externalValue", skip_serializing_if = "Option::is_none")]
pub external_value: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Link {
#[serde(rename = "operationRef", skip_serializing_if = "Option::is_none")]
pub operation_ref: Option<String>,
#[serde(rename = "operationId", skip_serializing_if = "Option::is_none")]
pub operation_id: Option<String>,
#[serde(skip_serializing_if = "HashMap::is_empty")]
pub parameters: HashMap<String, serde_json::Value>,
#[serde(rename = "requestBody", skip_serializing_if = "Option::is_none")]
pub request_body: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Schema {
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub schema_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub example: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nullable: Option<bool>,
#[serde(skip_serializing_if = "HashMap::is_empty")]
pub properties: HashMap<String, Schema>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub required: Vec<String>,
#[serde(
rename = "additionalProperties",
skip_serializing_if = "Option::is_none"
)]
pub additional_properties: Option<Box<Schema>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub items: Option<Box<Schema>>,
#[serde(rename = "enum", skip_serializing_if = "Vec::is_empty")]
pub enum_values: Vec<serde_json::Value>,
#[serde(rename = "$ref", skip_serializing_if = "Option::is_none")]
pub reference: Option<String>,
#[serde(rename = "allOf", skip_serializing_if = "Vec::is_empty")]
pub all_of: Vec<Schema>,
#[serde(rename = "anyOf", skip_serializing_if = "Vec::is_empty")]
pub any_of: Vec<Schema>,
#[serde(rename = "oneOf", skip_serializing_if = "Vec::is_empty")]
pub one_of: Vec<Schema>,
#[serde(skip_serializing_if = "Option::is_none")]
pub minimum: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub maximum: Option<f64>,
#[serde(rename = "minLength", skip_serializing_if = "Option::is_none")]
pub min_length: Option<usize>,
#[serde(rename = "maxLength", skip_serializing_if = "Option::is_none")]
pub max_length: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pattern: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Components {
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
pub schemas: HashMap<String, Schema>,
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
pub responses: HashMap<String, Response>,
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
pub parameters: HashMap<String, Parameter>,
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
pub examples: HashMap<String, Example>,
#[serde(
rename = "requestBodies",
skip_serializing_if = "HashMap::is_empty",
default
)]
pub request_bodies: HashMap<String, RequestBody>,
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
pub headers: HashMap<String, Header>,
#[serde(
rename = "securitySchemes",
skip_serializing_if = "HashMap::is_empty",
default
)]
pub security_schemes: HashMap<String, SecurityScheme>,
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
pub links: HashMap<String, Link>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum SecurityScheme {
#[serde(rename = "apiKey")]
ApiKey {
name: String,
#[serde(rename = "in")]
location: String,
},
#[serde(rename = "http")]
Http {
scheme: String,
#[serde(rename = "bearerFormat", skip_serializing_if = "Option::is_none")]
bearer_format: Option<String>,
},
#[serde(rename = "oauth2")]
OAuth2 { flows: OAuth2Flows },
#[serde(rename = "openIdConnect")]
OpenIdConnect {
#[serde(rename = "openIdConnectUrl")]
open_id_connect_url: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OAuth2Flows {
#[serde(rename = "implicit", skip_serializing_if = "Option::is_none")]
pub implicit: Option<OAuth2Flow>,
#[serde(rename = "password", skip_serializing_if = "Option::is_none")]
pub password: Option<OAuth2Flow>,
#[serde(rename = "clientCredentials", skip_serializing_if = "Option::is_none")]
pub client_credentials: Option<OAuth2Flow>,
#[serde(rename = "authorizationCode", skip_serializing_if = "Option::is_none")]
pub authorization_code: Option<OAuth2Flow>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OAuth2Flow {
#[serde(rename = "authorizationUrl", skip_serializing_if = "Option::is_none")]
pub authorization_url: Option<String>,
#[serde(rename = "tokenUrl", skip_serializing_if = "Option::is_none")]
pub token_url: Option<String>,
#[serde(rename = "refreshUrl", skip_serializing_if = "Option::is_none")]
pub refresh_url: Option<String>,
pub scopes: HashMap<String, String>,
}
pub type SecurityRequirement = HashMap<String, Vec<String>>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tag {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "externalDocs", skip_serializing_if = "Option::is_none")]
pub external_docs: Option<ExternalDocumentation>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExternalDocumentation {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
impl OpenApiSpec {
pub fn new(title: &str, version: &str) -> Self {
Self {
openapi: "3.0.3".to_string(),
info: ApiInfo {
title: title.to_string(),
description: None,
terms_of_service: None,
contact: None,
license: None,
version: version.to_string(),
},
servers: Vec::new(),
paths: HashMap::new(),
components: None,
security: Vec::new(),
tags: Vec::new(),
external_docs: None,
}
}
}