1
0
Fork 0
mirror of https://gitlab.com/msrd0/gotham-restful.git synced 2025-02-23 04:52:28 +00:00

introduce OpenapiSchema type

This commit is contained in:
Dominic 2019-10-01 15:33:05 +02:00
parent 0619e69925
commit d1c7ac5887
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
5 changed files with 85 additions and 115 deletions

View file

@ -29,14 +29,9 @@ macro_rules! rest_struct {
impl ::gotham_restful::OpenapiType for $struct_name impl ::gotham_restful::OpenapiType for $struct_name
{ {
fn schema_name() -> Option<String> fn to_schema() -> ::gotham_restful::OpenapiSchema
{ {
Some(stringify!($struct_name).to_string()) use ::gotham_restful::{helper::openapi::*, OpenapiSchema};
}
fn to_schema() -> ::gotham_restful::helper::openapi::SchemaKind
{
use ::gotham_restful::helper::openapi::*;
let mut properties : IndexMap<String, ReferenceOr<Box<Schema>>> = IndexMap::new(); let mut properties : IndexMap<String, ReferenceOr<Box<Schema>>> = IndexMap::new();
let mut required : Vec<String> = Vec::new(); let mut required : Vec<String> = Vec::new();
@ -44,31 +39,23 @@ macro_rules! rest_struct {
$( $(
properties.insert( properties.insert(
stringify!($field_id).to_string(), stringify!($field_id).to_string(),
ReferenceOr::Item(Box::new(Schema { ReferenceOr::Item(Box::new(<$field_ty>::to_schema().to_schema()))
schema_data: SchemaData {
nullable: false,
read_only: false,
write_only: false,
deprecated: false,
external_docs: None,
example: None,
title: <$field_ty>::schema_name(),
description: None,
discriminator: None,
default: None
},
schema_kind: <$field_ty>::to_schema()
}))
); );
)* )*
SchemaKind::Type(Type::Object(ObjectType { let schema = SchemaKind::Type(Type::Object(ObjectType {
properties, properties,
required, required,
additional_properties: None, additional_properties: None,
min_properties: None, min_properties: None,
max_properties: None max_properties: None
})) }));
OpenapiSchema {
name: Some(stringify!($struct_name).to_string()),
nullable: false,
schema
}
} }
} }
} }

View file

@ -11,7 +11,7 @@ pub mod openapi;
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
pub use openapi::{ pub use openapi::{
router::{GetOpenapi, OpenapiRouter}, router::{GetOpenapi, OpenapiRouter},
types::OpenapiType types::{OpenapiSchema, OpenapiType}
}; };
mod resource; mod resource;

View file

@ -19,7 +19,7 @@ use mime::{APPLICATION_JSON, TEXT_PLAIN};
use openapiv3::{ use openapiv3::{
Components, MediaType, OpenAPI, Operation, Parameter, ParameterData, ParameterSchemaOrContent, PathItem, Components, MediaType, OpenAPI, Operation, Parameter, ParameterData, ParameterSchemaOrContent, PathItem,
PathStyle, Paths, ReferenceOr, ReferenceOr::Item, ReferenceOr::Reference, RequestBody, Response, Responses, PathStyle, Paths, ReferenceOr, ReferenceOr::Item, ReferenceOr::Reference, RequestBody, Response, Responses,
Schema, SchemaData, Server, StatusCode Server, StatusCode
}; };
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::panic::RefUnwindSafe; use std::panic::RefUnwindSafe;
@ -71,22 +71,9 @@ impl OpenapiRouter
fn add_schema<T : OpenapiType>(&mut self, path : &str, method : &str, desc : &str) -> String fn add_schema<T : OpenapiType>(&mut self, path : &str, method : &str, desc : &str) -> String
{ {
let name = T::schema_name().unwrap_or_else(|| format!("path_{}_{}_{}", path, method, desc)); let schema = T::to_schema();
let item = Schema { let name = schema.name.clone().unwrap_or_else(|| format!("path_{}_{}_{}", path, method, desc));
schema_data: SchemaData { let item = schema.to_schema();
nullable: false,
read_only: false,
write_only: false,
deprecated: false,
external_docs: None,
example: None,
title: Some(name.to_string()),
description: None,
discriminator: None,
default: None
},
schema_kind: T::to_schema()
};
match &mut self.0.components { match &mut self.0.components {
Some(comp) => { Some(comp) => {
comp.schemas.insert(name.to_string(), Item(item)); comp.schemas.insert(name.to_string(), Item(item));
@ -181,10 +168,7 @@ fn new_operation(schema : &str, path_params : Vec<&str>, body_schema : Option<&s
description: None, description: None,
required: true, required: true,
deprecated: None, deprecated: None,
format: ParameterSchemaOrContent::Schema(Item(Schema { format: ParameterSchemaOrContent::Schema(Item(String::to_schema().to_schema())),
schema_data: SchemaData::default(),
schema_kind: String::to_schema()
})),
example: None, example: None,
examples: IndexMap::new() examples: IndexMap::new()
}, },

View file

@ -3,34 +3,68 @@ use chrono::{
Date, DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime, Utc Date, DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime, Utc
}; };
use openapiv3::{ use openapiv3::{
ArrayType, IntegerType, NumberType, ObjectType, ReferenceOr::Item, Schema, SchemaData, SchemaKind, ArrayType, IntegerType, NumberType, ObjectType, ReferenceOr::Item, ReferenceOr::Reference, Schema,
StringFormat, StringType, Type, VariantOrUnknownOrEmpty SchemaData, SchemaKind, StringFormat, StringType, Type, VariantOrUnknownOrEmpty
}; };
#[derive(Debug, Clone, PartialEq)]
pub struct OpenapiSchema
{
/// The name of this schema. If it is None, the schema will be inlined.
pub name : Option<String>,
pub nullable : bool,
pub schema : SchemaKind
}
impl OpenapiSchema
{
pub fn new(schema : SchemaKind) -> Self
{
Self {
name: None,
nullable: false,
schema
}
}
pub fn to_schema(self) -> Schema
{
Schema {
schema_data: SchemaData {
nullable: self.nullable,
read_only: false,
write_only: false,
deprecated: false,
external_docs: None,
example: None,
title: self.name,
description: None,
discriminator: None,
default: None
},
schema_kind: self.schema
}
}
}
pub trait OpenapiType pub trait OpenapiType
{ {
fn schema_name() -> Option<String> fn to_schema() -> OpenapiSchema;
{
None
}
fn to_schema() -> SchemaKind;
} }
impl OpenapiType for () impl OpenapiType for ()
{ {
fn to_schema() -> SchemaKind fn to_schema() -> OpenapiSchema
{ {
SchemaKind::Type(Type::Object(ObjectType::default())) OpenapiSchema::new(SchemaKind::Type(Type::Object(ObjectType::default())))
} }
} }
impl OpenapiType for bool impl OpenapiType for bool
{ {
fn to_schema() -> SchemaKind fn to_schema() -> OpenapiSchema
{ {
SchemaKind::Type(Type::Boolean{}) OpenapiSchema::new(SchemaKind::Type(Type::Boolean{}))
} }
} }
@ -38,9 +72,9 @@ macro_rules! int_types {
($($int_ty:ty),*) => {$( ($($int_ty:ty),*) => {$(
impl OpenapiType for $int_ty impl OpenapiType for $int_ty
{ {
fn to_schema() -> SchemaKind fn to_schema() -> OpenapiSchema
{ {
SchemaKind::Type(Type::Integer(IntegerType::default())) OpenapiSchema::new(SchemaKind::Type(Type::Integer(IntegerType::default())))
} }
} }
)*} )*}
@ -52,9 +86,9 @@ macro_rules! num_types {
($($num_ty:ty),*) => {$( ($($num_ty:ty),*) => {$(
impl OpenapiType for $num_ty impl OpenapiType for $num_ty
{ {
fn to_schema() -> SchemaKind fn to_schema() -> OpenapiSchema
{ {
SchemaKind::Type(Type::Number(NumberType::default())) OpenapiSchema::new(SchemaKind::Type(Type::Number(NumberType::default())))
} }
} }
)*} )*}
@ -66,9 +100,9 @@ macro_rules! str_types {
($($str_ty:ty),*) => {$( ($($str_ty:ty),*) => {$(
impl OpenapiType for $str_ty impl OpenapiType for $str_ty
{ {
fn to_schema() -> SchemaKind fn to_schema() -> OpenapiSchema
{ {
SchemaKind::Type(Type::String(StringType::default())) OpenapiSchema::new(SchemaKind::Type(Type::String(StringType::default())))
} }
} }
)*}; )*};
@ -76,13 +110,13 @@ macro_rules! str_types {
(format = $format:ident, $($str_ty:ty),*) => {$( (format = $format:ident, $($str_ty:ty),*) => {$(
impl OpenapiType for $str_ty impl OpenapiType for $str_ty
{ {
fn to_schema() -> SchemaKind fn to_schema() -> OpenapiSchema
{ {
SchemaKind::Type(Type::String(StringType { OpenapiSchema::new(SchemaKind::Type(Type::String(StringType {
format: VariantOrUnknownOrEmpty::Item(StringFormat::$format), format: VariantOrUnknownOrEmpty::Item(StringFormat::$format),
pattern: None, pattern: None,
enumeration: Vec::new() enumeration: Vec::new()
})) })))
} }
} }
)*}; )*};
@ -92,33 +126,18 @@ str_types!(String, &str);
impl<T : OpenapiType> OpenapiType for Vec<T> impl<T : OpenapiType> OpenapiType for Vec<T>
{ {
fn schema_name() -> Option<String> fn to_schema() -> OpenapiSchema
{ {
T::schema_name().map(|name| format!("{}Array", name)) let schema = T::to_schema();
} OpenapiSchema::new(SchemaKind::Type(Type::Array(ArrayType {
items: match schema.name {
fn to_schema() -> SchemaKind Some(name) => Reference { reference: format!("#/components/schemas/{}", name) },
{ None => Item(Box::new(schema.to_schema()))
SchemaKind::Type(Type::Array(ArrayType { },
items: Item(Box::new(Schema {
schema_data: SchemaData {
nullable: false,
read_only: false,
write_only: false,
deprecated: false,
external_docs: None,
example: None,
title: T::schema_name(),
description: None,
discriminator: None,
default: None
},
schema_kind: T::to_schema()
})),
min_items: None, min_items: None,
max_items: None, max_items: None,
unique_items: false unique_items: false
})) })))
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ResourceType, StatusCode}; use crate::{ResourceType, StatusCode};
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
use openapiv3::SchemaKind; use crate::OpenapiSchema;
use serde::Serialize; use serde::Serialize;
use serde_json::error::Error as SerdeJsonError; use serde_json::error::Error as SerdeJsonError;
use std::error::Error; use std::error::Error;
@ -11,21 +11,13 @@ pub trait ResourceResult
fn to_json(&self) -> Result<(StatusCode, String), SerdeJsonError>; fn to_json(&self) -> Result<(StatusCode, String), SerdeJsonError>;
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
fn schema_name() -> Option<String>; fn to_schema() -> OpenapiSchema;
#[cfg(feature = "openapi")]
fn to_schema() -> SchemaKind;
} }
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
impl<Res : ResourceResult> crate::OpenapiType for Res impl<Res : ResourceResult> crate::OpenapiType for Res
{ {
fn schema_name() -> Option<String> fn to_schema() -> OpenapiSchema
{
Self::schema_name()
}
fn to_schema() -> SchemaKind
{ {
Self::to_schema() Self::to_schema()
} }
@ -64,13 +56,7 @@ impl<R : ResourceType, E : Error> ResourceResult for Result<R, E>
} }
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
fn schema_name() -> Option<String> fn to_schema() -> OpenapiSchema
{
R::schema_name()
}
#[cfg(feature = "openapi")]
fn to_schema() -> SchemaKind
{ {
R::to_schema() R::to_schema()
} }
@ -95,13 +81,7 @@ impl<T : ResourceType> ResourceResult for Success<T>
} }
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
fn schema_name() -> Option<String> fn to_schema() -> OpenapiSchema
{
T::schema_name()
}
#[cfg(feature = "openapi")]
fn to_schema() -> SchemaKind
{ {
T::to_schema() T::to_schema()
} }