Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Add impl Middlware to support simple stateless middlewares #854

Open
NfNitLoop opened this issue Oct 17, 2021 · 1 comment
Labels
enhancement New feature or request

Comments

@NfNitLoop
Copy link

NfNitLoop commented Oct 17, 2021

I read a blog post that included a simplified middleware so I wrote one of my own:

/// Middleware that disables browser caching by default.
async fn no_store<'a, Data>(req: tide::Request<Data>, next: tide::Next<'a, Data>) -> tide::Result<Response>
where Data: Clone + Send + Sync + 'static
{
    use tide::http::cache::{CacheControl, CacheDirective};
    let mut response = next.run(req).await;

    if let None = response.header("Cache-Control") {
        let mut header = CacheControl::new();
        header.push(CacheDirective::NoStore);
        header.push(CacheDirective::MaxAge(Duration::from_secs(0)));

        response.insert_header(header.name(), header.value());
    }
    Ok(response)
}

Unfortunately, that didn't work. Off to the API docs, and I find that Middleware only has an impl for:

impl<State, F> Middleware<State> for F
where
    State: Clone + Send + Sync + 'static,
    F: Send + Sync + 'static + for<'a> Fn(Request<State>, Next<'a, State>) -> Pin<Box<dyn Future<Output = Result> + Send + 'a>>, 

At this point, as a merely intermediate Rust user, my eyes glazed over. So I generated my own impl like this: (Though I had to just try out different lifetimes until the compiler was happy. Because I'm still a bit vague on the how async_trait transforms the code, and so what signature I need to implement to match the one in the Rust docs.)

struct NoStore {}

#[async_trait]
impl <State: Clone + Send + Sync + 'static> tide::Middleware<State> for NoStore {
    async fn handle<'a, 'b>(&'a self, req: tide::Request<State>, next: tide::Next<'b, State>) -> tide::Result<Response>
    {
        // same body.
    }
}

But, AFAICT, there's no reason that Tide couldn't just add an impl Middleware for these type of bare/stateless middlewares. Then you could just:

app.with(no_store);

// instead of having to use a struct and manually impl the trait.

app.with(NoStore{});
@nyxtom
Copy link
Contributor

nyxtom commented Jul 16, 2022

I've implemented a solution to this and simplified the code base to move State into extensions via a StateMiddleware as well as remove the for<'a> requirement on middleware so this is now possible in my branch #895

#[derive(Clone)]
struct State {
    foo: String,
}

#[async_std::main]
async fn main() -> tide::Result<()> {
    let mut app = tide::with_state(State { foo: "asdf".into() });

    app.with(|req: tide::Request, next: tide::Next| async move {
        use tide::http::cache::{CacheControl, CacheDirective};
        let mut res = next.run(req).await;

        if let None = res.header("Cache-Control") {
            let mut header = CacheControl::new();
            header.push(CacheDirective::NoStore);
            header.push(CacheDirective::MaxAge(std::time::Duration::from_secs(0)));

            res.insert_header(header.name(), header.value());
        }
        Ok(res)
    });
    app.at("/").get(index);
    app.listen("127.0.0.1:7000").await?;

    Ok(())
}

async fn index(req: tide::Request) -> tide::Result {
    println!("{}", req.state::<State>().foo);
    Ok(tide::Response::new(200))
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants