1
0
Fork 0
mirror of https://gitlab.com/msrd0/gotham-restful.git synced 2025-02-22 20:52:27 +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;
#[cfg(feature = "openapi")]
pub use openapi::{
router::{GetOpenapi, OpenapiRouter},
router::GetOpenapi,
types::{OpenapiSchema, OpenapiType}
};

View file

@ -24,7 +24,8 @@ use openapiv3::{
};
use std::{
panic::RefUnwindSafe,
pin::Pin
pin::Pin,
sync::{Arc, RwLock}
};
/**
@ -33,31 +34,37 @@ same time. There is no need to use this type directly. See [`WithOpenapi`] on ho
[`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
{
Self(OpenAPI {
openapi: "3.0.2".to_string(),
info: openapiv3::Info {
title, version,
Self {
openapi: Arc::new(RwLock::new(OpenAPI {
openapi: "3.0.2".to_string(),
info: openapiv3::Info {
title, version,
..Default::default()
},
servers: vec![Server {
url,
..Default::default()
}],
..Default::default()
},
servers: vec![Server {
url,
..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
/// modify the path and add it back after the modification
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,
_ => PathItem::default()
}
@ -65,21 +72,23 @@ impl OpenapiRouter
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)
{
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) => {
comp.schemas.insert(name, Item(schema.into_schema()));
},
None => {
let mut comp = Components::default();
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)]
struct OpenapiHandler(OpenAPI);
struct OpenapiHandler
{
openapi : Arc<RwLock<OpenAPI>>
}
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>>
{
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 mut components = openapi.components.unwrap_or_default();
components.security_schemes = security_schemes;
@ -353,18 +374,18 @@ fn new_operation(
macro_rules! implOpenapiRouter {
($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
C : PipelineHandleChain<P> + Copy + Send + Sync + 'static,
P : RefUnwindSafe + Send + Sync + 'static
{
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
C : PipelineHandleChain<P> + Copy + 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
C : PipelineHandleChain<P> + Copy + Send + Sync + 'static,
P : RefUnwindSafe + Send + Sync + 'static

View file

@ -6,7 +6,7 @@ use crate::{
StatusCode
};
#[cfg(feature = "openapi")]
use crate::OpenapiRouter;
use crate::openapi::router::OpenapiBuilder;
use futures_util::{future, future::FutureExt};
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)
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
@ -316,9 +316,9 @@ macro_rules! implDrawResourceRoutes {
{
fn with_openapi<F>(&mut self, title : String, version : String, server_url : String, block : F)
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));
}
}