There seems to be a bug in how oneOf
code gets generated in OpenAPI >6.0.
The type gets generated as an empty struct instead of swagger::OneOf<A, B>
as it was in 5.4
generate-540: | |
docker run --rm \ | |
-v $(PWD):/local openapitools/openapi-generator-cli:v5.4.0 generate \ | |
-i /local/test.yaml \ | |
--generator-name rust-server \ | |
--output /local/openapi \ | |
--global-property models,modelDocs=false,supportingFiles | |
mv openapi/src/models.rs test-540.rs | |
rm -rf openapi | |
generate-710: | |
docker run --rm \ | |
-v $(PWD):/local openapitools/openapi-generator-cli:v7.1.0 generate \ | |
-i /local/test.yaml \ | |
--generator-name rust-server \ | |
--output /local/openapi \ | |
--global-property models,modelDocs=false,supportingFiles | |
mv openapi/src/models.rs test-710.rs | |
rm -rf openapi | |
generate-latest: | |
docker run --rm \ | |
-v $(PWD):/local openapitools/openapi-generator-cli:latest generate \ | |
-i /local/test.yaml \ | |
--generator-name rust-server \ | |
--output /local/openapi \ | |
--global-property models,modelDocs=false,supportingFiles | |
mv openapi/src/models.rs test-latest.rs | |
rm -rf openapi |
#![allow(unused_qualifications)] | |
use crate::models; | |
#[cfg(any(feature = "client", feature = "server"))] | |
use crate::header; | |
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] | |
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] | |
pub struct Test { | |
#[serde(rename = "something")] | |
#[serde(skip_serializing_if="Option::is_none")] | |
pub something: Option<swagger::OneOf2<String,i32>>, | |
#[serde(rename = "something_else")] | |
#[serde(skip_serializing_if="Option::is_none")] | |
pub something_else: Option<String>, | |
} | |
impl Test { | |
pub fn new() -> Test { | |
Test { | |
something: None, | |
something_else: None, | |
} | |
} | |
} | |
/// Converts the Test value to the Query Parameters representation (style=form, explode=false) | |
/// specified in https://swagger.io/docs/specification/serialization/ | |
/// Should be implemented in a serde serializer | |
impl std::string::ToString for Test { | |
fn to_string(&self) -> String { | |
let mut params: Vec<String> = vec![]; | |
// Skipping something in query parameter serialization | |
if let Some(ref something_else) = self.something_else { | |
params.push("something_else".to_string()); | |
params.push(something_else.to_string()); | |
} | |
params.join(",").to_string() | |
} | |
} | |
/// Converts Query Parameters representation (style=form, explode=false) to a Test value | |
/// as specified in https://swagger.io/docs/specification/serialization/ | |
/// Should be implemented in a serde deserializer | |
impl std::str::FromStr for Test { | |
type Err = String; | |
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { | |
#[derive(Default)] | |
// An intermediate representation of the struct to use for parsing. | |
struct IntermediateRep { | |
pub something: Vec<swagger::OneOf2<String,i32>>, | |
pub something_else: Vec<String>, | |
} | |
let mut intermediate_rep = IntermediateRep::default(); | |
// Parse into intermediate representation | |
let mut string_iter = s.split(',').into_iter(); | |
let mut key_result = string_iter.next(); | |
while key_result.is_some() { | |
let val = match string_iter.next() { | |
Some(x) => x, | |
None => return std::result::Result::Err("Missing value while parsing Test".to_string()) | |
}; | |
if let Some(key) = key_result { | |
match key { | |
"something" => intermediate_rep.something.push(<swagger::OneOf2<String,i32> as std::str::FromStr>::from_str(val).map_err(|x| format!("{}", x))?), | |
"something_else" => intermediate_rep.something_else.push(<String as std::str::FromStr>::from_str(val).map_err(|x| format!("{}", x))?), | |
_ => return std::result::Result::Err("Unexpected key while parsing Test".to_string()) | |
} | |
} | |
// Get the next key | |
key_result = string_iter.next(); | |
} | |
// Use the intermediate representation to return the struct | |
std::result::Result::Ok(Test { | |
something: intermediate_rep.something.into_iter().next(), | |
something_else: intermediate_rep.something_else.into_iter().next(), | |
}) | |
} | |
} | |
// Methods for converting between header::IntoHeaderValue<Test> and hyper::header::HeaderValue | |
#[cfg(any(feature = "client", feature = "server"))] | |
impl std::convert::TryFrom<header::IntoHeaderValue<Test>> for hyper::header::HeaderValue { | |
type Error = String; | |
fn try_from(hdr_value: header::IntoHeaderValue<Test>) -> std::result::Result<Self, Self::Error> { | |
let hdr_value = hdr_value.to_string(); | |
match hyper::header::HeaderValue::from_str(&hdr_value) { | |
std::result::Result::Ok(value) => std::result::Result::Ok(value), | |
std::result::Result::Err(e) => std::result::Result::Err( | |
format!("Invalid header value for Test - value: {} is invalid {}", | |
hdr_value, e)) | |
} | |
} | |
} | |
#[cfg(any(feature = "client", feature = "server"))] | |
impl std::convert::TryFrom<hyper::header::HeaderValue> for header::IntoHeaderValue<Test> { | |
type Error = String; | |
fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result<Self, Self::Error> { | |
match hdr_value.to_str() { | |
std::result::Result::Ok(value) => { | |
match <Test as std::str::FromStr>::from_str(value) { | |
std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), | |
std::result::Result::Err(err) => std::result::Result::Err( | |
format!("Unable to convert header value '{}' into Test - {}", | |
value, err)) | |
} | |
}, | |
std::result::Result::Err(e) => std::result::Result::Err( | |
format!("Unable to convert header: {:?} to string: {}", | |
hdr_value, e)) | |
} | |
} | |
} | |
#![allow(unused_qualifications)] | |
use validator::Validate; | |
use crate::models; | |
#[cfg(any(feature = "client", feature = "server"))] | |
use crate::header; | |
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] | |
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] | |
pub struct Test { | |
#[serde(rename = "something")] | |
#[serde(skip_serializing_if="Option::is_none")] | |
pub something: Option<models::TestSomething>, | |
#[serde(rename = "something_else")] | |
#[serde(skip_serializing_if="Option::is_none")] | |
pub something_else: Option<String>, | |
} | |
impl Test { | |
#[allow(clippy::new_without_default)] | |
pub fn new() -> Test { | |
Test { | |
something: None, | |
something_else: None, | |
} | |
} | |
} | |
/// Converts the Test value to the Query Parameters representation (style=form, explode=false) | |
/// specified in https://swagger.io/docs/specification/serialization/ | |
/// Should be implemented in a serde serializer | |
impl std::string::ToString for Test { | |
fn to_string(&self) -> String { | |
let params: Vec<Option<String>> = vec![ | |
// Skipping something in query parameter serialization | |
self.something_else.as_ref().map(|something_else| { | |
vec![ | |
"something_else".to_string(), | |
something_else.to_string(), | |
].join(",") | |
}), | |
]; | |
params.into_iter().flatten().collect::<Vec<_>>().join(",") | |
} | |
} | |
/// Converts Query Parameters representation (style=form, explode=false) to a Test value | |
/// as specified in https://swagger.io/docs/specification/serialization/ | |
/// Should be implemented in a serde deserializer | |
impl std::str::FromStr for Test { | |
type Err = String; | |
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { | |
/// An intermediate representation of the struct to use for parsing. | |
#[derive(Default)] | |
#[allow(dead_code)] | |
struct IntermediateRep { | |
pub something: Vec<models::TestSomething>, | |
pub something_else: Vec<String>, | |
} | |
let mut intermediate_rep = IntermediateRep::default(); | |
// Parse into intermediate representation | |
let mut string_iter = s.split(','); | |
let mut key_result = string_iter.next(); | |
while key_result.is_some() { | |
let val = match string_iter.next() { | |
Some(x) => x, | |
None => return std::result::Result::Err("Missing value while parsing Test".to_string()) | |
}; | |
if let Some(key) = key_result { | |
#[allow(clippy::match_single_binding)] | |
match key { | |
#[allow(clippy::redundant_clone)] | |
"something" => intermediate_rep.something.push(<models::TestSomething as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?), | |
#[allow(clippy::redundant_clone)] | |
"something_else" => intermediate_rep.something_else.push(<String as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?), | |
_ => return std::result::Result::Err("Unexpected key while parsing Test".to_string()) | |
} | |
} | |
// Get the next key | |
key_result = string_iter.next(); | |
} | |
// Use the intermediate representation to return the struct | |
std::result::Result::Ok(Test { | |
something: intermediate_rep.something.into_iter().next(), | |
something_else: intermediate_rep.something_else.into_iter().next(), | |
}) | |
} | |
} | |
// Methods for converting between header::IntoHeaderValue<Test> and hyper::header::HeaderValue | |
#[cfg(any(feature = "client", feature = "server"))] | |
impl std::convert::TryFrom<header::IntoHeaderValue<Test>> for hyper::header::HeaderValue { | |
type Error = String; | |
fn try_from(hdr_value: header::IntoHeaderValue<Test>) -> std::result::Result<Self, Self::Error> { | |
let hdr_value = hdr_value.to_string(); | |
match hyper::header::HeaderValue::from_str(&hdr_value) { | |
std::result::Result::Ok(value) => std::result::Result::Ok(value), | |
std::result::Result::Err(e) => std::result::Result::Err( | |
format!("Invalid header value for Test - value: {} is invalid {}", | |
hdr_value, e)) | |
} | |
} | |
} | |
#[cfg(any(feature = "client", feature = "server"))] | |
impl std::convert::TryFrom<hyper::header::HeaderValue> for header::IntoHeaderValue<Test> { | |
type Error = String; | |
fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result<Self, Self::Error> { | |
match hdr_value.to_str() { | |
std::result::Result::Ok(value) => { | |
match <Test as std::str::FromStr>::from_str(value) { | |
std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), | |
std::result::Result::Err(err) => std::result::Result::Err( | |
format!("Unable to convert header value '{}' into Test - {}", | |
value, err)) | |
} | |
}, | |
std::result::Result::Err(e) => std::result::Result::Err( | |
format!("Unable to convert header: {:?} to string: {}", | |
hdr_value, e)) | |
} | |
} | |
} | |
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] | |
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] | |
pub struct TestSomething { | |
} | |
impl TestSomething { | |
#[allow(clippy::new_without_default)] | |
pub fn new() -> TestSomething { | |
TestSomething { | |
} | |
} | |
} | |
/// Converts the TestSomething value to the Query Parameters representation (style=form, explode=false) | |
/// specified in https://swagger.io/docs/specification/serialization/ | |
/// Should be implemented in a serde serializer | |
impl std::string::ToString for TestSomething { | |
fn to_string(&self) -> String { | |
let params: Vec<Option<String>> = vec![ | |
]; | |
params.into_iter().flatten().collect::<Vec<_>>().join(",") | |
} | |
} | |
/// Converts Query Parameters representation (style=form, explode=false) to a TestSomething value | |
/// as specified in https://swagger.io/docs/specification/serialization/ | |
/// Should be implemented in a serde deserializer | |
impl std::str::FromStr for TestSomething { | |
type Err = String; | |
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { | |
/// An intermediate representation of the struct to use for parsing. | |
#[derive(Default)] | |
#[allow(dead_code)] | |
struct IntermediateRep { | |
} | |
let mut intermediate_rep = IntermediateRep::default(); | |
// Parse into intermediate representation | |
let mut string_iter = s.split(','); | |
let mut key_result = string_iter.next(); | |
while key_result.is_some() { | |
let val = match string_iter.next() { | |
Some(x) => x, | |
None => return std::result::Result::Err("Missing value while parsing TestSomething".to_string()) | |
}; | |
if let Some(key) = key_result { | |
#[allow(clippy::match_single_binding)] | |
match key { | |
_ => return std::result::Result::Err("Unexpected key while parsing TestSomething".to_string()) | |
} | |
} | |
// Get the next key | |
key_result = string_iter.next(); | |
} | |
// Use the intermediate representation to return the struct | |
std::result::Result::Ok(TestSomething { | |
}) | |
} | |
} | |
// Methods for converting between header::IntoHeaderValue<TestSomething> and hyper::header::HeaderValue | |
#[cfg(any(feature = "client", feature = "server"))] | |
impl std::convert::TryFrom<header::IntoHeaderValue<TestSomething>> for hyper::header::HeaderValue { | |
type Error = String; | |
fn try_from(hdr_value: header::IntoHeaderValue<TestSomething>) -> std::result::Result<Self, Self::Error> { | |
let hdr_value = hdr_value.to_string(); | |
match hyper::header::HeaderValue::from_str(&hdr_value) { | |
std::result::Result::Ok(value) => std::result::Result::Ok(value), | |
std::result::Result::Err(e) => std::result::Result::Err( | |
format!("Invalid header value for TestSomething - value: {} is invalid {}", | |
hdr_value, e)) | |
} | |
} | |
} | |
#[cfg(any(feature = "client", feature = "server"))] | |
impl std::convert::TryFrom<hyper::header::HeaderValue> for header::IntoHeaderValue<TestSomething> { | |
type Error = String; | |
fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result<Self, Self::Error> { | |
match hdr_value.to_str() { | |
std::result::Result::Ok(value) => { | |
match <TestSomething as std::str::FromStr>::from_str(value) { | |
std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), | |
std::result::Result::Err(err) => std::result::Result::Err( | |
format!("Unable to convert header value '{}' into TestSomething - {}", | |
value, err)) | |
} | |
}, | |
std::result::Result::Err(e) => std::result::Result::Err( | |
format!("Unable to convert header: {:?} to string: {}", | |
hdr_value, e)) | |
} | |
} | |
} | |
#![allow(unused_qualifications)] | |
use validator::Validate; | |
use crate::models; | |
#[cfg(any(feature = "client", feature = "server"))] | |
use crate::header; | |
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] | |
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] | |
pub struct Test { | |
#[serde(rename = "something")] | |
#[serde(skip_serializing_if="Option::is_none")] | |
pub something: Option<models::TestSomething>, | |
#[serde(rename = "something_else")] | |
#[serde(skip_serializing_if="Option::is_none")] | |
pub something_else: Option<String>, | |
} | |
impl Test { | |
#[allow(clippy::new_without_default)] | |
pub fn new() -> Test { | |
Test { | |
something: None, | |
something_else: None, | |
} | |
} | |
} | |
/// Converts the Test value to the Query Parameters representation (style=form, explode=false) | |
/// specified in https://swagger.io/docs/specification/serialization/ | |
/// Should be implemented in a serde serializer | |
impl std::string::ToString for Test { | |
fn to_string(&self) -> String { | |
let params: Vec<Option<String>> = vec![ | |
// Skipping something in query parameter serialization | |
self.something_else.as_ref().map(|something_else| { | |
[ | |
"something_else".to_string(), | |
something_else.to_string(), | |
].join(",") | |
}), | |
]; | |
params.into_iter().flatten().collect::<Vec<_>>().join(",") | |
} | |
} | |
/// Converts Query Parameters representation (style=form, explode=false) to a Test value | |
/// as specified in https://swagger.io/docs/specification/serialization/ | |
/// Should be implemented in a serde deserializer | |
impl std::str::FromStr for Test { | |
type Err = String; | |
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { | |
/// An intermediate representation of the struct to use for parsing. | |
#[derive(Default)] | |
#[allow(dead_code)] | |
struct IntermediateRep { | |
pub something: Vec<models::TestSomething>, | |
pub something_else: Vec<String>, | |
} | |
let mut intermediate_rep = IntermediateRep::default(); | |
// Parse into intermediate representation | |
let mut string_iter = s.split(','); | |
let mut key_result = string_iter.next(); | |
while key_result.is_some() { | |
let val = match string_iter.next() { | |
Some(x) => x, | |
None => return std::result::Result::Err("Missing value while parsing Test".to_string()) | |
}; | |
if let Some(key) = key_result { | |
#[allow(clippy::match_single_binding)] | |
match key { | |
#[allow(clippy::redundant_clone)] | |
"something" => intermediate_rep.something.push(<models::TestSomething as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?), | |
#[allow(clippy::redundant_clone)] | |
"something_else" => intermediate_rep.something_else.push(<String as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?), | |
_ => return std::result::Result::Err("Unexpected key while parsing Test".to_string()) | |
} | |
} | |
// Get the next key | |
key_result = string_iter.next(); | |
} | |
// Use the intermediate representation to return the struct | |
std::result::Result::Ok(Test { | |
something: intermediate_rep.something.into_iter().next(), | |
something_else: intermediate_rep.something_else.into_iter().next(), | |
}) | |
} | |
} | |
// Methods for converting between header::IntoHeaderValue<Test> and hyper::header::HeaderValue | |
#[cfg(any(feature = "client", feature = "server"))] | |
impl std::convert::TryFrom<header::IntoHeaderValue<Test>> for hyper::header::HeaderValue { | |
type Error = String; | |
fn try_from(hdr_value: header::IntoHeaderValue<Test>) -> std::result::Result<Self, Self::Error> { | |
let hdr_value = hdr_value.to_string(); | |
match hyper::header::HeaderValue::from_str(&hdr_value) { | |
std::result::Result::Ok(value) => std::result::Result::Ok(value), | |
std::result::Result::Err(e) => std::result::Result::Err( | |
format!("Invalid header value for Test - value: {} is invalid {}", | |
hdr_value, e)) | |
} | |
} | |
} | |
#[cfg(any(feature = "client", feature = "server"))] | |
impl std::convert::TryFrom<hyper::header::HeaderValue> for header::IntoHeaderValue<Test> { | |
type Error = String; | |
fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result<Self, Self::Error> { | |
match hdr_value.to_str() { | |
std::result::Result::Ok(value) => { | |
match <Test as std::str::FromStr>::from_str(value) { | |
std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), | |
std::result::Result::Err(err) => std::result::Result::Err( | |
format!("Unable to convert header value '{}' into Test - {}", | |
value, err)) | |
} | |
}, | |
std::result::Result::Err(e) => std::result::Result::Err( | |
format!("Unable to convert header: {:?} to string: {}", | |
hdr_value, e)) | |
} | |
} | |
} | |
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] | |
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] | |
pub struct TestSomething { | |
} | |
impl TestSomething { | |
#[allow(clippy::new_without_default)] | |
pub fn new() -> TestSomething { | |
TestSomething { | |
} | |
} | |
} | |
/// Converts the TestSomething value to the Query Parameters representation (style=form, explode=false) | |
/// specified in https://swagger.io/docs/specification/serialization/ | |
/// Should be implemented in a serde serializer | |
impl std::string::ToString for TestSomething { | |
fn to_string(&self) -> String { | |
let params: Vec<Option<String>> = vec![ | |
]; | |
params.into_iter().flatten().collect::<Vec<_>>().join(",") | |
} | |
} | |
/// Converts Query Parameters representation (style=form, explode=false) to a TestSomething value | |
/// as specified in https://swagger.io/docs/specification/serialization/ | |
/// Should be implemented in a serde deserializer | |
impl std::str::FromStr for TestSomething { | |
type Err = String; | |
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { | |
/// An intermediate representation of the struct to use for parsing. | |
#[derive(Default)] | |
#[allow(dead_code)] | |
struct IntermediateRep { | |
} | |
let mut intermediate_rep = IntermediateRep::default(); | |
// Parse into intermediate representation | |
let mut string_iter = s.split(','); | |
let mut key_result = string_iter.next(); | |
while key_result.is_some() { | |
let val = match string_iter.next() { | |
Some(x) => x, | |
None => return std::result::Result::Err("Missing value while parsing TestSomething".to_string()) | |
}; | |
if let Some(key) = key_result { | |
#[allow(clippy::match_single_binding)] | |
match key { | |
_ => return std::result::Result::Err("Unexpected key while parsing TestSomething".to_string()) | |
} | |
} | |
// Get the next key | |
key_result = string_iter.next(); | |
} | |
// Use the intermediate representation to return the struct | |
std::result::Result::Ok(TestSomething { | |
}) | |
} | |
} | |
// Methods for converting between header::IntoHeaderValue<TestSomething> and hyper::header::HeaderValue | |
#[cfg(any(feature = "client", feature = "server"))] | |
impl std::convert::TryFrom<header::IntoHeaderValue<TestSomething>> for hyper::header::HeaderValue { | |
type Error = String; | |
fn try_from(hdr_value: header::IntoHeaderValue<TestSomething>) -> std::result::Result<Self, Self::Error> { | |
let hdr_value = hdr_value.to_string(); | |
match hyper::header::HeaderValue::from_str(&hdr_value) { | |
std::result::Result::Ok(value) => std::result::Result::Ok(value), | |
std::result::Result::Err(e) => std::result::Result::Err( | |
format!("Invalid header value for TestSomething - value: {} is invalid {}", | |
hdr_value, e)) | |
} | |
} | |
} | |
#[cfg(any(feature = "client", feature = "server"))] | |
impl std::convert::TryFrom<hyper::header::HeaderValue> for header::IntoHeaderValue<TestSomething> { | |
type Error = String; | |
fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result<Self, Self::Error> { | |
match hdr_value.to_str() { | |
std::result::Result::Ok(value) => { | |
match <TestSomething as std::str::FromStr>::from_str(value) { | |
std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), | |
std::result::Result::Err(err) => std::result::Result::Err( | |
format!("Unable to convert header value '{}' into TestSomething - {}", | |
value, err)) | |
} | |
}, | |
std::result::Result::Err(e) => std::result::Result::Err( | |
format!("Unable to convert header: {:?} to string: {}", | |
hdr_value, e)) | |
} | |
} | |
} | |
openapi: 3.0.3 | |
info: | |
title: Test | |
version: "0.2" | |
paths: | |
/a: | |
post: | |
summary: Test | |
requestBody: | |
content: | |
application/json: | |
schema: | |
$ref: '#/components/schemas/Test' | |
responses: | |
200: | |
description: Ok | |
components: | |
schemas: | |
Test: | |
type: object | |
properties: | |
something: | |
oneOf: | |
- type: string | |
- type: integer | |
something_else: | |
type: string |