Building HTTP service with Rust
Cargo
Cargo is the package manager and build system for Rust programming language. It is used to manage dependencies, build, and run Rust projects. Here are a few frequently used cargo commands:
cargo new: Creates a new Rust project.
cargo build: Builds the project and its dependencies.
cargo run: Builds and runs the project.
cargo test: Runs the tests in the project.
cargo check: Checks the syntax and type correctness without producing an executable.
cargo update: Updates dependencies in the project.
cargo clean: Cleans the project files and directories.
Create a project with cargo
mkdir rust-study && cd rust-study
cargo init
Then we will have a project with this layout
lujunjie@mac:/Users/lujunjie/code/github/jaylu/rust-study > tree
.
├── Cargo.toml
└── src
└── main.rs
More folder structure info can be seen here
When can then try to run the project via cargo run
lujunjie@mac:/Users/lujunjie/code/github/jaylu/rust-study > cargo run
Blocking waiting for file lock on package cache
Compiling rust-study v0.1.0 (/Users/lujunjie/code/github/jaylu/rust-study)
Finished dev [unoptimized + debuginfo] target(s) in 10.62s
Running `target/debug/rust-study`
Hello, world!
Here we are, the project skeleton is set up!!
Building a simple web server with Actix
I try do some quick study of the Rust HTTP lib:
Library | Async Support | Performance | Stability | Ease of Use | Features |
---|---|---|---|---|---|
Actix Web | Yes | High | Stable | Moderate | Middlewares, WebSocket |
Rocket | Yes | Moderate | Stable | Easy | Macros, Form Handling |
Warp | Yes | High | Experimental | Easy | Filters, WebSockets |
Hyper | Yes | High | Stable | Moderate | Low-level, Flexibility |
Tide | Yes | High | Experimental | Easy | Middleware Chain, Async |
Iron | No | Moderate | Unmaintained | Moderate | Middleware |
Gotham | Yes | High | Experimental | Easy | Router, Middlewares |
And Actix seems to be supporting Middleware and the API is quite fit for my intuition. Below is what I had done to start up a simple http server:
Adding dependencies in
cargo.toml
txt[dev-dependencies] actix-web = "4" actix-files = "0.6" env_logger = "0.9.0" log = "0.4" serde = { version = "1.0", features = ["derive"] } serde_json = "1" futures = "0.3"
Add code in
examples/actix_web.rs
rustuse actix_files::Files; use actix_web::{App, get, HttpServer, middleware::Logger, Responder, Result, web}; use serde::Deserialize; #[get("/hello/{name}")] async fn greet(name: web::Path<String>) -> impl Responder { format!("Hello {name}!") } #[derive(Deserialize)] struct Info { username: String, } /// extract `Info` using serde async fn do_post(info: web::Json<Info>) -> Result<String> { println!("received request"); Ok(format!("Welcome {}!", info.username)) } #[actix_web::main] // or #[tokio::main] async fn main() -> std::io::Result<()> { env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); log::info!("starting HTTP server at http://localhost:8080"); HttpServer::new(|| { App::new() .route("/hello", web::get().to(|| async { "Hello World!" })) .route("/post", web::post().to(do_post)) .service(greet) .service(Files::new("/web", "./examples/static") .show_files_listing() .use_last_modified(true) ) .wrap(Logger::default()) }) .bind(("127.0.0.1", 8080))? .run() .await }
Run command
cargo run --example actix_web
source code here
Summary
It's simple enough to kick-start, but I might want a more low level HTTP server to build a web proxy in the near future, maybe let's look at using Hyper
next time to read the request body in a streaming way.