mirror of
https://gitlab.com/msrd0/gotham-restful.git
synced 2025-02-23 04:52:28 +00:00
first valid openapi spec generated
This commit is contained in:
parent
681482ece3
commit
d9b4b22af3
4 changed files with 130 additions and 20 deletions
|
@ -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) => {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,10 @@ use std::error::Error;
|
||||||
pub trait ResourceResult
|
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;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +47,14 @@ 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()
|
||||||
|
@ -68,7 +78,14 @@ 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()
|
||||||
|
|
Loading…
Add table
Reference in a new issue