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
{
fn schema_name() -> Option<String>
fn to_schema() -> ::gotham_restful::OpenapiSchema
{
Some(stringify!($struct_name).to_string())
}
fn to_schema() -> ::gotham_restful::helper::openapi::SchemaKind
{
use ::gotham_restful::helper::openapi::*;
use ::gotham_restful::{helper::openapi::*, OpenapiSchema};
let mut properties : IndexMap<String, ReferenceOr<Box<Schema>>> = IndexMap::new();
let mut required : Vec<String> = Vec::new();
@ -44,31 +39,23 @@ macro_rules! rest_struct {
$(
properties.insert(
stringify!($field_id).to_string(),
ReferenceOr::Item(Box::new(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()
}))
ReferenceOr::Item(Box::new(<$field_ty>::to_schema().to_schema()))
);
)*
SchemaKind::Type(Type::Object(ObjectType {
let schema = SchemaKind::Type(Type::Object(ObjectType {
properties,
required,
additional_properties: None,
min_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")]
pub use openapi::{
router::{GetOpenapi, OpenapiRouter},
types::OpenapiType
types::{OpenapiSchema, OpenapiType}
};
mod resource;

View file

@ -19,7 +19,7 @@ use mime::{APPLICATION_JSON, TEXT_PLAIN};
use openapiv3::{
Components, MediaType, OpenAPI, Operation, Parameter, ParameterData, ParameterSchemaOrContent, PathItem,
PathStyle, Paths, ReferenceOr, ReferenceOr::Item, ReferenceOr::Reference, RequestBody, Response, Responses,
Schema, SchemaData, Server, StatusCode
Server, StatusCode
};
use serde::de::DeserializeOwned;
use std::panic::RefUnwindSafe;
@ -71,22 +71,9 @@ impl OpenapiRouter
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 item = Schema {
schema_data: SchemaData {
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()
};
let schema = T::to_schema();
let name = schema.name.clone().unwrap_or_else(|| format!("path_{}_{}_{}", path, method, desc));
let item = schema.to_schema();
match &mut self.0.components {
Some(comp) => {
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,
required: true,
deprecated: None,
format: ParameterSchemaOrContent::Schema(Item(Schema {
schema_data: SchemaData::default(),
schema_kind: String::to_schema()
})),
format: ParameterSchemaOrContent::Schema(Item(String::to_schema().to_schema())),
example: None,
examples: IndexMap::new()
},

View file

@ -3,34 +3,68 @@ use chrono::{
Date, DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime, Utc
};
use openapiv3::{
ArrayType, IntegerType, NumberType, ObjectType, ReferenceOr::Item, Schema, SchemaData, SchemaKind,
StringFormat, StringType, Type, VariantOrUnknownOrEmpty
ArrayType, IntegerType, NumberType, ObjectType, ReferenceOr::Item, ReferenceOr::Reference, Schema,
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
{
fn schema_name() -> Option<String>
{
None
}
fn to_schema() -> SchemaKind;
fn to_schema() -> OpenapiSchema;
}
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
{
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),*) => {$(
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),*) => {$(
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),*) => {$(
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),*) => {$(
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),
pattern: None,
enumeration: Vec::new()
}))
})))
}
}
)*};
@ -92,33 +126,18 @@ str_types!(String, &str);
impl<T : OpenapiType> OpenapiType for Vec<T>
{
fn schema_name() -> Option<String>
fn to_schema() -> OpenapiSchema
{
T::schema_name().map(|name| format!("{}Array", name))
}
fn to_schema() -> SchemaKind
{
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()
})),
let schema = T::to_schema();
OpenapiSchema::new(SchemaKind::Type(Type::Array(ArrayType {
items: match schema.name {
Some(name) => Reference { reference: format!("#/components/schemas/{}", name) },
None => Item(Box::new(schema.to_schema()))
},
min_items: None,
max_items: None,
unique_items: false
}))
})))
}
}

View file

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