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

update routing to properly extend every DrawRoutes type

This commit is contained in:
Dominic 2020-03-30 16:32:53 +02:00
parent 4c50ea0959
commit 7486c23727
Signed by: msrd0
GPG key ID: DCC8C247452E98F9

View file

@ -16,7 +16,10 @@ use gotham::{
extractor::QueryStringExtractor, extractor::QueryStringExtractor,
handler::{HandlerFuture, IntoHandlerError}, handler::{HandlerFuture, IntoHandlerError},
helpers::http::response::{create_empty_response, create_response}, helpers::http::response::{create_empty_response, create_response},
pipeline::chain::PipelineHandleChain, pipeline::{
chain::PipelineHandleChain,
set::PipelineSet
},
router::{ router::{
builder::*, builder::*,
non_match::RouteNonMatch, non_match::RouteNonMatch,
@ -24,7 +27,8 @@ use gotham::{
content_type::ContentTypeHeaderRouteMatcher, content_type::ContentTypeHeaderRouteMatcher,
AcceptHeaderRouteMatcher, AcceptHeaderRouteMatcher,
RouteMatcher RouteMatcher
} },
tree::node::Node
}, },
state::{FromState, State} state::{FromState, State}
}; };
@ -49,7 +53,10 @@ struct PathExtractor<ID : RefUnwindSafe + Send + 'static>
/// router into one that will only allow RESTful resources, but record them and generate /// router into one that will only allow RESTful resources, but record them and generate
/// an OpenAPI specification on request. /// an OpenAPI specification on request.
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
pub trait WithOpenapi<D> pub trait WithOpenapi<C, P>
where
C : PipelineHandleChain<P> + Copy + Send + Sync + 'static,
P : RefUnwindSafe + Send + Sync + 'static
{ {
fn with_openapi<F, Title, Version, Url>(&mut self, title : Title, version : Version, server_url : Url, block : F) fn with_openapi<F, Title, Version, Url>(&mut self, title : Title, version : Version, server_url : Url, block : F)
where where
@ -61,9 +68,12 @@ pub trait WithOpenapi<D>
/// 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
/// any RESTful `Resource` with a path. /// any RESTful `Resource` with a path.
pub trait DrawResources pub trait DrawResources<C, P>
where
C : PipelineHandleChain<P> + Copy + Send + Sync + 'static,
P : RefUnwindSafe + Send + Sync + 'static
{ {
fn resource<R : Resource, T : ToString>(&mut self, path : T); fn resource<R : Resource>(&mut self, path : &str);
} }
/// This trait allows to draw routes within an resource. Use this only inside the /// This trait allows to draw routes within an resource. Use this only inside the
@ -336,151 +346,186 @@ impl From<Option<Vec<Mime>>> for MaybeMatchContentTypeHeader
} }
} }
macro_rules! implDrawResourceRoutes { #[cfg(feature = "openapi")]
($implType:ident) => { impl<C, P, T> WithOpenapi<C, P> for T
where
C : PipelineHandleChain<P> + Copy + Send + Sync + 'static,
P : RefUnwindSafe + Send + Sync + 'static,
T : DrawRoutes<C, P>
{
fn with_openapi<F, Title, Version, Url>(&mut self, title : Title, version : Version, server_url : Url, block : F)
where
F : FnOnce((&mut Self, &mut OpenapiRouter)),
Title : ToString,
Version : ToString,
Url : ToString
{
let mut router = OpenapiRouter::new(title, version, server_url);
block((self, &mut router));
}
}
#[cfg(feature = "openapi")] impl<C, P, T> DrawResources<C, P> for T
impl<'a, C, P> WithOpenapi<Self> for $implType<'a, C, P> 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 T : DrawRoutes<C, P>
{ {
fn with_openapi<F, Title, Version, Url>(&mut self, title : Title, version : Version, server_url : Url, block : F) fn resource<R : Resource>(&mut self, path : &str)
where {
F : FnOnce((&mut Self, &mut OpenapiRouter)), R::setup(ResourceSetup::new(self, path));
Title : ToString, }
Version : ToString, }
Url : ToString
{
let mut router = OpenapiRouter::new(title, version, server_url);
block((self, &mut router));
}
}
impl<'a, C, P> DrawResources for $implType<'a, C, P> struct ResourceSetup<'a, C, P>
where where
C : PipelineHandleChain<P> + Copy + Send + Sync + 'static, C : PipelineHandleChain<P> + Copy + Send + Sync + 'static,
P : RefUnwindSafe + Send + Sync + 'static P : Send + Sync + 'static
{ {
fn resource<R : Resource, T : ToString>(&mut self, path : T) node_builder : &'a mut Node,
{ pipeline_chain : C,
R::setup((self, path.to_string())); pipelines : PipelineSet<P>,
} path : &'a str
} }
#[allow(clippy::redundant_closure)] // doesn't work because of type parameters impl<'a, C, P> ResourceSetup<'a, C, P>
impl<'a, C, P> DrawResourceRoutes for (&mut $implType<'a, C, P>, String) 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 new<D>(router : &'a mut D, path : &'a str) -> Self
fn read_all<Handler, Res>(&mut self) where
where D : DrawRoutes<C, P> + 'a
Res : ResourceResult, {
Handler : ResourceReadAll<Res> let (node_builder, pipeline_chain, pipelines) = router.component_refs();
{ Self {
let matcher : MaybeMatchAcceptHeader = Res::accepted_types().into(); node_builder,
self.0.get(&self.1) pipeline_chain: *pipeline_chain,
.extend_route_matcher(matcher) pipelines: pipelines.clone(),
.to(|state| read_all_handler::<Handler, Res>(state)); path
}
fn read<Handler, ID, Res>(&mut self)
where
ID : DeserializeOwned + Clone + RefUnwindSafe + Send + Sync + 'static,
Res : ResourceResult,
Handler : ResourceRead<ID, Res>
{
let matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
self.0.get(&format!("{}/:id", self.1))
.extend_route_matcher(matcher)
.with_path_extractor::<PathExtractor<ID>>()
.to(|state| read_handler::<Handler, ID, Res>(state));
}
fn search<Handler, Query, Res>(&mut self)
where
Query : ResourceType + QueryStringExtractor<Body> + Send + Sync + 'static,
Res : ResourceResult,
Handler : ResourceSearch<Query, Res>
{
let matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
self.0.get(&format!("{}/search", self.1))
.extend_route_matcher(matcher)
.with_query_string_extractor::<Query>()
.to(|state| search_handler::<Handler, Query, Res>(state));
}
fn create<Handler, Body, Res>(&mut self)
where
Body : RequestBody,
Res : ResourceResult,
Handler : ResourceCreate<Body, Res>
{
let accept_matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
let content_matcher : MaybeMatchContentTypeHeader = Body::supported_types().into();
self.0.post(&self.1)
.extend_route_matcher(accept_matcher)
.extend_route_matcher(content_matcher)
.to(|state| create_handler::<Handler, Body, Res>(state));
}
fn update_all<Handler, Body, Res>(&mut self)
where
Body : RequestBody,
Res : ResourceResult,
Handler : ResourceUpdateAll<Body, Res>
{
let accept_matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
let content_matcher : MaybeMatchContentTypeHeader = Body::supported_types().into();
self.0.put(&self.1)
.extend_route_matcher(accept_matcher)
.extend_route_matcher(content_matcher)
.to(|state| update_all_handler::<Handler, Body, Res>(state));
}
fn update<Handler, ID, Body, Res>(&mut self)
where
ID : DeserializeOwned + Clone + RefUnwindSafe + Send + Sync + 'static,
Body : RequestBody,
Res : ResourceResult,
Handler : ResourceUpdate<ID, Body, Res>
{
let accept_matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
let content_matcher : MaybeMatchContentTypeHeader = Body::supported_types().into();
self.0.put(&format!("{}/:id", self.1))
.extend_route_matcher(accept_matcher)
.extend_route_matcher(content_matcher)
.with_path_extractor::<PathExtractor<ID>>()
.to(|state| update_handler::<Handler, ID, Body, Res>(state));
}
fn delete_all<Handler, Res>(&mut self)
where
Res : ResourceResult,
Handler : ResourceDeleteAll<Res>
{
let matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
self.0.delete(&self.1)
.extend_route_matcher(matcher)
.to(|state| delete_all_handler::<Handler, Res>(state));
}
fn delete<Handler, ID, Res>(&mut self)
where
ID : DeserializeOwned + Clone + RefUnwindSafe + Send + Sync + 'static,
Res : ResourceResult,
Handler : ResourceDelete<ID, Res>
{
let matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
self.0.delete(&format!("{}/:id", self.1))
.extend_route_matcher(matcher)
.with_path_extractor::<PathExtractor<ID>>()
.to(|state| delete_handler::<Handler, ID, Res>(state));
}
} }
} }
} }
implDrawResourceRoutes!(RouterBuilder); impl<'a, C, P> DrawRoutes<C, P> for ResourceSetup<'a, C, P>
implDrawResourceRoutes!(ScopeBuilder); where
C : PipelineHandleChain<P> + Copy + Send + Sync + 'static,
P : RefUnwindSafe + Send + Sync + 'static
{
fn component_refs(&mut self) -> (&mut Node, &mut C, &PipelineSet<P>)
{
(&mut self.node_builder, &mut self.pipeline_chain, &self.pipelines)
}
}
#[allow(clippy::redundant_closure)] // doesn't work because of type parameters
impl<'a, C, P> DrawResourceRoutes for ResourceSetup<'a, C, P>
where
C : PipelineHandleChain<P> + Copy + Send + Sync + 'static,
P : RefUnwindSafe + Send + Sync + 'static
{
fn read_all<Handler, Res>(&mut self)
where
Res : ResourceResult,
Handler : ResourceReadAll<Res>
{
let matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
self.get(self.path)
.extend_route_matcher(matcher)
.to(|state| read_all_handler::<Handler, Res>(state));
}
fn read<Handler, ID, Res>(&mut self)
where
ID : DeserializeOwned + Clone + RefUnwindSafe + Send + Sync + 'static,
Res : ResourceResult,
Handler : ResourceRead<ID, Res>
{
let matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
self.get(&format!("{}/:id", self.path))
.extend_route_matcher(matcher)
.with_path_extractor::<PathExtractor<ID>>()
.to(|state| read_handler::<Handler, ID, Res>(state));
}
fn search<Handler, Query, Res>(&mut self)
where
Query : ResourceType + QueryStringExtractor<Body> + Send + Sync + 'static,
Res : ResourceResult,
Handler : ResourceSearch<Query, Res>
{
let matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
self.get(&format!("{}/search", self.path))
.extend_route_matcher(matcher)
.with_query_string_extractor::<Query>()
.to(|state| search_handler::<Handler, Query, Res>(state));
}
fn create<Handler, Body, Res>(&mut self)
where
Body : RequestBody,
Res : ResourceResult,
Handler : ResourceCreate<Body, Res>
{
let accept_matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
let content_matcher : MaybeMatchContentTypeHeader = Body::supported_types().into();
self.post(self.path)
.extend_route_matcher(accept_matcher)
.extend_route_matcher(content_matcher)
.to(|state| create_handler::<Handler, Body, Res>(state));
}
fn update_all<Handler, Body, Res>(&mut self)
where
Body : RequestBody,
Res : ResourceResult,
Handler : ResourceUpdateAll<Body, Res>
{
let accept_matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
let content_matcher : MaybeMatchContentTypeHeader = Body::supported_types().into();
self.put(self.path)
.extend_route_matcher(accept_matcher)
.extend_route_matcher(content_matcher)
.to(|state| update_all_handler::<Handler, Body, Res>(state));
}
fn update<Handler, ID, Body, Res>(&mut self)
where
ID : DeserializeOwned + Clone + RefUnwindSafe + Send + Sync + 'static,
Body : RequestBody,
Res : ResourceResult,
Handler : ResourceUpdate<ID, Body, Res>
{
let accept_matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
let content_matcher : MaybeMatchContentTypeHeader = Body::supported_types().into();
self.put(&format!("{}/:id", self.path))
.extend_route_matcher(accept_matcher)
.extend_route_matcher(content_matcher)
.with_path_extractor::<PathExtractor<ID>>()
.to(|state| update_handler::<Handler, ID, Body, Res>(state));
}
fn delete_all<Handler, Res>(&mut self)
where
Res : ResourceResult,
Handler : ResourceDeleteAll<Res>
{
let matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
DrawRoutes::delete(self, self.path)
.extend_route_matcher(matcher)
.to(|state| delete_all_handler::<Handler, Res>(state));
}
fn delete<Handler, ID, Res>(&mut self)
where
ID : DeserializeOwned + Clone + RefUnwindSafe + Send + Sync + 'static,
Res : ResourceResult,
Handler : ResourceDelete<ID, Res>
{
let matcher : MaybeMatchAcceptHeader = Res::accepted_types().into();
DrawRoutes::delete(self, &format!("{}/:id", self.path))
.extend_route_matcher(matcher)
.with_path_extractor::<PathExtractor<ID>>()
.to(|state| delete_handler::<Handler, ID, Res>(state));
}
}