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:
parent
0619e69925
commit
d1c7ac5887
5 changed files with 85 additions and 115 deletions
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()
|
||||||
},
|
},
|
||||||
|
|
|
@ -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
|
||||||
}))
|
})))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue