Search code examples
rustnickel

nickel.rs post redirect not found


I am using nickel.rs, PostgreSQL, and Angular.js. I can insert into my table with an HTTP POST:

// insert
{
    let conn = shared_connection.clone();
    router.post("/api/movies", middleware! { |request, mut response|
        let conn = conn.lock().unwrap();
        let stmt = match conn.prepare("insert into movie (title, releaseYear, director, genre)
            values ($1, $2, $3, $4)") {
            Ok(stmt) => stmt,
            Err(e) => {
                return response.send(format!("Preparing query failed: {}", e));
            }
        };

        let movie = request.json_as::<MovieInsert>().unwrap();
        match stmt.execute(&[
            &movie.title.to_string(),
            &movie.releaseYear,
            &movie.director.to_string(),
            &movie.genre.to_string()
        ]) {
            Ok(v) => println!("Inserting movie was Success."),
            Err(e) => println!("Inserting movie failed. => {:?}", e),
        };

        // ERROR (1)
        // return response.set(Location("/".into()));

    });
}

I know this works fine because the row is inserted in the PostgreSQL table. However, the Chrome web browser shows an error:

POST http://localhost:6767/api/movies 404 (Not Found)

I also added the code in ERROR (1) line

response.set(Location("/".into()));

however, console show the error.

 expected `core::result::Result<nickel::middleware::Action<nickel::response::Response<'mw, _>, nickel::response::Response<'mw, _, hyper::net::Streaming>>, nickel::nickel_error::NickelError<'mw, _>>`,
    found `&mut nickel::response::Response<'_, _>`
(expected enum `core::result::Result`,
    found &-ptr)

Now it is my code applied what Shepmaster said.

// insert
{
    let conn = shared_connection.clone();
    router.post("/api/movies", middleware! { |request, mut response|
        let conn = conn.lock().unwrap();
        let stmt = match conn.prepare("insert into movie (title, releaseYear, director, genre)
            values ($1, $2, $3, $4)") {
            Ok(stmt) => stmt,
            Err(e) => {
                return response.send(format!("Preparing query failed: {}", e));
            }
        };

        let movie = request.json_as::<MovieInsert>().unwrap();
        match stmt.execute(&[
            &movie.title.to_string(),
            &movie.releaseYear,
            &movie.director.to_string(),
            &movie.genre.to_string()
        ]) {
            Ok(v) => println!("Inserting movie was Success."),
            Err(e) => println!("Inserting movie failed. => {:?}", e),
        };

        response.set(StatusCode::PermanentRedirect)
            .set(Location("/".into()));
        ""
    });
}

but the error occurred.

src/main.rs:155:18: 155:43 error: the trait modifier::Modifier<nickel::response::Response<'_, _>> is not implemented for the type hyper::header::common::location::Location [E0277] src/main.rs:155 .set(Location("/".into()));

finally I fix like this!

            Ok(v) => {
                println!("Inserting movie was Success.");
                response.set(StatusCode::Ok);
            },
            Err(e) => println!("Inserting movie failed. => {:?}", e),
        };

        //response.set(StatusCode::PermanentRedirect)
        //    .set(Location("/".into()));
        //""
        return response.send("");

Solution

  • The code, as currently listed, doesn't make any sense. There's nothing returned from your route handler:

    match ... {
        Ok(v) => println!("Inserting movie was Success."),
        Err(e) => println!("Inserting movie failed. => {:?}", e),
    };
    

    Because nothing about the database or the frontend framework is important, your code is equivalent to this:

    #[macro_use]
    extern crate nickel;
    
    use nickel::{Nickel, HttpRouter};
    
    fn main() {
        let mut server = Nickel::new();
    
        server.post("/api/movies", middleware! { |request, mut response|
            println!("Hello");
        });
    
        server.listen("127.0.0.1:6767");
    }
    

    If you return something from the handler, then the HTTP status code changes from a 404 to a 200.

    If you'd like to redirect somewhere, you need to explicitly change the status code. The documentation for Response::set happens to have an example:

    server.get("/a", middleware! { |_, mut res|
        res.set(StatusCode::PermanentRedirect)
           .set(Location("http://nickel.rs".into()));
    
        ""
    });
    

    Note that an empty string is returned, similar to before. You were trying to return the Response type directly.