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

don't require the get_openapi call be the last one to contain the full spec

This commit is contained in:
Dominic 2020-04-26 22:20:07 +02:00
parent 96317cdfb7
commit b4eaeca01c
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
3 changed files with 53 additions and 32 deletions

View file

@ -157,7 +157,7 @@ pub mod matcher;
mod openapi; mod openapi;
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
pub use openapi::{ pub use openapi::{
router::{GetOpenapi, OpenapiRouter}, router::GetOpenapi,
types::{OpenapiSchema, OpenapiType} types::{OpenapiSchema, OpenapiType}
}; };

View file

@ -24,7 +24,8 @@ use openapiv3::{
}; };
use std::{ use std::{
panic::RefUnwindSafe, panic::RefUnwindSafe,
pin::Pin pin::Pin,
sync::{Arc, RwLock}
}; };
/** /**
@ -33,13 +34,17 @@ same time. There is no need to use this type directly. See [`WithOpenapi`] on ho
[`WithOpenapi`]: trait.WithOpenapi.html [`WithOpenapi`]: trait.WithOpenapi.html
*/ */
pub struct OpenapiRouter(OpenAPI); pub struct OpenapiBuilder
{
openapi : Arc<RwLock<OpenAPI>>
}
impl OpenapiRouter impl OpenapiBuilder
{ {
pub fn new(title : String, version : String, url : String) -> Self pub fn new(title : String, version : String, url : String) -> Self
{ {
Self(OpenAPI { Self {
openapi: Arc::new(RwLock::new(OpenAPI {
openapi: "3.0.2".to_string(), openapi: "3.0.2".to_string(),
info: openapiv3::Info { info: openapiv3::Info {
title, version, title, version,
@ -50,14 +55,16 @@ impl OpenapiRouter
..Default::default() ..Default::default()
}], }],
..Default::default() ..Default::default()
}) }))
}
} }
/// Remove path from the OpenAPI spec, or return an empty one if not included. This is handy if you need to /// Remove path from the OpenAPI spec, or return an empty one if not included. This is handy if you need to
/// modify the path and add it back after the modification /// modify the path and add it back after the modification
fn remove_path(&mut self, path : &str) -> PathItem fn remove_path(&mut self, path : &str) -> PathItem
{ {
match self.0.paths.swap_remove(path) { let mut openapi = self.openapi.write().unwrap();
match openapi.paths.swap_remove(path) {
Some(Item(item)) => item, Some(Item(item)) => item,
_ => PathItem::default() _ => PathItem::default()
} }
@ -65,21 +72,23 @@ impl OpenapiRouter
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)); let mut openapi = self.openapi.write().unwrap();
openapi.paths.insert(path.to_string(), Item(item));
} }
fn add_schema_impl(&mut self, name : String, mut schema : OpenapiSchema) fn add_schema_impl(&mut self, name : String, mut schema : OpenapiSchema)
{ {
self.add_schema_dependencies(&mut schema.dependencies); self.add_schema_dependencies(&mut schema.dependencies);
match &mut self.0.components { let mut openapi = self.openapi.write().unwrap();
match &mut openapi.components {
Some(comp) => { Some(comp) => {
comp.schemas.insert(name, Item(schema.into_schema())); comp.schemas.insert(name, Item(schema.into_schema()));
}, },
None => { None => {
let mut comp = Components::default(); let mut comp = Components::default();
comp.schemas.insert(name, Item(schema.into_schema())); comp.schemas.insert(name, Item(schema.into_schema()));
self.0.components = Some(comp); openapi.components = Some(comp);
} }
}; };
} }
@ -115,13 +124,16 @@ impl OpenapiRouter
} }
#[derive(Clone)] #[derive(Clone)]
struct OpenapiHandler(OpenAPI); struct OpenapiHandler
{
openapi : Arc<RwLock<OpenAPI>>
}
impl OpenapiHandler impl OpenapiHandler
{ {
fn new(openapi : &OpenapiRouter) -> Self fn new(openapi : Arc<RwLock<OpenAPI>>) -> Self
{ {
Self(openapi.0.clone()) Self { openapi }
} }
} }
@ -180,7 +192,16 @@ impl Handler for OpenapiHandler
{ {
fn handle(self, mut state : State) -> Pin<Box<HandlerFuture>> fn handle(self, mut state : State) -> Pin<Box<HandlerFuture>>
{ {
let mut openapi = self.0; let openapi = match self.openapi.read() {
Ok(openapi) => openapi,
Err(e) => {
error!("Unable to acquire read lock for the OpenAPI specification: {}", e);
let res = create_response(&state, crate::StatusCode::INTERNAL_SERVER_ERROR, TEXT_PLAIN, "");
return future::ok((state, res)).boxed()
}
};
let mut openapi = openapi.clone();
let security_schemes = get_security(&mut state); let security_schemes = get_security(&mut state);
let mut components = openapi.components.unwrap_or_default(); let mut components = openapi.components.unwrap_or_default();
components.security_schemes = security_schemes; components.security_schemes = security_schemes;
@ -353,18 +374,18 @@ fn new_operation(
macro_rules! implOpenapiRouter { macro_rules! implOpenapiRouter {
($implType:ident) => { ($implType:ident) => {
impl<'a, C, P> GetOpenapi for (&mut $implType<'a, C, P>, &mut OpenapiRouter) impl<'a, C, P> GetOpenapi for (&mut $implType<'a, C, P>, &mut OpenapiBuilder)
where where
C : PipelineHandleChain<P> + Copy + Send + Sync + 'static, C : PipelineHandleChain<P> + Copy + Send + Sync + 'static,
P : RefUnwindSafe + Send + Sync + 'static P : RefUnwindSafe + Send + Sync + 'static
{ {
fn get_openapi(&mut self, path : &str) fn get_openapi(&mut self, path : &str)
{ {
self.0.get(path).to_new_handler(OpenapiHandler::new(&self.1)); self.0.get(path).to_new_handler(OpenapiHandler::new(self.1.openapi.clone()));
} }
} }
impl<'a, C, P> DrawResources for (&mut $implType<'a, C, P>, &mut OpenapiRouter) impl<'a, C, P> DrawResources for (&mut $implType<'a, C, P>, &mut OpenapiBuilder)
where where
C : PipelineHandleChain<P> + Copy + Send + Sync + 'static, C : PipelineHandleChain<P> + Copy + Send + Sync + 'static,
P : RefUnwindSafe + Send + Sync + 'static P : RefUnwindSafe + Send + Sync + 'static
@ -375,7 +396,7 @@ macro_rules! implOpenapiRouter {
} }
} }
impl<'a, C, P> DrawResourceRoutes for (&mut (&mut $implType<'a, C, P>, &mut OpenapiRouter), &str) impl<'a, C, P> DrawResourceRoutes for (&mut (&mut $implType<'a, C, P>, &mut OpenapiBuilder), &str)
where where
C : PipelineHandleChain<P> + Copy + Send + Sync + 'static, C : PipelineHandleChain<P> + Copy + Send + Sync + 'static,
P : RefUnwindSafe + Send + Sync + 'static P : RefUnwindSafe + Send + Sync + 'static

View file

@ -6,7 +6,7 @@ use crate::{
StatusCode StatusCode
}; };
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
use crate::OpenapiRouter; use crate::openapi::router::OpenapiBuilder;
use futures_util::{future, future::FutureExt}; use futures_util::{future, future::FutureExt};
use gotham::{ use gotham::{
@ -49,7 +49,7 @@ pub trait WithOpenapi<D>
{ {
fn with_openapi<F>(&mut self, title : String, version : String, server_url : String, block : F) fn with_openapi<F>(&mut self, title : String, version : String, server_url : String, block : F)
where where
F : FnOnce((&mut D, &mut OpenapiRouter)); F : FnOnce((&mut D, &mut OpenapiBuilder));
} }
/// This trait adds the `resource` method to gotham's routing. It allows you to register /// This trait adds the `resource` method to gotham's routing. It allows you to register
@ -316,9 +316,9 @@ macro_rules! implDrawResourceRoutes {
{ {
fn with_openapi<F>(&mut self, title : String, version : String, server_url : String, block : F) fn with_openapi<F>(&mut self, title : String, version : String, server_url : String, block : F)
where where
F : FnOnce((&mut Self, &mut OpenapiRouter)) F : FnOnce((&mut Self, &mut OpenapiBuilder))
{ {
let mut router = OpenapiRouter::new(title, version, server_url); let mut router = OpenapiBuilder::new(title, version, server_url);
block((self, &mut router)); block((self, &mut router));
} }
} }