Skip to content

Commit

Permalink
feat: Support deserializing other versions in 3.0.x (#578)
Browse files Browse the repository at this point in the history
Add support for deserializing other OpenAPI `3.0.x` formats than the default `3.0.3`
  • Loading branch information
siketyan authored Apr 15, 2023
1 parent dc0cf3c commit 96feca3
Showing 1 changed file with 59 additions and 2 deletions.
61 changes: 59 additions & 2 deletions utoipa/src/openapi.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Rust implementation of Openapi Spec V3.
use serde::{de::Visitor, Deserialize, Serialize, Serializer};
use serde::{de::Error, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::Formatter;

pub use self::{
content::{Content, ContentBuilder},
Expand Down Expand Up @@ -260,7 +261,7 @@ impl OpenApiBuilder {
/// Represents available [OpenAPI versions][version].
///
/// [version]: <https://spec.openapis.org/oas/latest.html#versions>
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
#[derive(Serialize, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub enum OpenApiVersion {
/// Will serialize to `3.0.3` the latest from 3.0 serde.
Expand All @@ -274,6 +275,50 @@ impl Default for OpenApiVersion {
}
}

impl<'de> Deserialize<'de> for OpenApiVersion {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct VersionVisitor;

impl<'v> Visitor<'v> for VersionVisitor {
type Value = OpenApiVersion;

fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("a version string in 3, 3.0, or 3.0.x format")
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
self.visit_string(v.to_string())
}

fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: Error,
{
let parts = v.split('.').collect::<Vec<_>>();
if parts.len() > 3 || parts.len() < 1 {
return Err(E::custom(format!(
"Invalid format of OpenAPI version: {}",
v,
)));
}

Ok(match (parts[0], parts.get(1).map(|p| *p).unwrap_or("0")) {
("3", "0") => Self::Value::Version3,
_ => return Err(E::custom(format!("Unsupported version: {}", &v))),
})
}
}

deserializer.deserialize_string(VersionVisitor)
}
}

/// Value used to indicate whether reusable schema, parameter or operation is deprecated.
///
/// The value will serialize to boolean.
Expand Down Expand Up @@ -688,4 +733,16 @@ mod tests {
)
)
}

#[test]
fn deserialize_other_versions() {
[r#""3.0.3""#, r#""3.0.0""#, r#""3.0""#, r#""3""#]
.iter()
.for_each(|v| {
assert!(matches!(
serde_json::from_str::<OpenApiVersion>(v).unwrap(),
OpenApiVersion::Version3,
));
});
}
}

0 comments on commit 96feca3

Please sign in to comment.