Rust Web Development: High-Performance APIs with Memory Safety
As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world! Rust has revolutionized web development by bringing systems-level performance and memory safety to server-side applications. I've spent years working with various frameworks across languages, and Rust's approach offers unique advantages that address many long-standing challenges in web development. The Rust web ecosystem has matured significantly in recent years. With strong type safety, zero-cost abstractions, and concurrency without data races, it's particularly valuable for high-performance applications where reliability is critical. Web Frameworks in Rust Rust offers several web frameworks with different philosophies. Each has distinct strengths depending on your priorities. Actix Web remains one of the most popular frameworks. It leverages the actor system model and consistently ranks among the fastest web frameworks in TechEmpower benchmarks. I appreciate its balance of performance and ergonomics: use actix_web::{web, App, HttpServer, Responder, HttpResponse}; use serde::{Deserialize, Serialize}; use std::sync::Mutex; use std::collections::HashMap; #[derive(Serialize, Deserialize, Clone)] struct User { id: u64, name: String, email: String, } struct AppState { users: Mutex, } async fn create_user(data: web::Data, user: web::Json) -> impl Responder { let mut users = data.users.lock().unwrap(); users.insert(user.id, user.into_inner()); HttpResponse::Created().finish() } async fn get_user(data: web::Data, path: web::Path) -> impl Responder { let users = data.users.lock().unwrap(); let user_id = path.into_inner(); match users.get(&user_id) { Some(user) => HttpResponse::Ok().json(user), None => HttpResponse::NotFound().finish(), } } #[actix_web::main] async fn main() -> std::io::Result { let app_state = web::Data::new(AppState { users: Mutex::new(HashMap::new()), }); HttpServer::new(move || { App::new() .app_data(app_state.clone()) .route("/users", web::post().to(create_user)) .route("/users/{id}", web::get().to(get_user)) }) .bind("127.0.0.1:8080")? .run() .await } Rocket offers a more Rails-like developer experience with expressive routing. Version 0.5 embraces async Rust and provides a mature set of features: #[macro_use] extern crate rocket; use rocket::serde::{Serialize, Deserialize, json::Json}; use std::sync::Mutex; use std::collections::HashMap; #[derive(Serialize, Deserialize, Clone)] #[serde(crate = "rocket::serde")] struct User { id: u64, name: String, email: String, } struct UserDatabase { users: Mutex, } #[post("/users", data = "")] fn create_user(user: Json, db: &rocket::State) -> (rocket::http::Status) { let mut users = db.users.lock().unwrap(); users.insert(user.id, user.into_inner()); rocket::http::Status::Created } #[get("/users/")] fn get_user(id: u64, db: &rocket::State) -> Option { let users = db.users.lock().unwrap(); users.get(&id).map(|user| Json(user.clone())) } #[launch] fn rocket() -> _ { rocket::build() .manage(UserDatabase { users: Mutex::new(HashMap::new()), }) .mount("/", routes![create_user, get_user]) } Axum, developed by the Tokio team, stands out with its tower-based middleware system and extractor pattern: use axum::{ routing::{get, post}, http::StatusCode, extract::{Path, State, Json}, Router, }; use serde::{Deserialize, Serialize}; use std::sync::{Arc, Mutex}; use std::collections::HashMap; use std::net::SocketAddr; #[derive(Serialize, Deserialize, Clone)] struct User { id: u64, name: String, email: String, } type UserDb = Arc; async fn create_user( State(db): State, Json(user): Json, ) -> StatusCode { let mut users = db.lock().unwrap(); users.insert(user.id, user); StatusCode::CREATED } async fn get_user( State(db): State, Path(id): Path, ) -> Result { let users = db.lock().unwrap(); users.get(&id) .cloned() .map(Json) .ok_or(StatusCode::NOT_FOUND) } #[tokio::main] async fn main() { let db = Arc::new(Mutex::new(HashMap::new())); let app = Router::new() .route("/users", post(create_user)) .route("/users/:id", get(get_user)) .with_state(db); let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); println!("Server listening on {}", addr); axum::Server::bind(&addr) .serve(app.into_make_service()) .await .unwrap(); } Warp provides a composable approach using filters: use warp::{Filter, Reply, Rejection}; use serde::{Deserialize, Serialize}; use std::sync::{Arc, Mutex}; use std::collections::HashMap; #[derive(Serialize, Deserialize, Clone)] struct User { id: u64, name: St

As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world!
Rust has revolutionized web development by bringing systems-level performance and memory safety to server-side applications. I've spent years working with various frameworks across languages, and Rust's approach offers unique advantages that address many long-standing challenges in web development.
The Rust web ecosystem has matured significantly in recent years. With strong type safety, zero-cost abstractions, and concurrency without data races, it's particularly valuable for high-performance applications where reliability is critical.
Web Frameworks in Rust
Rust offers several web frameworks with different philosophies. Each has distinct strengths depending on your priorities.
Actix Web remains one of the most popular frameworks. It leverages the actor system model and consistently ranks among the fastest web frameworks in TechEmpower benchmarks. I appreciate its balance of performance and ergonomics:
use actix_web::{web, App, HttpServer, Responder, HttpResponse};
use serde::{Deserialize, Serialize};
use std::sync::Mutex;
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Clone)]
struct User {
id: u64,
name: String,
email: String,
}
struct AppState {
users: Mutex<HashMap<u64, User>>,
}
async fn create_user(data: web::Data<AppState>, user: web::Json<User>) -> impl Responder {
let mut users = data.users.lock().unwrap();
users.insert(user.id, user.into_inner());
HttpResponse::Created().finish()
}
async fn get_user(data: web::Data<AppState>, path: web::Path<u64>) -> impl Responder {
let users = data.users.lock().unwrap();
let user_id = path.into_inner();
match users.get(&user_id) {
Some(user) => HttpResponse::Ok().json(user),
None => HttpResponse::NotFound().finish(),
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let app_state = web::Data::new(AppState {
users: Mutex::new(HashMap::new()),
});
HttpServer::new(move || {
App::new()
.app_data(app_state.clone())
.route("/users", web::post().to(create_user))
.route("/users/{id}", web::get().to(get_user))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
Rocket offers a more Rails-like developer experience with expressive routing. Version 0.5 embraces async Rust and provides a mature set of features:
#[macro_use] extern crate rocket;
use rocket::serde::{Serialize, Deserialize, json::Json};
use std::sync::Mutex;
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Clone)]
#[serde(crate = "rocket::serde")]
struct User {
id: u64,
name: String,
email: String,
}
struct UserDatabase {
users: Mutex<HashMap<u64, User>>,
}
#[post("/users", data = "" )]
fn create_user(user: Json<User>, db: &rocket::State<UserDatabase>) -> (rocket::http::Status) {
let mut users = db.users.lock().unwrap();
users.insert(user.id, user.into_inner());
rocket::http::Status::Created
}
#[get("/users/" )]
fn get_user(id: u64, db: &rocket::State<UserDatabase>) -> Option<Json<User>> {
let users = db.users.lock().unwrap();
users.get(&id).map(|user| Json(user.clone()))
}
#[launch]
fn rocket() -> _ {
rocket::build()
.manage(UserDatabase {
users: Mutex::new(HashMap::new()),
})
.mount("/", routes![create_user, get_user])
}
Axum, developed by the Tokio team, stands out with its tower-based middleware system and extractor pattern:
use axum::{
routing::{get, post},
http::StatusCode,
extract::{Path, State, Json},
Router,
};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use std::net::SocketAddr;
#[derive(Serialize, Deserialize, Clone)]
struct User {
id: u64,
name: String,
email: String,
}
type UserDb = Arc<Mutex<HashMap<u64, User>>>;
async fn create_user(
State(db): State<UserDb>,
Json(user): Json<User>,
) -> StatusCode {
let mut users = db.lock().unwrap();
users.insert(user.id, user);
StatusCode::CREATED
}
async fn get_user(
State(db): State<UserDb>,
Path(id): Path<u64>,
) -> Result<Json<User>, StatusCode> {
let users = db.lock().unwrap();
users.get(&id)
.cloned()
.map(Json)
.ok_or(StatusCode::NOT_FOUND)
}
#[tokio::main]
async fn main() {
let db = Arc::new(Mutex::new(HashMap::new()));
let app = Router::new()
.route("/users", post(create_user))
.route("/users/:id", get(get_user))
.with_state(db);
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("Server listening on {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
Warp provides a composable approach using filters:
use warp::{Filter, Reply, Rejection};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Clone)]
struct User {
id: u64,
name: String,
email: String,
}
type UserDb = Arc<Mutex<HashMap<u64, User>>>;
type Result<T> = std::result::Result<T, Rejection>;
async fn create_user(user: User, db: UserDb) -> Result<impl Reply> {
let mut users = db.lock().unwrap();
users.insert(user.id, user);
Ok(warp::reply::with_status(
"Created",
warp::http::StatusCode::CREATED,
))
}
async fn get_user(id: u64, db: UserDb) -> Result<impl Reply> {
let users = db.lock().unwrap();
match users.get(&id) {
Some(user) => Ok(warp::reply::json(user)),
None => Err(warp::reject::not_found()),
}
}
#[tokio::main]
async fn main() {
let db: UserDb = Arc::new(Mutex::new(HashMap::new()));
let db_filter = warp::any().map(move || db.clone());
let create_route = warp::post()
.and(warp::path("users"))
.and(warp::body::json())
.and(db_filter.clone())
.and_then(create_user);
let get_route = warp::get()
.and(warp::path("users"))
.and(warp::path::param::<u64>())
.and(db_filter)
.and_then(get_user);
let routes = create_route.or(get_route);
warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
}
Database Access
SQLx provides compile-time checked SQL queries that validate against your actual database:
use sqlx::{PgPool, postgres::PgPoolOptions};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, sqlx::FromRow)]
struct User {
id: i64,
name: String,
email: String,
}
async fn create_user(pool: &PgPool, name: String, email: String) -> Result<User, sqlx::Error> {
let user = sqlx::query_as!(
User,
"INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name, email",
name,
email
)
.fetch_one(pool)
.await?;
Ok(user)
}
async fn get_user(pool: &PgPool, id: i64) -> Result<Option<User>, sqlx::Error> {
let user = sqlx::query_as!(
User,
"SELECT id, name, email FROM users WHERE id = $1",
id
)
.fetch_optional(pool)
.await?;
Ok(user)
}
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = PgPoolOptions::new()
.max_connections(5)
.connect("postgres://postgres:password@localhost/mydatabase")
.await?;
// Create tables if they don't exist
sqlx::query(
"CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE
)"
)
.execute(&pool)
.await?;
// Example usage
let new_user = create_user(&pool, "Alice".into(), "alice@example.com".into()).await?;
println!("Created user: {:?}", new_user);
let user = get_user(&pool, new_user.id).await?;
println!("Retrieved user: {:?}", user);
Ok(())
}
Diesel offers an ORM approach with type-safe query building:
#[macro_use]
extern crate diesel;
use diesel::prelude::*;
use diesel::pg::PgConnection;
use dotenv::dotenv;
use std::env;
use serde::{Serialize, Deserialize};
mod schema {
table! {
users (id) {
id -> Int4,
name -> Text,
email -> Text,
}
}
}
use schema::users;
#[derive(Queryable, Serialize, Deserialize)]
struct User {
id: i32,
name: String,
email: String,
}
#[derive(Insertable)]
#[table_name="users"]
struct NewUser {
name: String,
email: String,
}
fn establish_connection() -> PgConnection {
dotenv().ok();
let database_url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");
PgConnection::establish(&database_url)
.expect("Error connecting to database")
}
fn create_user(conn: &PgConnection, name: &str, email: &str) -> User {
let new_user = NewUser {
name: name.to_string(),
email: email.to_string(),
};
diesel::insert_into(users::table)
.values(&new_user)
.get_result(conn)
.expect("Error saving new user")
}
fn get_user(conn: &PgConnection, user_id: i32) -> Option<User> {
users::table
.find(user_id)
.first(conn)
.optional()
.expect("Error loading user")
}
fn main() {
let connection = establish_connection();
// Create tables if they don't exist
diesel::sql_query("
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE
)
").execute(&connection).expect("Could not create table");
let user = create_user(&connection, "Bob", "bob@example.com");
println!("Created user with ID {}", user.id);
match get_user(&connection, user.id) {
Some(user) => println!("Found user: {} <{}>", user.name, user.email),
None => println!("User not found"),
}
}
Authentication and Authorization
Authentication is crucial for web applications. Here's a JWT implementation with Actix Web:
use actix_web::{web, App, HttpServer, HttpResponse, Responder, Error, middleware};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use chrono::{Duration, Utc};
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: String,
exp: usize,
role: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct LoginRequest {
username: String,
password: String,
}
async fn login(request: web::Json<LoginRequest>) -> impl Responder {
// In a real app, verify credentials against a database
if request.username == "admin" && request.password == "password" {
let expiration = Utc::now()
.checked_add_signed(Duration::hours(1))
.expect("valid timestamp")
.timestamp() as usize;
let claims = Claims {
sub: request.username.clone(),
exp: expiration,
role: "admin".into(),
};
let header = Header::new(Algorithm::HS256);
let secret = b"my_secret_key"; // In production, use a secure key management solution
match encode(&header, &claims, &EncodingKey::from_secret(secret)) {
Ok(token) => HttpResponse::Ok().json(serde_json::json!({ "token": token })),
Err(_) => HttpResponse::InternalServerError().body("Could not generate token"),
}
} else {
HttpResponse::Unauthorized().body("Invalid credentials")
}
}
async fn protected(auth: BearerAuth) -> Result<HttpResponse, Error> {
let token = auth.token();
let secret = b"my_secret_key";
match decode::<Claims>(
token,
&DecodingKey::from_secret(secret),
&Validation::new(Algorithm::HS256),
) {
Ok(token_data) => {
// Access claims with token_data.claims
Ok(HttpResponse::Ok().json(serde_json::json!({
"message": "Protected data",
"user": token_data.claims.sub,
"role": token_data.claims.role,
})))
}
Err(_) => Ok(HttpResponse::Unauthorized().body("Invalid token")),
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.wrap(middleware::Logger::default())
.route("/login", web::post().to(login))
.route("/protected", web::get().to(protected))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
WebAssembly and Frontend Development
Rust's WebAssembly support enables sharing code between server and client. Yew provides a React-like frontend framework:
use yew::prelude::*;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
use web_sys::HtmlInputElement;
use std::rc::Rc;
#[derive(Serialize, Deserialize, Clone, PartialEq)]
struct User {
id: usize,
name: String,
email: String,
}
enum Msg {
AddUser,
UpdateName(String),
UpdateEmail(String),
FetchUsers,
UsersLoaded(Vec<User>),
Error(String),
}
struct UserApp {
users: Vec<User>,
new_user_name: String,
new_user_email: String,
error: Option<String>,
}
impl Component for UserApp {
type Message = Msg;
type Properties = ();
fn create(_ctx: &Context<Self>) -> Self {
Self {
users: vec![],
new_user_name: String::new(),
new_user_email: String::new(),
error: None,
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::AddUser => {
if !self.new_user_name.is_empty() && !self.new_user_email.is_empty() {
let new_id = self.users.len() + 1;
self.users.push(User {
id: new_id,
name: self.new_user_name.clone(),
email: self.new_user_email.clone(),
});
self.new_user_name = String::new();
self.new_user_email = String::new();
true
} else {
self.error = Some("Name and email cannot be empty".into());
true
}
}
Msg::UpdateName(name) => {
self.new_user_name = name;
true
}
Msg::UpdateEmail(email) => {
self.new_user_email = email;
true
}
Msg::FetchUsers => {
// In a real app, make an API call here
let users = vec![
User { id: 1, name: "Alice".into(), email: "alice@example.com".into() },
User { id: 2, name: "Bob".into(), email: "bob@example.com".into() },
];
ctx.link().send_message(Msg::UsersLoaded(users));
false
}
Msg::UsersLoaded(users) => {
self.users = users;
true
}
Msg::Error(message) => {
self.error = Some(message);
true
}
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let on_name_change = ctx.link().callback(|e: Event| {
let input: HtmlInputElement = e.target_unchecked_into();
Msg::UpdateName(input.value())
});
let on_email_change = ctx.link().callback(|e: Event| {
let input: HtmlInputElement = e.target_unchecked_into();
Msg::UpdateEmail(input.value())
});
let on_add = ctx.link().callback(|_| Msg::AddUser);
let on_fetch = ctx.link().callback(|_| Msg::FetchUsers);
html! {
<div class="app">
<h1>{"User Management"}h1>
{if let Some(error) = &self.error {
html! { <div class="error">{error}div> }
} else {
html! {}
}}
<div class="form">
<input
type="text"
placeholder="Name"
value={self.new_user_name.clone()}
onchange={on_name_change}
/>
<input
type="email"
placeholder="Email"
value={self.new_user_email.clone()}
onchange={on_email_change}
/>
<button onclick={on_add}>{"Add User"}button>
<button onclick={on_fetch}>{"Fetch Users"}button>
div>
<div class="user-list">
<h2>{"Users"}h2>
{if self.users.is_empty() {
html! { <p>{"No users found"}p> }
} else {
html! {
<ul>
{for self.users.iter().map(|user| {
let user = Rc::new(user.clone());
html! {
<li key={user.id.to_string()}>
{format!("{} <{}>", user.name, user.email)}
li>
}
})}
ul>
}
}}
div>
div>
}
}
}
fn main() {
yew::Renderer::<UserApp>::new().render();
}
Leptos offers a reactive approach to UI building:
use leptos::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct User {
id: usize,
name: String,
email: String,
}
#[component]
fn App() -> impl IntoView {
let (users, set_users) = create_signal(vec![
User { id: 1, name: "Alice".into(), email: "alice@example.com".into() },
User { id: 2, name: "Bob".into(), email: "bob@example.com".into() },
]);
let (new_name, set_new_name) = create_signal(String::new());
let (new_email, set_new_email) = create_signal(String::new());
let (error, set_error) = create_signal(None::<String>);
let add_user = move |_| {
if new_name().is_empty() || new_email().is_empty() {
set_error.set(Some("Name and email cannot be empty".into()));
return;
}
set_error.set(None);
let next_id = users().len() + 1;
set_users.update(|users| {
users.push(User {
id: next_id,
name: new_name(),
email: new_email(),
});
});
set_new_name.set(String::new());
set_new_email.set(String::new());
};
view! {
<div class="app">
<h1>"User Management"h1>
{move || error().map(|err| view! { <div class="error">{err}div> })}
<div class="form">
<input
type="text"
placeholder="Name"
prop:value={move || new_name()}
on:input=move |ev| set_new_name.set(event_target_value(&ev))
/>
<input
type="email"
placeholder="Email"
prop:value={move || new_email()}
on:input=move |ev| set_new_email.set(event_target_value(&ev))
/>
<button on:click=add_user>"Add User"button>
div>
<div class="user-list">
<h2>"Users"h2>
<Show
when=move || !users().is_empty()
fallback=|| view! { <p>"No users found"p> }
>
<ul>
<For
each=move || users()
key=|user| user.id
children=move |user| {
view! {
<li>{format!("{} <{}>", user.name, user.email)}li>
}
}
/>
ul>
Show>
div>
div>
}
}
fn main() {
mount_to_body(App);
}
HTTP Client and APIs
Building APIs in Rust is just one part of the equation. For client-side HTTP requests, Reqwest offers a powerful interface:
use reqwest::{Client, Error};
use serde::{Deserialize, Serialize};
use tokio;
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u64,
name: String,
email: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct CreateUserRequest {
name: String,
email: String,
}
async fn create_user(client: &Client, name: &str, email: &str) -> Result<User, Error> {
let request = CreateUserRequest {
name: name.to_string(),
email: email.to_string(),
};
let response = client
.post("https://api.example.com/users")
.json(&request)
.send()
.await?;
let user = response.json::<User>().await?;
Ok(user)
}
async fn get_user(client: &Client, id: u64) -> Result<Option<User>, Error> {
let response = client
.get(&format!("https://api.example.com/users/{}", id))
.send()
.await?;
if response.status().is_success() {
let user = response.json::<User>().await?;
Ok(Some(user))
} else if response.status() == reqwest::StatusCode::NOT_FOUND {
Ok(None)
} else {
response.error_for_status()?;
Ok(None) // This line won't be reached if error_for_status() returns an Err
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
// Create a new user
match create_user(&client, "Eve", "eve@example.com").await {
Ok(user) => println!("Created user: {:?}", user),
Err(e) => eprintln!("Error creating user: {}", e),
}
// Fetch a user by ID
match get_user(&client, 1).await {
Ok(Some(user)) => println!("Found user: {:?}", user),
Ok(None) => println!("User not found"),
Err(e) => eprintln!("Error fetching user: {}", e),
}
Ok(())
}
Testing in Rust Web Applications
Testing is where Rust's type system truly shines. Here's testing a web application with Actix Web's test utilities:
use actix_web::{web, App, HttpResponse, Responder};
use actix_web::test;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct User {
id: u64,
name: String,
email: String,
}
async fn get_user(path: web::Path<u64>) -> impl Responder {
let user_id = path.into_inner();
// In a real app, fetch from database
if user_id == 1 {
let user = User {
id: 1,
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
};
HttpResponse::Ok().json(user)
} else {
HttpResponse::NotFound().finish()
}
}
async fn create_user(user: web::Json<User>) -> impl Responder {
// In a real app, save to database
HttpResponse::Created().json(user.0)
}
#[cfg(test)]
mod tests {
use super::*;
use actix_web::{http, test, web, App};
#[actix_rt::test]
async fn test_get_user_found() {
let app = test::init_service(
App::new().route("/users/{id}", web::get().to(get_user))
).await;
let req = test::TestRequest::get()
.uri("/users/1")
.to_request();
let resp = test::call_service(&app, req).await;
assert_eq!(resp.status(), http::StatusCode::OK);
let user: User = test::read_body_json(resp).await;
assert_eq!(user.id, 1);
assert_eq!(user.name, "Alice");
assert_eq!(user.email, "alice@example.com");
}
#[actix_rt::test]
async fn test_get_user_not_found() {
let app = test::init_service(
App::new().route("/users/{id}", web::get().to(get_user))
).await;
let req = test::TestRequest::get()
.uri("/users/999")
.to_request();
let resp = test::call_service(&app, req).await;
assert_eq!(resp.status(), http::StatusCode::NOT_FOUND);
}
#[actix_rt::test]
async fn test_create_user() {
let app = test::init_service(
App::new().route("/users", web::post().to(create_user))
).await;
let user = User {
id: 2,
name: "Bob".to_string(),
email: "bob@example.com".to_string(),
};
let req = test::TestRequest::post()
.uri("/users")
.set_json(&user)
.to_request();
let resp = test::call_service(&app, req).await;
assert_eq!(resp.status(), http::StatusCode::CREATED);
let created_user: User = test::read_body_json(resp).await;
assert_eq!(created_user, user);
}
}
Performance and Scaling
Rust web servers excel in performance. With Tokio's async runtime, they handle thousands of concurrent connections efficiently.
I've migrated several Node.js services to Rust and consistently seen reduced CPU usage, lower memory consumption, and more consistent response times under load.
For scaling, Rust applications can run in containers with minimal resource usage. A typical Rust web service often requires less than 10MB of RAM at startup, compared to hundreds of megabytes for JVM or Node.js applications.
API Documentation
Rust's docstrings support Markdown and code examples that can be verified during testing:
/// Creates a new user
///
/// # Examples
///
/// ```
{% endraw %}
/// let user = create_user("Alice", "alice@example.com").await?;
/// assert_eq!(user.name, "Alice");
///
{% raw %}
///
/// # Errors
///
/// Returns an error if the user cannot be created
async fn create_user(name: &str, email: &str) -> Result {
// Implementation
}
Combined with tools like Swagger
---
## 101 Books
**101 Books** is an AI-driven publishing company co-founded by author **Aarav Joshi**. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as **$4**—making quality knowledge accessible to everyone.
Check out our book **[Golang Clean Code](https://www.amazon.com/dp/B0DQQF9K3Z)** available on Amazon.
Stay tuned for updates and exciting news. When shopping for books, search for **Aarav Joshi** to find more of our titles. Use the provided link to enjoy **special discounts**!
## Our Creations
Be sure to check out our creations:
**[Investor Central](https://www.investorcentral.co.uk/)** | **[Investor Central Spanish](https://spanish.investorcentral.co.uk/)** | **[Investor Central German](https://german.investorcentral.co.uk/)** | **[Smart Living](https://smartliving.investorcentral.co.uk/)** | **[Epochs & Echoes](https://epochsandechoes.com/)** | **[Puzzling Mysteries](https://www.puzzlingmysteries.com/)** | **[Hindutva](http://hindutva.epochsandechoes.com/)** | **[Elite Dev](https://elitedev.in/)** | **[JS Schools](https://jsschools.com/)**
---
### We are on Medium
**[Tech Koala Insights](https://techkoalainsights.com/)** | **[Epochs & Echoes World](https://world.epochsandechoes.com/)** | **[Investor Central Medium](https://medium.investorcentral.co.uk/)** | **[Puzzling Mysteries Medium](https://medium.com/puzzling-mysteries)** | **[Science & Epochs Medium](https://science.epochsandechoes.com/)** | **[Modern Hindutva](https://modernhindutva.substack.com/)**