use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::BTreeMap;
use super::{
builder, content::Content, example::Example, extensions::Extensions, path::ParameterStyle,
set_value, Deprecated, Object, RefOr, Schema, Type,
};
builder! {
HeaderBuilder;
#[non_exhaustive]
#[derive(Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct Header {
#[serde(skip_serializing_if = "Option::is_none")]
pub schema: Option<RefOr<Schema>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deprecated: Option<Deprecated>,
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<ParameterStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub explode: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub example: Option<Value>,
#[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
pub examples: BTreeMap<String, RefOr<Example>>,
#[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
pub content: BTreeMap<String, RefOr<Content>>,
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub extensions: Option<Extensions>,
}
}
impl Header {
pub fn new<C: Into<RefOr<Schema>>>(component: C) -> Self {
Self {
schema: Some(component.into()),
..Default::default()
}
}
}
impl Default for Header {
fn default() -> Self {
Self {
schema: Some(Object::with_type(Type::String).into()),
description: None,
deprecated: None,
style: None,
explode: None,
example: None,
examples: BTreeMap::new(),
content: BTreeMap::new(),
extensions: None,
}
}
}
impl HeaderBuilder {
pub fn schema<I: Into<RefOr<Schema>>>(mut self, component: Option<I>) -> Self {
set_value!(self schema component.map(Into::into))
}
pub fn content<S: Into<String>, C: Into<RefOr<Content>>>(
mut self,
content_type: S,
content: C,
) -> Self {
self.content.insert(content_type.into(), content.into());
self
}
pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
set_value!(self description description.map(|description| description.into()))
}
pub fn deprecated(mut self, deprecated: Option<Deprecated>) -> Self {
set_value!(self deprecated deprecated)
}
pub fn style(mut self, style: Option<ParameterStyle>) -> Self {
set_value!(self style style)
}
pub fn explode(mut self, explode: Option<bool>) -> Self {
set_value!(self explode explode)
}
pub fn example(mut self, example: Option<Value>) -> Self {
set_value!(self example example)
}
pub fn examples_from_iter<
E: IntoIterator<Item = (N, V)>,
N: Into<String>,
V: Into<RefOr<Example>>,
>(
mut self,
examples: E,
) -> Self {
self.examples.extend(
examples
.into_iter()
.map(|(name, example)| (name.into(), example.into())),
);
self
}
pub fn content_from_iter<
E: IntoIterator<Item = (N, V)>,
N: Into<String>,
V: Into<RefOr<Content>>,
>(
mut self,
content: E,
) -> Self {
self.content.extend(
content
.into_iter()
.map(|(name, content)| (name.into(), content.into())),
);
self
}
pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
set_value!(self extensions extensions)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
use crate::openapi::content::ContentBuilder;
use crate::openapi::example::ExampleBuilder;
#[test]
fn test_header_builder_and_serialization() {
let header = HeaderBuilder::new()
.description(Some("custom header"))
.deprecated(Some(Deprecated::True))
.style(Some(ParameterStyle::Simple))
.explode(Some(true))
.example(Some(json!("example-value")))
.build();
insta::assert_json_snapshot!(&header, @r#"
{
"schema": {
"type": "string"
},
"description": "custom header",
"deprecated": true,
"style": "simple",
"explode": true,
"example": "example-value"
}
"#);
}
#[test]
fn test_header_with_content_and_examples() {
let content = ContentBuilder::new()
.schema(Some(Object::with_type(Type::Integer)))
.build();
let example = ExampleBuilder::new().value(Some(json!("test"))).build();
let header = Header {
schema: None,
content: BTreeMap::from_iter([("application/json".to_string(), content.into())]),
examples: BTreeMap::from_iter([("test_example".to_string(), example.into())]),
..Default::default()
};
insta::assert_json_snapshot!(&header, @r#"
{
"examples": {
"test_example": {
"value": "test"
}
},
"content": {
"application/json": {
"schema": {
"type": "integer"
}
}
}
}
"#);
}
}