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:
parent
4c50ea0959
commit
7486c23727
1 changed files with 191 additions and 146 deletions
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue