Skip to content

Commit 1cb9af2

Browse files
committed
introduce the ideas of Before and After middlewares
1 parent eb872dd commit 1cb9af2

3 files changed

Lines changed: 78 additions & 3 deletions

File tree

examples/middleware.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ use std::future::Future;
22
use std::pin::Pin;
33
use std::sync::atomic::{AtomicUsize, Ordering};
44
use std::sync::Arc;
5-
use tide::{Middleware, Next, Request, Response, Result, StatusCode};
5+
use tide::{After, Before, Middleware, Next, Request, Response, Result, StatusCode};
66

77
#[derive(Debug)]
88
struct User {
99
name: String,
1010
}
1111

12-
#[derive(Default)]
12+
#[derive(Default, Debug)]
1313
struct UserDatabase;
1414
impl UserDatabase {
1515
async fn find_user(&self) -> Option<User> {
@@ -77,14 +77,37 @@ impl<State: Send + Sync + 'static> Middleware<State> for RequestCounterMiddlewar
7777
})
7878
}
7979
}
80+
const NOT_FOUND_HTML_PAGE: &str = "<html><body>
81+
<h1>uh oh, we couldn't find that document</h1>
82+
<p>
83+
probably, this would be served from the file system or
84+
included with `include_bytes!`
85+
</p>
86+
</body></html>";
8087

8188
#[async_std::main]
8289
async fn main() -> Result<()> {
8390
tide::log::start();
8491
let mut app = tide::with_state(UserDatabase::default());
8592

93+
app.middleware(After::new(|result: Result| async move {
94+
let response = result.unwrap_or_else(|e| Response::new(e.status()));
95+
match response.status() {
96+
StatusCode::NotFound => Ok(Response::new(response.status())
97+
.set_mime(tide::http::mime::HTML)
98+
.body_string(NOT_FOUND_HTML_PAGE.into())),
99+
_ => Ok(response),
100+
}
101+
}));
102+
86103
app.middleware(user_loader);
87104
app.middleware(RequestCounterMiddleware::new(0));
105+
app.middleware(Before::new(
106+
|mut request: Request<UserDatabase>| async move {
107+
request.set_ext(std::time::Instant::now());
108+
request
109+
},
110+
));
88111

89112
app.at("/").get(|req: Request<_>| async move {
90113
let count: &RequestCount = req.ext().unwrap();

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ pub mod security;
211211
pub mod sse;
212212

213213
pub use endpoint::Endpoint;
214-
pub use middleware::{Middleware, Next};
214+
pub use middleware::{After, Before, Middleware, Next};
215215
pub use redirect::Redirect;
216216
pub use request::Request;
217217
pub use response::Response;

src/middleware.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,58 @@ pub trait Middleware<State>: 'static + Send + Sync {
2727
}
2828
}
2929

30+
#[derive(Debug)]
31+
pub struct Before<F>(F);
32+
impl<F> Before<F> {
33+
pub fn new(f: F) -> Self {
34+
Self(f)
35+
}
36+
}
37+
38+
impl<State, F, Fut> Middleware<State> for Before<F>
39+
where
40+
State: Send + Sync + 'static,
41+
F: Fn(Request<State>) -> Fut + Send + Sync + 'static,
42+
Fut: std::future::Future<Output = Request<State>> + Send + Sync,
43+
{
44+
fn handle<'a>(
45+
&'a self,
46+
request: Request<State>,
47+
next: Next<'a, State>,
48+
) -> BoxFuture<'a, crate::Result> {
49+
Box::pin(async move {
50+
let request = (self.0)(request).await;
51+
next.run(request).await
52+
})
53+
}
54+
}
55+
56+
#[derive(Debug)]
57+
pub struct After<F>(F);
58+
impl<F> After<F> {
59+
pub fn new(f: F) -> Self {
60+
Self(f)
61+
}
62+
}
63+
64+
impl<State, F, Fut> Middleware<State> for After<F>
65+
where
66+
State: Send + Sync + 'static,
67+
F: Fn(crate::Result) -> Fut + Send + Sync + 'static,
68+
Fut: std::future::Future<Output = crate::Result> + Send + Sync,
69+
{
70+
fn handle<'a>(
71+
&'a self,
72+
request: Request<State>,
73+
next: Next<'a, State>,
74+
) -> BoxFuture<'a, crate::Result> {
75+
Box::pin(async move {
76+
let result = next.run(request).await;
77+
(self.0)(result).await
78+
})
79+
}
80+
}
81+
3082
impl<State, F> Middleware<State> for F
3183
where
3284
F: Send

0 commit comments

Comments
 (0)