Systems programming, memory safety, performance-critical applications, WebAssembly.
Fast. Safe. Fearless concurrency.
Before implementing with Rust:
| Need | Solution |
|---|---|
| Web API | Axum or Actix Web |
| CLI tool | Clap |
| Async runtime | Tokio |
| WebAssembly | wasm-bindgen, wasm-pack |
| Database | SQLx, Diesel |
| Serialization |
| Serde |
| Error handling | thiserror, anyhow |
| Dimension | Spectrum |
|---|---|
| Performance priority | Latency-sensitive ←→ Throughput-focused |
| Safety requirements | Standard ←→ Security-critical |
| Team experience | Learning Rust ←→ Seasoned Rustaceans |
| Integration | Greenfield ←→ Legacy system interop |
| If Context Is... | Then Consider... |
|---|---|
| Building high-perf API | Axum + Tokio + SQLx |
| CLI tool | Clap + tokio for async |
| WebAssembly | wasm-bindgen + wasm-pack |
| Cloud infrastructure | Tokio + AWS SDK |
| Blockchain/crypto | Custom + cryptography crates |
| Embedded systems | no_std, embedded-hal |
# Cargo.toml
[package]
name = "my-api"
version = "0.1.0"
edition = "2021"
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio"] }
tower-http = { version = "0.5", features = ["cors", "trace"] }
tracing = "0.1"
tracing-subscriber = "0.3"
// src/main.rs
use axum::{
routing::{get, post},
Json, Router,
};
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
#[derive(Serialize)]
struct HealthResponse {
status: String,
}
#[derive(Deserialize)]
struct CreateUser {
name: String,
email: String,
}
#[derive(Serialize)]
struct User {
id: i64,
name: String,
email: String,
}
async fn health() -> Json<HealthResponse> {
Json(HealthResponse {
status: "ok".to_string(),
})
}
async fn create_user(Json(payload): Json<CreateUser>) -> Json<User> {
Json(User {
id: 1,
name: payload.name,
email: payload.email,
})
}
#[tokio::main]
async fn main() {
tracing_subscriber::init();
let app = Router::new()
.route("/health", get(health))
.route("/users", post(create_user));
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
println!("Listening on {}", addr);
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ApiError {
#[error("Database error: {0}")]
Database(#[from] sqlx::Error),
#[error("Not found: {0}")]
NotFound(String),
#[error("Validation error: {0}")]
Validation(String),
}
// Convert to Axum response
impl axum::response::IntoResponse for ApiError {
fn into_response(self) -> axum::response::Response {
let (status, message) = match &self {
ApiError::Database(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Internal error"),
ApiError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.as_str()),
ApiError::Validation(msg) => (StatusCode::BAD_REQUEST, msg.as_str()),
};
(status, Json(json!({ "error": message }))).into_response()
}
}
// Concurrent execution
let (users, posts) = tokio::join!(
fetch_users(),
fetch_posts(),
);
// Spawn background task