nickel-org / nickel.rs

An expressjs inspired web framework for Rust

Home Page:http://nickel-org.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use handler in impl

imclint21 opened this issue · comments

Hi,

I would like to use a custom handler or a logger in the same impl, but i've this error:

44 |         server.utilize(self.logger);
   |                             ^^^^^^ help: use parentheses to call the method: `logger(...)

Thanks

The utilize method takes something implementing the Middleware trait. There is a blanket implementation for functions taking the request and response, and return a MiddlewareResult. There is also a fragile macro, but I recommend you avoid it. It has some unexpected behavior. I often end up just implementing the trait.

@jolhoeft is the macro implementation still not recommended by you?

@amitavaghosh1 I am not sure. As I mentioned it's behavior is unexpected. I have nickel mostly migrated to async hyper (see the head of the master branch), and I think some sort of macro may be needed to fill some usability gaps. I'd be interested in hearing more about use cases.

for me the use case is not that complicated. a hypothetical similar situation would be. when the route is /internal add some headers, when its not remove any headers that might be associated with a /internal route.
so I guess there would be two ways of doing it.

One way is the form-data example, where there can be a struct as such:

struct InternalMiddleware { isInternal: bool }

and then have impl Middleware<()> for InternalMiddleware {...

the other way is something like:

fn add_header<D>(is_internal: bool) -> impl Middleware<D> {
    middleware! { |req, res|
        if is_internal {
            println!("internal");
            return res.next_middleware()
        }

        let auth_header = match req.origin.headers.get::<Authorization<Bearer>>() {
            Some(header) => header,
            None => panic!("No authorization header found")
        };

        let header = hyper::header::HeaderFormatter(auth_header).to_string();
        println!("Header v {}", header);
    }
}

since in rust we cannot return closures, this is one way I figured, with some help, this way without having to add a struct.
The other advantage of this would be that, I can pass a service to this wrapper function and then the middleware can run it. Right now most of the the routers I have tried, like tide, actix etc (actix is already difficult :D) doesn't allow this kind of thing. so the only way is to pass the database objects inside the state. And I don't think that is a very good way to go about it, in no way should a router be aware of the database in its state, it just makes testing very difficult and I think it also violates srp.

You're example is a good case of my problem with the middleware macro. The macro expects something implementing Responder, but res.next_middleware returns a MiddlewareResult, so the above code won't compile. Maybe we could implement Responder for MiddlewareResult. I think with these caveats, using the middleware macro is fine.

My other question is where you need this. For the 0.11.x branch, I'm not planning on anything but major bug fixes. Most of my limited time is on the master branch where I'm trying to get async fully functional.

Since at my workplace, we will be mostly taking up rust for web dev, quite slowly and incrementally, we will mostly be using latest releases, so if you release this in one of your newer branches, it won't be a problem for us. I am also trying to learn the language, so that I can contribute.
Rust for web development, I think, still needs some work. There are a few minor things where I keep getting stuck at, and it gets harder each time to convince people to use it as well 😃 .