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

first valid openapi spec generated

This commit is contained in:
Dominic 2019-09-30 23:53:55 +02:00
parent 681482ece3
commit d9b4b22af3
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
4 changed files with 130 additions and 20 deletions

View file

@ -1,4 +1,11 @@
#[cfg(feature = "openapi")]
pub mod openapi
{
pub use indexmap::IndexMap;
pub use openapiv3::{ObjectType, ReferenceOr, Schema, SchemaData, SchemaKind, Type};
}
#[cfg(not(feature = "openapi"))]
#[macro_export] #[macro_export]
macro_rules! rest_struct { macro_rules! rest_struct {
($struct_name:ident { $($field_id:ident : $field_ty:ty),* }) => { ($struct_name:ident { $($field_id:ident : $field_ty:ty),* }) => {
@ -10,6 +17,52 @@ macro_rules! rest_struct {
} }
} }
#[cfg(feature = "openapi")]
#[macro_export]
macro_rules! rest_struct {
($struct_name:ident { $($field_id:ident : $field_ty:ty),* }) => {
#[derive(serde::Deserialize, serde::Serialize)]
struct $struct_name
{
$($field_id : $field_ty),*
}
impl ::gotham_restful::OpenapiType for $struct_name
{
fn schema_name() -> Option<String>
{
Some(stringify!($struct_name).to_string())
}
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 required : Vec<String> = Vec::new();
$(
properties.insert(
stringify!($field_id).to_string(),
ReferenceOr::Item(Box::new(Schema {
schema_data: SchemaData::default(),
schema_kind: <$field_ty>::to_schema()
}))
);
)*
SchemaKind::Type(Type::Object(ObjectType {
properties,
required,
additional_properties: None,
min_properties: None,
max_properties: None
}))
}
}
}
}
#[macro_export] #[macro_export]
macro_rules! rest_resource { macro_rules! rest_resource {
($res_name:ident, $route:ident => $setup:block) => { ($res_name:ident, $route:ident => $setup:block) => {

View file

@ -15,7 +15,8 @@ use indexmap::IndexMap;
use log::error; use log::error;
use mime::{APPLICATION_JSON, TEXT_PLAIN}; use mime::{APPLICATION_JSON, TEXT_PLAIN};
use openapiv3::{ use openapiv3::{
MediaType, OpenAPI, Operation, PathItem, Paths, ReferenceOr, ReferenceOr::Item, Response, Responses, Server, StatusCode Components, MediaType, OpenAPI, Operation, PathItem, Paths, ReferenceOr, ReferenceOr::Item, ReferenceOr::Reference,
Response, Responses, Schema, SchemaData, Server, StatusCode
}; };
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::panic::RefUnwindSafe; use std::panic::RefUnwindSafe;
@ -57,24 +58,27 @@ impl OpenapiRouter
{ {
return item; return item;
} }
return PathItem { return PathItem::default()
get: None,
put: None,
post: None,
delete: None,
options: None,
head: None,
patch: None,
trace: None,
servers: Vec::new(),
parameters: Vec::new()
};
} }
fn add_path<Path : ToString>(&mut self, path : Path, item : PathItem) fn add_path<Path : ToString>(&mut self, path : Path, item : PathItem)
{ {
self.0.paths.insert(path.to_string(), Item(item)); self.0.paths.insert(path.to_string(), Item(item));
} }
fn add_schema<Name : ToString>(&mut self, name : Name, item : Schema)
{
match &mut self.0.components {
Some(comp) => {
comp.schemas.insert(name.to_string(), Item(item));
},
None => {
let mut comp = Components::default();
comp.schemas.insert(name.to_string(), Item(item));
self.0.components = Some(comp);
}
};
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -159,11 +163,21 @@ macro_rules! implOpenapiRouter {
Res : ResourceResult, Res : ResourceResult,
Handler : ResourceReadAll<Res> Handler : ResourceReadAll<Res>
{ {
let path = &self.1; let schema = Res::schema_name().unwrap_or_else(|| {
let mut item = (self.0).1.remove_path(path); format!("Resource_{}_ReadAllResult", self.1)
});
(self.0).1.add_schema(&schema, Schema {
schema_data: SchemaData::default(),
schema_kind: Res::to_schema()
});
let path = format!("/{}", &self.1);
let mut item = (self.0).1.remove_path(&path);
let mut content : IndexMap<String, MediaType> = IndexMap::new(); let mut content : IndexMap<String, MediaType> = IndexMap::new();
content.insert(APPLICATION_JSON.to_string(), MediaType { content.insert(APPLICATION_JSON.to_string(), MediaType {
schema: None, // TODO schema: Some(Reference {
reference: format!("#/components/schemas/{}", schema)
}),
example: None, example: None,
examples: IndexMap::new(), examples: IndexMap::new(),
encoding: IndexMap::new() encoding: IndexMap::new()

View file

@ -1,12 +1,17 @@
use indexmap::IndexMap; use indexmap::IndexMap;
use openapiv3::{ use openapiv3::{
IntegerType, NumberType, ObjectType, SchemaKind, StringType, Type ArrayType, IntegerType, NumberType, ObjectType, ReferenceOr::Item, Schema, SchemaData, SchemaKind, StringType, Type
}; };
use serde::Serialize; use serde::Serialize;
pub trait OpenapiType : Serialize pub trait OpenapiType : Serialize
{ {
fn schema_name() -> Option<String>
{
None
}
fn to_schema() -> SchemaKind; fn to_schema() -> SchemaKind;
} }
@ -67,3 +72,24 @@ macro_rules! str_types {
} }
str_types!(String, &str); str_types!(String, &str);
impl<T : OpenapiType> OpenapiType for Vec<T>
{
fn schema_name() -> Option<String>
{
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::default(),
schema_kind: T::to_schema()
})),
min_items: None,
max_items: None,
unique_items: false
}))
}
}

View file

@ -9,6 +9,9 @@ pub trait ResourceResult
{ {
fn to_json(&self) -> Result<(StatusCode, String), SerdeJsonError>; fn to_json(&self) -> Result<(StatusCode, String), SerdeJsonError>;
#[cfg(feature = "openapi")]
fn schema_name() -> Option<String>;
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
fn to_schema() -> SchemaKind; fn to_schema() -> SchemaKind;
} }
@ -45,6 +48,13 @@ 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() -> SchemaKind
{ {
R::to_schema() R::to_schema()
@ -69,6 +79,13 @@ impl<T : ResourceType> ResourceResult for Success<T>
Ok((StatusCode::OK, serde_json::to_string(&self.0)?)) Ok((StatusCode::OK, serde_json::to_string(&self.0)?))
} }
#[cfg(feature = "openapi")]
fn schema_name() -> Option<String>
{
T::schema_name()
}
#[cfg(feature = "openapi")]
fn to_schema() -> SchemaKind fn to_schema() -> SchemaKind
{ {
T::to_schema() T::to_schema()