routerify/ext/request.rs
1use crate::data_map::SharedDataMap;
2use crate::types::{RequestContext, RequestMeta, RouteParams};
3use hyper::Request;
4use std::net::SocketAddr;
5
6/// A extension trait which extends the [`hyper::Request`](https://docs.rs/hyper/0.14.4/hyper/struct.Request.html) and [`http::Parts`](https://docs.rs/http/0.2.4/http/request/struct.Parts.html) types with some helpful methods.
7pub trait RequestExt {
8 /// It returns the route parameters as [RouteParams](../struct.RouteParams.html) type with the name of the parameter specified in the path as their respective keys.
9 ///
10 /// # Examples
11 ///
12 /// ```
13 /// use routerify::{Router, RouteParams};
14 /// use routerify::ext::RequestExt;
15 /// use hyper::{Response, Body};
16 /// # use std::convert::Infallible;
17 ///
18 /// # fn run() -> Router<Body, Infallible> {
19 /// let router = Router::builder()
20 /// .get("/users/:userName/books/:bookName", |req| async move {
21 /// let params: &RouteParams = req.params();
22 /// let user_name = params.get("userName").unwrap();
23 /// let book_name = params.get("bookName").unwrap();
24 ///
25 /// Ok(Response::new(Body::from(format!("Username: {}, Book Name: {}", user_name, book_name))))
26 /// })
27 /// .build()
28 /// .unwrap();
29 /// # router
30 /// # }
31 /// # run();
32 /// ```
33 fn params(&self) -> &RouteParams;
34
35 /// It returns the route parameter value by the name of the parameter specified in the path.
36 ///
37 /// # Examples
38 ///
39 /// ```
40 /// use routerify::{Router, RouteParams};
41 /// use routerify::ext::RequestExt;
42 /// use hyper::{Response, Body};
43 /// # use std::convert::Infallible;
44 ///
45 /// # fn run() -> Router<Body, Infallible> {
46 /// let router = Router::builder()
47 /// .get("/users/:userName/books/:bookName", |req| async move {
48 /// let user_name = req.param("userName").unwrap();
49 /// let book_name = req.param("bookName").unwrap();
50 ///
51 /// Ok(Response::new(Body::from(format!("Username: {}, Book Name: {}", user_name, book_name))))
52 /// })
53 /// .build()
54 /// .unwrap();
55 /// # router
56 /// # }
57 /// # run();
58 /// ```
59 fn param<P: Into<String>>(&self, param_name: P) -> Option<&String>;
60
61 /// It returns the remote address of the incoming request.
62 ///
63 /// # Examples
64 ///
65 /// ```
66 /// use routerify::{Router, RouteParams};
67 /// use routerify::ext::RequestExt;
68 /// use hyper::{Response, Body};
69 /// # use std::convert::Infallible;
70 ///
71 /// # fn run() -> Router<Body, Infallible> {
72 /// let router = Router::builder()
73 /// .get("/hello", |req| async move {
74 /// let remote_addr = req.remote_addr();
75 ///
76 /// Ok(Response::new(Body::from(format!("Hello from : {}", remote_addr))))
77 /// })
78 /// .build()
79 /// .unwrap();
80 /// # router
81 /// # }
82 /// # run();
83 /// ```
84 fn remote_addr(&self) -> SocketAddr;
85
86 /// Access data which was shared by the [`RouterBuilder`](../struct.RouterBuilder.html) method
87 /// [`data`](../struct.RouterBuilder.html#method.data).
88 ///
89 /// Please refer to the [Data and State Sharing](../index.html#data-and-state-sharing) for more info.
90 fn data<T: Send + Sync + 'static>(&self) -> Option<&T>;
91
92 /// Access data in the request context.
93 fn context<T: Send + Sync + Clone + 'static>(&self) -> Option<T>;
94
95 /// Put data into the request context.
96 ///
97 /// # Examples
98 ///
99 /// ```
100 /// use routerify::{Router, RouteParams, Middleware};
101 /// use routerify::ext::RequestExt;
102 /// use hyper::{Response, Request, Body};
103 /// # use std::convert::Infallible;
104 ///
105 /// # fn run() -> Router<Body, Infallible> {
106 /// let router = Router::builder()
107 /// .middleware(Middleware::pre(|req: Request<Body>| async move {
108 /// req.set_context("example".to_string());
109 ///
110 /// Ok(req)
111 /// }))
112 /// .get("/hello", |req| async move {
113 /// let text = req.context::<String>().unwrap();
114 ///
115 /// Ok(Response::new(Body::from(format!("Hello from : {}", text))))
116 /// })
117 /// .build()
118 /// .unwrap();
119 /// # router
120 /// # }
121 /// # run();
122 /// ```
123 fn set_context<T: Send + Sync + Clone + 'static>(&self, val: T);
124}
125
126fn params(ext: &http::Extensions) -> &RouteParams {
127 ext.get::<RequestMeta>()
128 .and_then(|meta| meta.route_params())
129 .expect("Routerify: No RouteParams added while processing request")
130}
131
132fn param<P: Into<String>>(ext: &http::Extensions, param_name: P) -> Option<&String> {
133 params(ext).get(¶m_name.into())
134}
135
136fn remote_addr(ext: &http::Extensions) -> SocketAddr {
137 ext.get::<RequestMeta>()
138 .and_then(|meta| meta.remote_addr())
139 .copied()
140 .expect("Routerify: No remote address added while processing request")
141}
142
143fn data<T: Send + Sync + 'static>(ext: &http::Extensions) -> Option<&T> {
144 let shared_data_maps = ext.get::<Vec<SharedDataMap>>();
145
146 if let Some(shared_data_maps) = shared_data_maps {
147 for shared_data_map in shared_data_maps.iter() {
148 if let Some(data) = shared_data_map.inner.get::<T>() {
149 return Some(data);
150 }
151 }
152 }
153
154 None
155}
156
157fn context<T: Send + Sync + Clone + 'static>(ext: &http::Extensions) -> Option<T> {
158 let ctx = ext.get::<RequestContext>().expect("Context must be present");
159 ctx.get::<T>()
160}
161
162fn set_context<T: Send + Sync + Clone + 'static>(ext: &http::Extensions, val: T) {
163 let ctx = ext.get::<RequestContext>().expect("Context must be present");
164 ctx.set(val)
165}
166
167impl RequestExt for Request<hyper::Body> {
168 fn params(&self) -> &RouteParams {
169 params(self.extensions())
170 }
171
172 fn param<P: Into<String>>(&self, param_name: P) -> Option<&String> {
173 param(self.extensions(), param_name)
174 }
175
176 fn remote_addr(&self) -> SocketAddr {
177 remote_addr(self.extensions())
178 }
179
180 fn data<T: Send + Sync + 'static>(&self) -> Option<&T> {
181 data(self.extensions())
182 }
183
184 fn context<T: Send + Sync + Clone + 'static>(&self) -> Option<T> {
185 context(self.extensions())
186 }
187
188 fn set_context<T: Send + Sync + Clone + 'static>(&self, val: T) {
189 set_context(self.extensions(), val)
190 }
191}
192
193impl RequestExt for http::request::Parts {
194 fn params(&self) -> &RouteParams {
195 params(&self.extensions)
196 }
197
198 fn param<P: Into<String>>(&self, param_name: P) -> Option<&String> {
199 param(&self.extensions, param_name)
200 }
201
202 fn remote_addr(&self) -> SocketAddr {
203 remote_addr(&self.extensions)
204 }
205
206 fn data<T: Send + Sync + 'static>(&self) -> Option<&T> {
207 data(&self.extensions)
208 }
209
210 fn context<T: Send + Sync + Clone + 'static>(&self) -> Option<T> {
211 context(&self.extensions)
212 }
213
214 fn set_context<T: Send + Sync + Clone + 'static>(&self, val: T) {
215 set_context(&self.extensions, val)
216 }
217}