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

openapi for read method

This commit is contained in:
Dominic 2019-10-01 00:23:34 +02:00
parent d9b4b22af3
commit 7286054a2f
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
3 changed files with 92 additions and 44 deletions

View file

@ -118,7 +118,7 @@ fn main()
); );
gotham::start(ADDR, build_router(chain, pipelines, |route| { gotham::start(ADDR, build_router(chain, pipelines, |route| {
route.with_openapi("Users Example", "0.0.1", ADDR, |mut route| { route.with_openapi("Users Example", "0.0.1", format!("http://{}", ADDR), |mut route| {
route.resource::<Users, _>("users"); route.resource::<Users, _>("users");
route.get_openapi("openapi"); route.get_openapi("openapi");
}); });

View file

@ -1,7 +1,8 @@
use crate::{ use crate::{
resource::*, resource::*,
result::*, result::*,
routing::* routing::*,
OpenapiType
}; };
use futures::future::ok; use futures::future::ok;
use gotham::{ use gotham::{
@ -15,8 +16,9 @@ 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::{
Components, MediaType, OpenAPI, Operation, PathItem, Paths, ReferenceOr, ReferenceOr::Item, ReferenceOr::Reference, Components, MediaType, OpenAPI, Operation, Parameter, ParameterData, ParameterSchemaOrContent, PathItem,
Response, Responses, Schema, SchemaData, Server, StatusCode PathStyle, 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;
@ -66,8 +68,24 @@ impl OpenapiRouter
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) fn add_schema<T : ResourceResult>(&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()
};
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));
@ -78,6 +96,7 @@ impl OpenapiRouter
self.0.components = Some(comp); self.0.components = Some(comp);
} }
}; };
name
} }
} }
@ -128,6 +147,64 @@ pub trait GetOpenapi
fn get_openapi(&mut self, path : &str); fn get_openapi(&mut self, path : &str);
} }
fn new_operation(schema : &str, path_params : Vec<&str>) -> Operation
{
let mut content : IndexMap<String, MediaType> = IndexMap::new();
content.insert(APPLICATION_JSON.to_string(), MediaType {
schema: Some(Reference {
reference: format!("#/components/schemas/{}", schema)
}),
example: None,
examples: IndexMap::new(),
encoding: IndexMap::new()
});
let mut responses : IndexMap<StatusCode, ReferenceOr<Response>> = IndexMap::new();
responses.insert(StatusCode::Code(200), Item(Response {
description: "OK".to_string(),
headers: IndexMap::new(),
content,
links: IndexMap::new()
}));
let mut params : Vec<ReferenceOr<Parameter>> = Vec::new();
for param in path_params
{
params.push(Item(Parameter::Path {
parameter_data: ParameterData {
name: param.to_string(),
description: None,
required: true,
deprecated: None,
format: ParameterSchemaOrContent::Schema(Item(Schema {
schema_data: SchemaData::default(),
schema_kind: String::to_schema()
})),
example: None,
examples: IndexMap::new()
},
style: PathStyle::default(),
}));
}
Operation {
tags: Vec::new(),
summary: None,
description: None,
external_documentation: None,
operation_id: None, // TODO
parameters: params,
request_body: None,
responses: Responses {
default: None,
responses
},
deprecated: false,
security: Vec::new(),
servers: Vec::new()
}
}
macro_rules! implOpenapiRouter { macro_rules! implOpenapiRouter {
($implType:ident) => { ($implType:ident) => {
@ -163,48 +240,11 @@ macro_rules! implOpenapiRouter {
Res : ResourceResult, Res : ResourceResult,
Handler : ResourceReadAll<Res> Handler : ResourceReadAll<Res>
{ {
let schema = Res::schema_name().unwrap_or_else(|| { let schema = (self.0).1.add_schema::<Res>(&self.1, "read_all", "result_body");
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 path = format!("/{}", &self.1);
let mut item = (self.0).1.remove_path(&path); let mut item = (self.0).1.remove_path(&path);
let mut content : IndexMap<String, MediaType> = IndexMap::new(); item.get = Some(new_operation(&schema, vec![]));
content.insert(APPLICATION_JSON.to_string(), MediaType {
schema: Some(Reference {
reference: format!("#/components/schemas/{}", schema)
}),
example: None,
examples: IndexMap::new(),
encoding: IndexMap::new()
});
let mut responses : IndexMap<StatusCode, ReferenceOr<Response>> = IndexMap::new();
responses.insert(StatusCode::Code(200), Item(Response {
description: "OK".to_string(),
headers: IndexMap::new(),
content,
links: IndexMap::new()
}));
item.get = Some(Operation {
tags: Vec::new(),
summary: None,
description: None,
external_documentation: None,
operation_id: None, // TODO
parameters: Vec::new(),
request_body: None,
responses: Responses {
default: None,
responses
},
deprecated: false,
security: Vec::new(),
servers: Vec::new()
});
(self.0).1.add_path(path, item); (self.0).1.add_path(path, item);
(&mut *(self.0).0, self.1.to_string()).read_all::<Handler, Res>() (&mut *(self.0).0, self.1.to_string()).read_all::<Handler, Res>()
@ -216,6 +256,13 @@ macro_rules! implOpenapiRouter {
Res : ResourceResult, Res : ResourceResult,
Handler : ResourceRead<ID, Res> Handler : ResourceRead<ID, Res>
{ {
let schema = (self.0).1.add_schema::<Res>(&self.1, "read", "result_body");
let path = format!("/{}/{{id}}", &self.1);
let mut item = (self.0).1.remove_path(&path);
item.get = Some(new_operation(&schema, vec!["id"]));
(self.0).1.add_path(path, item);
(&mut *(self.0).0, self.1.to_string()).read::<Handler, ID, Res>() (&mut *(self.0).0, self.1.to_string()).read::<Handler, ID, Res>()
} }

View file

@ -1,4 +1,5 @@
use crate::{ResourceType, StatusCode}; use crate::{ResourceType, StatusCode};
#[cfg(feature = "openapi")]
use openapiv3::SchemaKind; use openapiv3::SchemaKind;
use serde::Serialize; use serde::Serialize;
use serde_json::error::Error as SerdeJsonError; use serde_json::error::Error as SerdeJsonError;