use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OpenApiDoc {
pub openapi: String,
pub info: InfoObject,
pub servers: Vec<ServerObject>,
pub paths: HashMap<String, PathItem>,
pub components: ComponentsObject,
pub tags: Vec<TagObject>,
}
impl OpenApiDoc {
pub fn new(title: &str, version: &str) -> Self {
Self {
openapi: "3.0.3".to_string(),
info: InfoObject {
title: title.to_string(),
description: None,
version: version.to_string(),
},
servers: vec![],
paths: HashMap::new(),
components: ComponentsObject::new(),
tags: vec![],
}
}
pub fn server(mut self, url: &str) -> Self {
self.servers.push(ServerObject {
url: url.to_string(),
description: None,
});
self
}
pub fn path(mut self, path: &str, item: PathItem) -> Self {
self.paths.insert(path.to_string(), item);
self
}
pub fn tag(mut self, name: &str, description: &str) -> Self {
self.tags.push(TagObject {
name: name.to_string(),
description: Some(description.to_string()),
});
self
}
pub fn schema(mut self, name: &str, schema: SchemaObject) -> Self {
self.components.schemas.insert(name.to_string(), schema);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InfoObject {
pub title: String,
pub description: Option<String>,
pub version: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerObject {
pub url: String,
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PathItem {
#[serde(skip_serializing_if = "Option::is_none")]
pub get: Option<OperationObject>,
#[serde(skip_serializing_if = "Option::is_none")]
pub post: Option<OperationObject>,
#[serde(skip_serializing_if = "Option::is_none")]
pub put: Option<OperationObject>,
#[serde(skip_serializing_if = "Option::is_none")]
pub delete: Option<OperationObject>,
#[serde(skip_serializing_if = "Option::is_none")]
pub patch: Option<OperationObject>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OperationObject {
pub summary: Option<String>,
pub description: Option<String>,
pub operation_id: Option<String>,
pub tags: Option<Vec<String>>,
pub request_body: Option<RequestBodyObject>,
pub responses: HashMap<String, ResponseObject>,
pub parameters: Option<Vec<ParameterObject>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RequestBodyObject {
pub required: bool,
pub content: HashMap<String, MediaTypeObject>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediaTypeObject {
pub schema: SchemaObject,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResponseObject {
pub description: String,
pub content: Option<HashMap<String, MediaTypeObject>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParameterObject {
pub name: String,
pub location: String, pub required: bool,
pub schema: SchemaObject,
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentsObject {
pub schemas: HashMap<String, SchemaObject>,
#[serde(skip_serializing_if = "Option::is_none")]
pub security_schemes: Option<HashMap<String, SecuritySchemeObject>>,
}
impl ComponentsObject {
pub fn new() -> Self {
Self {
schemas: HashMap::new(),
security_schemes: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchemaObject {
pub type_: Option<String>,
pub format: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub properties: Option<HashMap<String, SchemaObject>>,
pub items: Option<Box<SchemaObject>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub required: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecuritySchemeObject {
pub type_: String,
pub scheme: Option<String>,
pub bearer_format: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TagObject {
pub name: String,
pub description: Option<String>,
}
pub struct OpenApiBuilder {
doc: OpenApiDoc,
}
impl OpenApiBuilder {
pub fn new(title: &str, version: &str) -> Self {
Self {
doc: OpenApiDoc::new(title, version),
}
}
pub fn server(mut self, url: &str) -> Self {
self.doc = self.doc.server(url);
self
}
pub fn tag(mut self, name: &str, description: &str) -> Self {
self.doc = self.doc.tag(name, description);
self
}
pub fn path_get(mut self, path: &str, summary: &str) -> Self {
let mut item = PathItem::default();
item.get = Some(OperationObject {
summary: Some(summary.to_string()),
description: None,
operation_id: None,
tags: None,
request_body: None,
responses: HashMap::new(),
parameters: None,
});
self.doc = self.doc.path(path, item);
self
}
pub fn schema<T: serde::Serialize>(mut self, name: &str) -> Self {
let schema = SchemaObject {
type_: Some("object".to_string()),
format: None,
properties: None,
items: None,
required: None,
};
self.doc = self.doc.schema(name, schema);
self
}
pub fn build(self) -> OpenApiDoc {
self.doc
}
}
impl Default for PathItem {
fn default() -> Self {
Self {
get: None,
post: None,
put: None,
delete: None,
patch: None,
}
}
}