mirror of
https://gitlab.com/msrd0/gotham-restful.git
synced 2025-02-23 04:52:28 +00:00
add dependencies to schema
This commit is contained in:
parent
d1c7ac5887
commit
3427fb4c6f
4 changed files with 141 additions and 50 deletions
|
@ -27,14 +27,14 @@ rest_struct!{User {
|
|||
username : String
|
||||
}}
|
||||
|
||||
impl ResourceReadAll<Success<Vec<User>>> for Users
|
||||
impl ResourceReadAll<Success<Vec<Option<User>>>> for Users
|
||||
{
|
||||
fn read_all(_state : &mut State) -> Success<Vec<User>>
|
||||
fn read_all(_state : &mut State) -> Success<Vec<Option<User>>>
|
||||
{
|
||||
vec![Username().fake(), Username().fake()]
|
||||
.into_iter()
|
||||
.map(|username| User { username })
|
||||
.collect::<Vec<User>>()
|
||||
.map(|username| Some(User { username }))
|
||||
.collect::<Vec<Option<User>>>()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,12 +35,32 @@ macro_rules! rest_struct {
|
|||
|
||||
let mut properties : IndexMap<String, ReferenceOr<Box<Schema>>> = IndexMap::new();
|
||||
let mut required : Vec<String> = Vec::new();
|
||||
let mut dependencies : IndexMap<String, OpenapiSchema> = IndexMap::new();
|
||||
|
||||
$(
|
||||
properties.insert(
|
||||
stringify!($field_id).to_string(),
|
||||
ReferenceOr::Item(Box::new(<$field_ty>::to_schema().to_schema()))
|
||||
);
|
||||
{
|
||||
let mut schema = <$field_ty>::to_schema();
|
||||
if let Some(name) = schema.name.clone()
|
||||
{
|
||||
properties.insert(
|
||||
stringify!($field_id).to_string(),
|
||||
ReferenceOr::Reference { reference: format!("#/components/schemas/{}", name) }
|
||||
);
|
||||
if schema.nullable
|
||||
{
|
||||
required.push(stringify!($field_id).to_string());
|
||||
schema.nullable = false;
|
||||
}
|
||||
dependencies.insert(name, schema);
|
||||
}
|
||||
else
|
||||
{
|
||||
properties.insert(
|
||||
stringify!($field_id).to_string(),
|
||||
ReferenceOr::Item(Box::new(<$field_ty>::to_schema().to_schema()))
|
||||
);
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
let schema = SchemaKind::Type(Type::Object(ObjectType {
|
||||
|
@ -54,7 +74,8 @@ macro_rules! rest_struct {
|
|||
OpenapiSchema {
|
||||
name: Some(stringify!($struct_name).to_string()),
|
||||
nullable: false,
|
||||
schema
|
||||
schema,
|
||||
dependencies
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::{
|
|||
resource::*,
|
||||
result::*,
|
||||
routing::*,
|
||||
OpenapiSchema,
|
||||
OpenapiType,
|
||||
ResourceType
|
||||
};
|
||||
|
@ -19,7 +20,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,
|
||||
Server, StatusCode
|
||||
Schema, Server, StatusCode
|
||||
};
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::panic::RefUnwindSafe;
|
||||
|
@ -69,22 +70,49 @@ impl OpenapiRouter
|
|||
self.0.paths.insert(path.to_string(), Item(item));
|
||||
}
|
||||
|
||||
fn add_schema<T : OpenapiType>(&mut self, path : &str, method : &str, desc : &str) -> String
|
||||
fn add_schema_impl(&mut self, name : String, mut schema : OpenapiSchema)
|
||||
{
|
||||
let schema = T::to_schema();
|
||||
let name = schema.name.clone().unwrap_or_else(|| format!("path_{}_{}_{}", path, method, desc));
|
||||
let item = schema.to_schema();
|
||||
self.add_schema_dependencies(&mut schema.dependencies);
|
||||
|
||||
match &mut self.0.components {
|
||||
Some(comp) => {
|
||||
comp.schemas.insert(name.to_string(), Item(item));
|
||||
comp.schemas.insert(name, Item(schema.to_schema()));
|
||||
},
|
||||
None => {
|
||||
let mut comp = Components::default();
|
||||
comp.schemas.insert(name.to_string(), Item(item));
|
||||
comp.schemas.insert(name, Item(schema.to_schema()));
|
||||
self.0.components = Some(comp);
|
||||
}
|
||||
};
|
||||
name
|
||||
}
|
||||
|
||||
fn add_schema_dependencies(&mut self, dependencies : &mut IndexMap<String, OpenapiSchema>)
|
||||
{
|
||||
let keys : Vec<String> = dependencies.keys().map(|k| k.to_string()).collect();
|
||||
for dep in keys
|
||||
{
|
||||
let dep_schema = dependencies.swap_remove(&dep);
|
||||
if let Some(dep_schema) = dep_schema
|
||||
{
|
||||
self.add_schema_impl(dep, dep_schema);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_schema<T : OpenapiType>(&mut self) -> ReferenceOr<Schema>
|
||||
{
|
||||
let mut schema = T::to_schema();
|
||||
if let Some(name) = schema.name.clone()
|
||||
{
|
||||
let reference = Reference { reference: format!("#/components/schemas/{}", name) };
|
||||
self.add_schema_impl(name, schema);
|
||||
reference
|
||||
}
|
||||
else
|
||||
{
|
||||
self.add_schema_dependencies(&mut schema.dependencies);
|
||||
Item(schema.to_schema())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,13 +163,11 @@ pub trait GetOpenapi
|
|||
fn get_openapi(&mut self, path : &str);
|
||||
}
|
||||
|
||||
fn schema_to_content(schema : &str) -> IndexMap<String, MediaType>
|
||||
fn schema_to_content(schema : ReferenceOr<Schema>) -> IndexMap<String, MediaType>
|
||||
{
|
||||
let mut content : IndexMap<String, MediaType> = IndexMap::new();
|
||||
content.insert(APPLICATION_JSON.to_string(), MediaType {
|
||||
schema: Some(Reference {
|
||||
reference: format!("#/components/schemas/{}", schema)
|
||||
}),
|
||||
schema: Some(schema),
|
||||
example: None,
|
||||
examples: IndexMap::new(),
|
||||
encoding: IndexMap::new()
|
||||
|
@ -149,7 +175,7 @@ fn schema_to_content(schema : &str) -> IndexMap<String, MediaType>
|
|||
content
|
||||
}
|
||||
|
||||
fn new_operation(schema : &str, path_params : Vec<&str>, body_schema : Option<&str>) -> Operation
|
||||
fn new_operation(schema : ReferenceOr<Schema>, path_params : Vec<&str>, body_schema : Option<ReferenceOr<Schema>>) -> Operation
|
||||
{
|
||||
let mut responses : IndexMap<StatusCode, ReferenceOr<Response>> = IndexMap::new();
|
||||
responses.insert(StatusCode::Code(200), Item(Response {
|
||||
|
@ -235,11 +261,11 @@ macro_rules! implOpenapiRouter {
|
|||
Res : ResourceResult,
|
||||
Handler : ResourceReadAll<Res>
|
||||
{
|
||||
let schema = (self.0).1.add_schema::<Res>(&self.1, "read_all", "result_body");
|
||||
let schema = (self.0).1.add_schema::<Res>();
|
||||
|
||||
let path = format!("/{}", &self.1);
|
||||
let mut item = (self.0).1.remove_path(&path);
|
||||
item.get = Some(new_operation(&schema, vec![], None));
|
||||
item.get = Some(new_operation(schema, vec![], None));
|
||||
(self.0).1.add_path(path, item);
|
||||
|
||||
(&mut *(self.0).0, self.1.to_string()).read_all::<Handler, Res>()
|
||||
|
@ -251,11 +277,11 @@ macro_rules! implOpenapiRouter {
|
|||
Res : ResourceResult,
|
||||
Handler : ResourceRead<ID, Res>
|
||||
{
|
||||
let schema = (self.0).1.add_schema::<Res>(&self.1, "read", "result_body");
|
||||
let schema = (self.0).1.add_schema::<Res>();
|
||||
|
||||
let path = format!("/{}/{{id}}", &self.1);
|
||||
let mut item = (self.0).1.remove_path(&path);
|
||||
item.get = Some(new_operation(&schema, vec!["id"], None));
|
||||
item.get = Some(new_operation(schema, vec!["id"], None));
|
||||
(self.0).1.add_path(path, item);
|
||||
|
||||
(&mut *(self.0).0, self.1.to_string()).read::<Handler, ID, Res>()
|
||||
|
@ -267,12 +293,12 @@ macro_rules! implOpenapiRouter {
|
|||
Res : ResourceResult,
|
||||
Handler : ResourceCreate<Body, Res>
|
||||
{
|
||||
let schema = (self.0).1.add_schema::<Res>(&self.1, "create", "result_body");
|
||||
let body_schema = (self.0).1.add_schema::<Body>(&self.1, "create", "body");
|
||||
let schema = (self.0).1.add_schema::<Res>();
|
||||
let body_schema = (self.0).1.add_schema::<Body>();
|
||||
|
||||
let path = format!("/{}", &self.1);
|
||||
let mut item = (self.0).1.remove_path(&path);
|
||||
item.post = Some(new_operation(&schema, vec![], Some(&body_schema)));
|
||||
item.post = Some(new_operation(schema, vec![], Some(body_schema)));
|
||||
(self.0).1.add_path(path, item);
|
||||
|
||||
(&mut *(self.0).0, self.1.to_string()).create::<Handler, Body, Res>()
|
||||
|
@ -284,12 +310,12 @@ macro_rules! implOpenapiRouter {
|
|||
Res : ResourceResult,
|
||||
Handler : ResourceUpdateAll<Body, Res>
|
||||
{
|
||||
let schema = (self.0).1.add_schema::<Res>(&self.1, "update_all", "result_body");
|
||||
let body_schema = (self.0).1.add_schema::<Body>(&self.1, "create", "body");
|
||||
let schema = (self.0).1.add_schema::<Res>();
|
||||
let body_schema = (self.0).1.add_schema::<Body>();
|
||||
|
||||
let path = format!("/{}", &self.1);
|
||||
let mut item = (self.0).1.remove_path(&path);
|
||||
item.put = Some(new_operation(&schema, vec![], Some(&body_schema)));
|
||||
item.put = Some(new_operation(schema, vec![], Some(body_schema)));
|
||||
(self.0).1.add_path(path, item);
|
||||
|
||||
(&mut *(self.0).0, self.1.to_string()).update_all::<Handler, Body, Res>()
|
||||
|
@ -302,12 +328,12 @@ macro_rules! implOpenapiRouter {
|
|||
Res : ResourceResult,
|
||||
Handler : ResourceUpdate<ID, Body, Res>
|
||||
{
|
||||
let schema = (self.0).1.add_schema::<Res>(&self.1, "update", "result_body");
|
||||
let body_schema = (self.0).1.add_schema::<Body>(&self.1, "create", "body");
|
||||
let schema = (self.0).1.add_schema::<Res>();
|
||||
let body_schema = (self.0).1.add_schema::<Body>();
|
||||
|
||||
let path = format!("/{}/{{id}}", &self.1);
|
||||
let mut item = (self.0).1.remove_path(&path);
|
||||
item.put = Some(new_operation(&schema, vec!["id"], Some(&body_schema)));
|
||||
item.put = Some(new_operation(schema, vec!["id"], Some(body_schema)));
|
||||
(self.0).1.add_path(path, item);
|
||||
|
||||
(&mut *(self.0).0, self.1.to_string()).update::<Handler, ID, Body, Res>()
|
||||
|
@ -318,11 +344,11 @@ macro_rules! implOpenapiRouter {
|
|||
Res : ResourceResult,
|
||||
Handler : ResourceDeleteAll<Res>
|
||||
{
|
||||
let schema = (self.0).1.add_schema::<Res>(&self.1, "delete_all", "result_body");
|
||||
let schema = (self.0).1.add_schema::<Res>();
|
||||
|
||||
let path = format!("/{}", &self.1);
|
||||
let mut item = (self.0).1.remove_path(&path);
|
||||
item.delete = Some(new_operation(&schema, vec![], None));
|
||||
item.delete = Some(new_operation(schema, vec![], None));
|
||||
(self.0).1.add_path(path, item);
|
||||
|
||||
(&mut *(self.0).0, self.1.to_string()).delete_all::<Handler, Res>()
|
||||
|
@ -334,11 +360,11 @@ macro_rules! implOpenapiRouter {
|
|||
Res : ResourceResult,
|
||||
Handler : ResourceDelete<ID, Res>
|
||||
{
|
||||
let schema = (self.0).1.add_schema::<Res>(&self.1, "delete", "result_body");
|
||||
let schema = (self.0).1.add_schema::<Res>();
|
||||
|
||||
let path = format!("/{}/{{id}}", &self.1);
|
||||
let mut item = (self.0).1.remove_path(&path);
|
||||
item.delete = Some(new_operation(&schema, vec!["id"], None));
|
||||
item.delete = Some(new_operation(schema, vec!["id"], None));
|
||||
(self.0).1.add_path(path, item);
|
||||
|
||||
(&mut *(self.0).0, self.1.to_string()).delete::<Handler, ID, Res>()
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
use chrono::{
|
||||
Date, DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime, Utc
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
use openapiv3::{
|
||||
ArrayType, IntegerType, NumberType, ObjectType, ReferenceOr::Item, ReferenceOr::Reference, Schema,
|
||||
SchemaData, SchemaKind, StringFormat, StringType, Type, VariantOrUnknownOrEmpty
|
||||
|
@ -13,7 +14,8 @@ 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
|
||||
pub schema : SchemaKind,
|
||||
pub dependencies : IndexMap<String, OpenapiSchema>
|
||||
}
|
||||
|
||||
impl OpenapiSchema
|
||||
|
@ -23,7 +25,8 @@ impl OpenapiSchema
|
|||
Self {
|
||||
name: None,
|
||||
nullable: false,
|
||||
schema
|
||||
schema,
|
||||
dependencies: IndexMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,20 +127,61 @@ macro_rules! str_types {
|
|||
|
||||
str_types!(String, &str);
|
||||
|
||||
impl<T : OpenapiType> OpenapiType for Option<T>
|
||||
{
|
||||
fn to_schema() -> OpenapiSchema
|
||||
{
|
||||
let schema = T::to_schema();
|
||||
let mut dependencies : IndexMap<String, OpenapiSchema> = IndexMap::new();
|
||||
let refor = if let Some(name) = schema.name.clone()
|
||||
{
|
||||
let reference = Reference { reference: format!("#/components/schemas/{}", name) };
|
||||
dependencies.insert(name, schema);
|
||||
reference
|
||||
}
|
||||
else
|
||||
{
|
||||
Item(schema.to_schema())
|
||||
};
|
||||
|
||||
OpenapiSchema {
|
||||
nullable: true,
|
||||
name: None,
|
||||
schema: SchemaKind::AllOf { all_of: vec![refor] },
|
||||
dependencies
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T : OpenapiType> OpenapiType for Vec<T>
|
||||
{
|
||||
fn to_schema() -> OpenapiSchema
|
||||
{
|
||||
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
|
||||
})))
|
||||
let mut dependencies : IndexMap<String, OpenapiSchema> = IndexMap::new();
|
||||
|
||||
let items = if let Some(name) = schema.name.clone()
|
||||
{
|
||||
let reference = Reference { reference: format!("#/components/schemas/{}", name) };
|
||||
dependencies.insert(name, schema);
|
||||
reference
|
||||
}
|
||||
else
|
||||
{
|
||||
Item(Box::new(schema.to_schema()))
|
||||
};
|
||||
|
||||
OpenapiSchema {
|
||||
nullable: false,
|
||||
name: None,
|
||||
schema: SchemaKind::Type(Type::Array(ArrayType {
|
||||
items,
|
||||
min_items: None,
|
||||
max_items: None,
|
||||
unique_items: false
|
||||
})),
|
||||
dependencies
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue