surf icon indicating copy to clipboard operation
surf copied to clipboard

Difficult to use closure as middleware

Open abonander opened this issue 6 years ago • 3 comments

You can't trivially set a closure as a middleware on a request even though closures implement Middleware; the obvious doesn't work by itself:

surf::post(...)
    .middleware(|request, client, next| { // error on `next`: type annotation needed
        // I want to log the full request, the logger middleware doesn't print much
        trace!("request {:?}", request);
        next.run(request, client)
    })
...

However, because the concrete HttpClient types are not importable, there's no way to give a type for Next that satisfies the compiler:

    .middleware(|request, client, next: Next<'_, /* what the heck do I put here? `impl HttpClient` isn't allowed */> | { .. })

It's not too difficult to write a function that allows you to omit the type annotation, but it's not the greatest experience:

fn apply_middleware_fn<C: HttpClient, F>(request: surf::Request<C>, middleware: F) -> surf::Request<C>
    where F: Send + Sync + 'static + for<'a> Fn(Request, C, Next<'a, C>) -> BoxFuture<'a, Result<Response, Exception>> 
{
    request.middleware(middleware)
}

apply_middleware_fn(request, |request, client, next| { ... });

This could be fixed pretty simply by providing this wrapper as a method on Request:

impl<C: HttpClient> Request<C> {

    pub fn middleware_fn<F>(self, middleware_fn: F) -> Self
        where F: Send + Sync + 'static + for<'a> Fn(Request, C, Next<'a, C>) -> BoxFuture<'a, Result<Response, Exception>>
    {
        self.middleware(middleware_fn)
    }
}

This should allow the above usage to work as-is without naming types in the closure.

abonander avatar Oct 19 '19 01:10 abonander

@abonander it seems like the right outcome here is to make http-client and its related types public. I'll see what I can do here.

yoshuawuyts avatar Oct 30 '19 16:10 yoshuawuyts

@aldanor IIRC this is due to the absence of async closures in Rust.

Fishrock123 avatar Nov 04 '20 18:11 Fishrock123

We could add something like tide::utils::Before and tide::utils::After to surf (which I still think should be made more prominent in tide)

jbr avatar Nov 04 '20 18:11 jbr