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

Early return inside middleware! macro

mmacedoeu opened this issue · comments

I need to return early if preconditions are not met, but tuple response is not accepted if I use return:

fn main() {
  let mut server = Nickel::new();
  server.post("/claim",
    middleware!{ |request, response|
      let condition : bool = try_with!(response, {handle_preconditions().map_err(|e| (StatusCode::BadRequest, e))});

     if !condition {
       return (StatusCode::PreconditionRequired, "invalid state".to_string()); // this is not compilling
       // expected type `std::result::Result<nickel::Action<nickel::Response<'mw, _>, //nickel::Response<'mw, _, hyper::net::Streaming>>, nickel::NickelError<'mw, _>>`
//    = note:    found type `(hyper::status::StatusCode, std::string::String)`
     }

      let good : bool = try_with!(response, {handle_processing().map_err(|e| (StatusCode::BadRequest, e))});

      if good {
         (StatusCode::Accepted, "Fine".to_string())
      } else {
         (StatusCode::NotAcceptable, "Not Fine".to_string())
      }

    });
    server.listen("127.0.0.1:6767").unwrap();
}

It is expecting a return of type std::result::Result<nickel::Action<nickel::Response<'mw, _>, nickel::Response<'mw, _, hyper::net::Streaming>>, nickel::NickelError<'mw, _>>

How can I early return ?

I'm not very good at offering advice, but im currently banging my head against Nickel.rs and it's macros.

I believe this might help you.

In your file, use
use nickel::MiddlewareResult;
and then for your early return use return response.send(put your stuff here);
Ex:
return response.send((StatusCode::Accepted, "Fine".to_string()));

I guess this also should work:

return Err(From::from((
    response, (
        StatusCode::PreconditionRequired, 
        String::from("invalid state")
    )
)));

https://github.com/nickel-org/nickel.rs/blob/master/src/nickel_error.rs#L72

I figured this out while sorting out #399. Basically the middleware macro is somewhat fragile. It looks like it takes a closure, but is actually taking a block. The block must return something implementing Responder. Note that since it is a block, the return statement interacts with the macro expansion in unexpected ways. To make the original example work, you need to not use return, and instead nest the if statements:

fn main() {
    let mut server = Nickel::new();
    server.post("/claim", middleware!{ |request, response|
        let condition : bool = try_with!(response, {handle_preconditions().map_err(|e| (StatusCode::BadRequest, e))});
                                        
        if !condition {
            (StatusCode::PreconditionRequired, "invalid state".to_string())
        } else {            
            let good : bool = try_with!(response, {handle_processing().map_err(|e| (StatusCode::BadRequest, e))});
            
            if good {
                (StatusCode::Accepted, "Fine".to_string())
            } else {
                (StatusCode::NotAcceptable, "Not Fine".to_string())
            }
        }
    });
    server.listen("127.0.0.1:6767").unwrap();
}