Difficult to use closure as middleware
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 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.
@aldanor IIRC this is due to the absence of async closures in Rust.
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)