$devvkit learn --librarie actix-web-guide
Actix Web Guide
[rust][http][async][high-performance]
Rust
Install
cargo add actix-web actix-rt # or: add to Cargo.toml manually
Actix Web is one of the fastest web frameworks in any language. It uses an actor-based runtime (actix-rt) and provides a full set of features: routing, middleware, WebSockets, multipart uploads, SSL, and streaming.
The framework uses extractors to pull data from requests (Path, Query, Json, Form, Data for app state). Handlers return types implementing Responder (HttpResponse, Json, web::Redirect, etc.).
Actix Web has excellent WebSocket support via actix-web-actors. The middleware system uses the `Service` trait with wrap_fn for simple cases or custom middleware structs for complex logic.
Setup
Basic server— Hello world.
use actix_web::{get, App, HttpResponse, HttpServer, Responder};
#[get("/")]
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello world!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(hello))
.bind(("127.0.0.1", 8080))?
.run()
.await
}Routing
Route with params— Path and query parameters.
use actix_web::{get, web, HttpResponse};
#[get("/users/{id}")]
async fn get_user(path: web::Path<u32>, query: web::Query<Search>) -> HttpResponse {
let user_id = path.into_inner();
HttpResponse::Ok().json(SearchResult { id: user_id, query: query.into_inner() })
}JSON response— Return JSON.
use serde::Serialize;
#[derive(Serialize)]
struct User { id: u32, name: String }
#[get("/users")]
async fn list_users() -> HttpResponse {
let users = vec![
User { id: 1, name: "Alice".into() },
User { id: 2, name: "Bob".into() },
];
HttpResponse::Ok().json(users)
}Extractors
Shared state— Application state.
use std::sync::Mutex;
struct AppState { counter: Mutex<u32> }
#[get("/count")]
async fn get_count(data: web::Data<AppState>) -> HttpResponse {
let mut count = data.counter.lock().unwrap();
*count += 1;
HttpResponse::Ok().body(format!("Count: {}", count))
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let state = web::Data::new(AppState { counter: Mutex::new(0) });
HttpServer::new(move || App::new().app_data(state.clone()).service(get_count))
.bind(("127.0.0.1", 8080))?
.run().await
}Middleware
Middleware— Simple wrap middleware.
use actix_web::middleware::from_fn;
async fn my_middleware(
req: actix_web::dev::ServiceRequest,
next: actix_web::dev::ServiceResponse,
) -> Result<actix_web::dev::ServiceResponse, actix_web::Error> {
let start = std::time::Instant::now();
let res = next.call(req).await?;
log::info!("Request took {:?}", start.elapsed());
Ok(res)
}
App::new().wrap(from_fn(my_middleware))WebSockets
WebSocket— WebSocket endpoint.
use actix_web::{web, HttpRequest, HttpResponse};
use actix_web_actors::ws;
async fn ws_handler(req: HttpRequest, stream: web::Payload) -> Result<HttpResponse, actix_web::Error> {
ws::start(MyWebSocket, &req, stream)
}
App::new().route("/ws/", web::get().to(ws_handler))Testing
Test integration— Integration test.
#[cfg(test)]
mod tests {
use actix_web::{test, App, HttpResponse};
#[actix_web::test]
async fn test_hello() {
let app = test::init_service(App::new().route("/", web::get().to(hello))).await;
let req = test::TestRequest::get().uri("/").to_request();
let resp = test::call_service(&app, req).await;
assert!(resp.status().is_success());
}
}