Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adding support to parse discriminator field in ObjectSchema #138

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions crates/oas3/src/spec/discriminator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//! Schema specification for [OpenAPI 3.1](https://github.com/OAI/OpenAPI-Specification/blob/HEAD/versions/3.1.0.md)

use std::collections::BTreeMap;

use serde::{Deserialize, Serialize};

/// The discriminator is a specific object in a schema which is used to inform the consumer of
/// the document of an alternative schema based on the value associated with it.
///
/// See <https://spec.openapis.org/oas/v3.1.0#discriminator-object>
#[derive(Clone, Debug, PartialEq, Default, Deserialize, Serialize)]
pub struct Discriminator {
/// The name of the property in the payload that will hold the discriminator value.
#[serde(rename = "propertyName")]
pub property_name: String,

/// An object to hold mappings between payload values and schema names or references
///
/// When using the discriminator, inline schemas will not be considered
#[serde(skip_serializing_if = "Option::is_none")]
pub mapping: Option<BTreeMap<String, String>>,
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn discriminator_property_name_parsed_correctly() {
let spec = "propertyName: testName";
let discriminator = serde_yml::from_str::<Discriminator>(spec).unwrap();
assert_eq!("testName", discriminator.property_name);
assert!(discriminator.mapping.is_none());
}

#[test]
fn discriminator_mapping_parsed_correctly() {
let spec = indoc::indoc! {"
propertyName: petType
mapping:
dog: '#/components/schemas/Dog'
cat: '#/components/schemas/Cat'
monster: 'https://gigantic-server.com/schemas/Monster/schema.json'
"};
let discriminator = serde_yml::from_str::<Discriminator>(spec).unwrap();

assert_eq!("petType", discriminator.property_name);
let mapping = discriminator.mapping.unwrap();

assert_eq!("#/components/schemas/Dog", mapping.get("dog").unwrap());
assert_eq!("#/components/schemas/Cat", mapping.get("cat").unwrap());
assert_eq!(
"https://gigantic-server.com/schemas/Monster/schema.json",
mapping.get("monster").unwrap()
);
}
}
1 change: 1 addition & 0 deletions crates/oas3/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod components;
mod contact;
mod encoding;

mod discriminator;
mod error;
mod example;
mod external_doc;
Expand Down
29 changes: 28 additions & 1 deletion crates/oas3/src/spec/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use std::{collections::BTreeMap, fmt};
use derive_more::derive::{Display, Error};
use serde::{Deserialize, Deserializer, Serialize};

use super::{spec_extensions, FromRef, ObjectOrReference, Ref, RefError, RefType, Spec};
use super::{
discriminator::Discriminator, spec_extensions, FromRef, ObjectOrReference, Ref, RefError,
RefType, Spec,
};

/// Schema errors.
#[derive(Debug, Clone, PartialEq, Display, Error)]
Expand Down Expand Up @@ -526,6 +529,12 @@ pub struct ObjectSchema {
/// See <https://github.com/OAI/OpenAPI-Specification/blob/HEAD/versions/3.1.0.md#specification-extensions>.
#[serde(flatten, with = "spec_extensions")]
pub extensions: BTreeMap<String, serde_json::Value>,

/// Discriminator for object selection based on propertyName
///
/// See <https://spec.openapis.org/oas/v3.1.0#discriminator-object>
#[serde(default, skip_serializing_if = "Option::is_none")]
pub discriminator: Option<Discriminator>,
}

impl ObjectSchema {
Expand Down Expand Up @@ -628,4 +637,22 @@ mod tests {
let schema = serde_yml::from_str::<ObjectSchema>(spec).unwrap();
assert_eq!(schema.example, Some(serde_json::Value::Null));
}

#[test]
fn discriminator_example_is_parsed_correctly() {
let spec = indoc::indoc! {"
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Lizard'
- $ref: 'https://gigantic-server.com/schemas/Monster/schema.json'
discriminator:
propertyName: petType
mapping:
dog: '#/components/schemas/Dog'
monster: 'https://gigantic-server.com/schemas/Monster/schema.json'
"};
let schema = serde_yml::from_str::<ObjectSchema>(spec).unwrap();
assert!(schema.discriminator.is_some());
}
}
Loading