Skip to content

[rust] zero2prod Build Log 03 - Health Check ​

Shubham Dhage

zero2prod is a web API project, and the book suggests that you start with the actix-web framework. Rust has many web frameworks, and actix is only one of them. I came into programming through C#, so this really took some adjustment. In the .NET world, everyone follows Microsoft's lead. Microsoft tells you how to write your code, and its grip only got stronger after .NET Core arrived. Rust has plenty of frameworks besides actix-web, but I will not go into them here.

actix_web::main ​

After you set up the cargo project, replace the contents of main.rs. The book uses actix-web 4.0.0. I switched straight to 4.3.0.

rust
#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(||{
        App::new()
        .route("/health_check", web::get().to(health_check))
    })
    .bind(("127.0.0.1",8080))?
    .run()
    .await
}

async fn health_check(_req: HttpRequest) -> impl Responder{
    HttpResponse::Ok()
}

Read this from the inside out. That odd-looking ||{} is a lambda expression. In C# you would write ()=>{}. It is a method that takes no arguments and returns an instance of the App struct.

You can set routes on App. The first way is the one that the example shows: .route() sets the route and binds health_check to get. The second way is .service().

rust
// App instance
App::new()
.service(health_check)

// health_check handler
#[get("/")]
async fn health_check(_req: HttpRequest) -> impl Responder{
    HttpResponse::Ok()
}

Look at the return value of health_check: it is a Responder. Rust uses a trait here, which is similar to an interface in other languages. The return value must implement the Responder trait. The other thing that is worth a look is .to(), which sets the handler:

pub fn to<F, Args>(handler: F) -> Route
where
    F: Handler<Args>,
    Args: FromRequest + 'static,
    F::Output: Responder + 'static,

I bring this up because of Rust lifetimes. 'static means that the variable lives for the whole run of the program. The meaning here is subtly different, and this article explains it. In short, the type Args must stay valid for the whole of one request. You use the App instance to build the HttpServer. The rest of the method chain then builds the middleware.

Finally, look at main. Once you attach #[actix_web::main], main must return the Result type, which is an enum. Rust and functional languages state explicitly that a method returns either a result or a failure. Once you make the method async, you must handle the failure case. Some people call the () inside Result the unit type, which means that there is no result. The method does not need to return anything when it succeeds, so the return type here is Result<()>.

Summary ​

I finally finished the first post. I do not know Rust well, so some of my understanding is probably wrong. I will correct it bit by bit as I learn.

Last updated:

Built with VitePress