use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct OpenApiPath {
pub path: String,
pub method: String,
pub operation: OpenApiOperation,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct OpenApiOperation {
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "operationId", skip_serializing_if = "Option::is_none")]
pub operation_id: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub tags: Vec<String>,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub deprecated: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub parameters: Vec<OpenApiParameter>,
#[serde(rename = "requestBody", skip_serializing_if = "Option::is_none")]
pub request_body: Option<Value>,
#[serde(default)]
pub responses: serde_json::Map<String, Value>,
#[serde(flatten)]
pub extra: serde_json::Map<String, Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct OpenApiParameter {
pub name: String,
#[serde(rename = "in")]
pub location: String,
#[serde(default)]
pub required: bool,
#[serde(default)]
pub schema: Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(flatten)]
pub extra: serde_json::Map<String, Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct OpenApiSchema {
pub name: String,
pub schema: Value,
}
impl OpenApiPath {
pub fn new(path: impl Into<String>, method: impl Into<String>) -> Self {
Self {
path: path.into(),
method: method.into().to_lowercase(),
operation: OpenApiOperation::default(),
}
}
pub fn with_operation(mut self, operation: OpenApiOperation) -> Self {
self.operation = operation;
self
}
}
impl Default for OpenApiOperation {
fn default() -> Self {
Self {
summary: None,
description: None,
operation_id: None,
tags: Vec::new(),
deprecated: false,
parameters: Vec::new(),
request_body: None,
responses: serde_json::Map::new(),
extra: serde_json::Map::new(),
}
}
}
impl OpenApiOperation {
pub fn new(summary: impl Into<String>) -> Self {
Self {
summary: Some(summary.into()),
..Default::default()
}
}
pub fn with_id(mut self, id: impl Into<String>) -> Self {
self.operation_id = Some(id.into());
self
}
pub fn with_description(mut self, desc: impl Into<String>) -> Self {
self.description = Some(desc.into());
self
}
pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
self.tags.push(tag.into());
self
}
pub fn with_tags(mut self, tags: impl IntoIterator<Item = impl Into<String>>) -> Self {
self.tags.extend(tags.into_iter().map(|t| t.into()));
self
}
pub fn deprecated(mut self) -> Self {
self.deprecated = true;
self
}
pub fn with_parameter(mut self, param: OpenApiParameter) -> Self {
self.parameters.push(param);
self
}
pub fn with_response(mut self, status: impl Into<String>, response: Value) -> Self {
self.responses.insert(status.into(), response);
self
}
}
impl OpenApiParameter {
pub fn path(name: impl Into<String>) -> Self {
Self {
name: name.into(),
location: "path".to_string(),
required: true, schema: serde_json::json!({"type": "string"}),
description: None,
extra: serde_json::Map::new(),
}
}
pub fn query(name: impl Into<String>, required: bool) -> Self {
Self {
name: name.into(),
location: "query".to_string(),
required,
schema: serde_json::json!({"type": "string"}),
description: None,
extra: serde_json::Map::new(),
}
}
pub fn header(name: impl Into<String>, required: bool) -> Self {
Self {
name: name.into(),
location: "header".to_string(),
required,
schema: serde_json::json!({"type": "string"}),
description: None,
extra: serde_json::Map::new(),
}
}
pub fn with_schema(mut self, schema: Value) -> Self {
self.schema = schema;
self
}
pub fn with_description(mut self, desc: impl Into<String>) -> Self {
self.description = Some(desc.into());
self
}
}
impl OpenApiSchema {
pub fn new(name: impl Into<String>, schema: Value) -> Self {
Self {
name: name.into(),
schema,
}
}
}