Add some config for openapi3 compatibility

This commit is contained in:
Graham Esau 2019-08-05 23:30:53 +01:00
parent ef5c584118
commit 1f514f2be7
3 changed files with 108 additions and 14 deletions

View file

@ -4,19 +4,90 @@ use std::collections::BTreeMap as Map;
use std::collections::BTreeSet as Set;
use std::iter::FromIterator;
#[derive(Debug, Default)]
#[derive(Debug, PartialEq, Clone)]
pub struct SchemaSettings {
pub option_nullable: bool,
pub option_any_of_null: bool,
pub bool_schemas: BoolSchemas,
pub definitions_path: String,
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum BoolSchemas {
Enable,
AdditionalPropertiesOnly,
Disable,
}
impl Default for SchemaSettings {
fn default() -> SchemaSettings {
SchemaSettings {
option_nullable: false,
option_any_of_null: true,
bool_schemas: BoolSchemas::Enable,
definitions_path: "#/definitions/".to_owned(),
}
}
}
impl SchemaSettings {
pub fn new() -> SchemaSettings {
SchemaSettings {
..Default::default()
}
}
pub fn openapi3() -> SchemaSettings {
SchemaSettings {
option_nullable: true,
option_any_of_null: false,
bool_schemas: BoolSchemas::AdditionalPropertiesOnly,
definitions_path: "#/components/schemas/".to_owned(),
}
}
pub fn into_generator(self) -> SchemaGenerator {
SchemaGenerator::new(self)
}
}
#[derive(Debug, Default, Clone)]
pub struct SchemaGenerator {
settings: SchemaSettings,
names: Set<String>,
definitions: Map<SchemaTypeId, (String, Schema)>,
}
impl SchemaGenerator {
pub fn new() -> SchemaGenerator {
pub fn new(settings: SchemaSettings) -> SchemaGenerator {
SchemaGenerator {
settings,
..Default::default()
}
}
pub fn settings(&self) -> &SchemaSettings {
&self.settings
}
pub fn schema_for_any(&self) -> Schema {
if self.settings().bool_schemas == BoolSchemas::Enable {
true.into()
} else {
Schema::Object(Default::default())
}
}
pub fn schema_for_none(&self) -> Schema {
if self.settings().bool_schemas == BoolSchemas::Enable {
false.into()
} else {
Schema::Object(SchemaObject {
not: Some(Schema::Object(Default::default()).into()),
..Default::default()
})
}
}
pub fn subschema_for<T: ?Sized + MakeSchema>(&mut self) -> Schema {
if !T::generates_ref_schema() {
return T::make_schema(self);
@ -33,7 +104,7 @@ impl SchemaGenerator {
self.insert_new_subschema_for::<T>(type_id, name.clone());
name
});
let reference = format!("#/definitions/{}", name);
let reference = format!("{}{}", self.settings().definitions_path, name);
SchemaRef { reference }.into()
}

View file

@ -1,6 +1,6 @@
#[macro_export()]
macro_rules! schema_for {
($($type:tt)+) => {
$crate::gen::SchemaGenerator::new().into_root_schema_for::<$($type)+>()
$crate::gen::SchemaGenerator::default().into_root_schema_for::<$($type)+>()
};
}

View file

@ -1,4 +1,4 @@
use crate::gen::SchemaGenerator;
use crate::gen::{BoolSchemas, SchemaGenerator};
use crate::schema::*;
use serde_json::json;
use std::collections::BTreeMap as Map;
@ -233,10 +233,17 @@ macro_rules! map_impl {
fn make_schema(gen: &mut SchemaGenerator) -> Schema
{
let subschema = gen.subschema_for::<V>();
let make_schema_bool = gen.settings().bool_schemas == BoolSchemas::AdditionalPropertiesOnly
&& subschema == gen.schema_for_any();
let mut extensions = Map::new();
extensions.insert(
"additionalProperties".to_owned(),
json!(gen.subschema_for::<V>())
if make_schema_bool {
json!(true)
} else {
json!(subschema)
}
);
SchemaObject {
instance_type: Some(InstanceType::Object.into()),
@ -257,16 +264,32 @@ impl<T: MakeSchema> MakeSchema for Option<T> {
no_ref_schema!();
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
match gen.subschema_for::<T>() {
let settings = gen.settings();
let make_any_of = settings.option_any_of_null;
let set_nullable = settings.option_nullable;
let mut schema = match gen.subschema_for::<T>() {
Schema::Bool(true) => true.into(),
Schema::Bool(false) => <()>::make_schema(gen),
schema => SchemaObject {
schema => {
if make_any_of {
SchemaObject {
any_of: Some(vec![schema, <()>::make_schema(gen)]),
..Default::default()
}
.into(),
.into()
} else {
schema
}
}
};
if set_nullable {
// FIXME still need to handle ref schemas here
if let Schema::Object(ref mut o) = schema {
o.extensions.insert("nullable".to_owned(), true.into());
}
};
schema
}
}
////////// DEREF //////////
@ -298,7 +321,7 @@ deref_impl!(<'a, T: ToOwned> MakeSchema for std::borrow::Cow<'a, T>);
impl MakeSchema for serde_json::Value {
no_ref_schema!();
fn make_schema(_: &mut SchemaGenerator) -> Schema {
true.into()
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
gen.schema_for_any()
}
}