Add some config for openapi3 compatibility
This commit is contained in:
parent
ef5c584118
commit
1f514f2be7
3 changed files with 108 additions and 14 deletions
|
@ -4,19 +4,90 @@ use std::collections::BTreeMap as Map;
|
||||||
use std::collections::BTreeSet as Set;
|
use std::collections::BTreeSet as Set;
|
||||||
use std::iter::FromIterator;
|
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 {
|
pub struct SchemaGenerator {
|
||||||
|
settings: SchemaSettings,
|
||||||
names: Set<String>,
|
names: Set<String>,
|
||||||
definitions: Map<SchemaTypeId, (String, Schema)>,
|
definitions: Map<SchemaTypeId, (String, Schema)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SchemaGenerator {
|
impl SchemaGenerator {
|
||||||
pub fn new() -> SchemaGenerator {
|
pub fn new(settings: SchemaSettings) -> SchemaGenerator {
|
||||||
SchemaGenerator {
|
SchemaGenerator {
|
||||||
|
settings,
|
||||||
..Default::default()
|
..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 {
|
pub fn subschema_for<T: ?Sized + MakeSchema>(&mut self) -> Schema {
|
||||||
if !T::generates_ref_schema() {
|
if !T::generates_ref_schema() {
|
||||||
return T::make_schema(self);
|
return T::make_schema(self);
|
||||||
|
@ -33,7 +104,7 @@ impl SchemaGenerator {
|
||||||
self.insert_new_subschema_for::<T>(type_id, name.clone());
|
self.insert_new_subschema_for::<T>(type_id, name.clone());
|
||||||
name
|
name
|
||||||
});
|
});
|
||||||
let reference = format!("#/definitions/{}", name);
|
let reference = format!("{}{}", self.settings().definitions_path, name);
|
||||||
SchemaRef { reference }.into()
|
SchemaRef { reference }.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#[macro_export()]
|
#[macro_export()]
|
||||||
macro_rules! schema_for {
|
macro_rules! schema_for {
|
||||||
($($type:tt)+) => {
|
($($type:tt)+) => {
|
||||||
$crate::gen::SchemaGenerator::new().into_root_schema_for::<$($type)+>()
|
$crate::gen::SchemaGenerator::default().into_root_schema_for::<$($type)+>()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::{BoolSchemas, SchemaGenerator};
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::collections::BTreeMap as Map;
|
use std::collections::BTreeMap as Map;
|
||||||
|
@ -233,10 +233,17 @@ macro_rules! map_impl {
|
||||||
|
|
||||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema
|
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();
|
let mut extensions = Map::new();
|
||||||
extensions.insert(
|
extensions.insert(
|
||||||
"additionalProperties".to_owned(),
|
"additionalProperties".to_owned(),
|
||||||
json!(gen.subschema_for::<V>())
|
if make_schema_bool {
|
||||||
|
json!(true)
|
||||||
|
} else {
|
||||||
|
json!(subschema)
|
||||||
|
}
|
||||||
);
|
);
|
||||||
SchemaObject {
|
SchemaObject {
|
||||||
instance_type: Some(InstanceType::Object.into()),
|
instance_type: Some(InstanceType::Object.into()),
|
||||||
|
@ -257,16 +264,32 @@ impl<T: MakeSchema> MakeSchema for Option<T> {
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
|
||||||
fn make_schema(gen: &mut SchemaGenerator) -> 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(true) => true.into(),
|
||||||
Schema::Bool(false) => <()>::make_schema(gen),
|
Schema::Bool(false) => <()>::make_schema(gen),
|
||||||
schema => SchemaObject {
|
schema => {
|
||||||
|
if make_any_of {
|
||||||
|
SchemaObject {
|
||||||
any_of: Some(vec![schema, <()>::make_schema(gen)]),
|
any_of: Some(vec![schema, <()>::make_schema(gen)]),
|
||||||
..Default::default()
|
..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 //////////
|
////////// DEREF //////////
|
||||||
|
@ -298,7 +321,7 @@ deref_impl!(<'a, T: ToOwned> MakeSchema for std::borrow::Cow<'a, T>);
|
||||||
impl MakeSchema for serde_json::Value {
|
impl MakeSchema for serde_json::Value {
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
|
||||||
fn make_schema(_: &mut SchemaGenerator) -> Schema {
|
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
true.into()
|
gen.schema_for_any()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue