//! src/main.rs
// [...]
 
#[tokio::main]  
async fn main() -> Result<(), std::io::Error> {
 
HttpServer::new(|| { 
	App::new()
		.route("/", web::get().to(greet))
		.route("/{name}", web::get().to(greet))
    })
	    .bind("127.0.0.1:8000")?
	    .run()
	    .await
}

HttpServer:: is the main backbone to the project, it handles all the transport layer details

App:: is where the app logic lives:

  1. routes
  2. middleware
  3. request handlers
  4. etc.

Each request handler is set up in the same way for actix-web

async fn health_check() -> impl Responder {
    HttpResponse::Ok().finish()
}
  • an async function that takes a HttpRequest returns a Responder that returns something that implements the ability to turn into an HttpResponse.
/*
	Whole tokio function breakdown
*/
use zero2prod::run;
 
#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
    run("127.0.0.1:8080")?.await
}

our run function is defined in another file (lib.rs)

but why do we have tokio there?

tokio helps our main function be asynchronous

Asynchronous programming in Rust relies on the Future trait.

Future traits stand for a value that might not be there yet.

values that impl. the future trait expose a polling method that allows the program to check in on the status of the Future.

if you don’t poll a future there is no guarantee that the future will resolve. (lazy polling)

#[tokio::main] is a macro. macro’s take in code (or a bunch of characters) and then transform or add code to the characters and then pass that code to the compiler at compile time.

you can use cargo expand to stop the macros from going to the compiler so you can see what is going on in the macro under-the-hood.