在当今的微服务架构和云原生应用中,高性能的 API 服务是系统成功的关键。虽然 Node.js、Python 等语言在 API 开发中占据主流地位,但 Rust 凭借其卓越的性能和内存安全性,正在成为构建关键基础设施的新选择。本文将带你使用 Rust 和 Actix-web 框架,从零开始构建一个完整的高性能 REST API。
为什么选择 Rust 和 Actix-web?
Rust 的优势
- 零成本抽象:高级特性不会带来运行时开销
- 内存安全:编译时保证内存安全,无需垃圾回收
- 并发安全:所有权系统防止数据竞争
- 卓越性能:与 C/C++ 相媲美的运行速度
Actix-web 的特点
- Actor 模型:基于 Actor 的并发模型
- 类型安全:强大的类型系统
- 中间件支持:灵活的中间件生态系统
- 异步支持:完整的 async/await 支持
项目搭建
1. 创建项目
cargo new rust-api-demo
cd rust-api-demo
2. 添加依赖
修改 Cargo.toml:
[package]
name = "rust-api-demo"
version = "0.1.0"
edition = "2021"
[dependencies]
actix-web = "4.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }
chrono = { version = "0.4", features = ["serde"] }
uuid = { version = "1.0", features = ["v4", "serde"] }
sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "postgres", "chrono", "uuid"] }
dotenv = "0.15"
核心架构设计
分层架构
├── src/
│ ├── main.rs # 应用入口
│ ├── models/ # 数据模型
│ ├── handlers/ # 请求处理器
│ ├── routes/ # 路由定义
│ ├── database/ # 数据库连接
│ └── middleware/ # 中间件
完整实现
1. 定义数据模型
// src/models/user.rs
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
use uuid::Uuid;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct User {
pub id: Uuid,
pub username: String,
pub email: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
pub struct CreateUser {
pub username: String,
pub email: String,
pub password: String,
}
#[derive(Debug, Deserialize)]
pub struct UpdateUser {
pub username: Option<String>,
pub email: Option<String>,
}
// 实现 From trait 用于类型转换
impl From<CreateUser> for User {
fn from(user: CreateUser) -> Self {
let now = Utc::now();
User {
id: Uuid::new_v4(),
username: user.username,
email: user.email,
created_at: now,
updated_at: now,
}
}
}
2. 数据库连接池
// src/database/mod.rs
use sqlx::{PgPool, postgres::PgPoolOptions};
use std::env;
pub type DbPool = PgPool;
pub async fn create_pool() -> Result<DbPool, sqlx::Error> {
let database_url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");
PgPoolOptions::new()
.max_connections(10)
.connect(&database_url)
.await
}
3. 请求处理器
// src/handlers/user_handler.rs
use actix_web::{web, HttpResponse, Responder};
use crate::models::user::{User, CreateUser, UpdateUser};
use crate::database::DbPool;
use uuid::Uuid;
// 创建用户
pub async fn create_user(
pool: web::Data<DbPool>,
user_data: web::Json<CreateUser>,
) -> impl Responder {
let user: User = user_data.into_inner().into();
let result = sqlx::query!(
r#"
INSERT INTO users (id, username, email, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5)
RETURNING id, username, email, created_at, updated_at
"#,
user.id,
user.username,
user.email,
user.created_at,
user.updated_at
)
.fetch_one(pool.get_ref())
.await;
match result {
Ok(record) => {
let created_user = User {
id: record.id,
username: record.username,
email: record.email,
created_at: record.created_at,
updated_at: record.updated_at,
};
HttpResponse::Created().json(created_user)
}
Err(e) => {
eprintln!("Failed to create user: {}", e);
HttpResponse::InternalServerError().body("Failed to create user")
}
}
}
// 获取用户列表(带分页)
pub async fn get_users(
pool: web::Data<DbPool>,
query: web::Query<PaginationQuery>,
) -> impl Responder {
let page = query.page.unwrap_or(1);
let per_page = query.per_page.unwrap_or(10);
let offset = (page - 1) * per_page;
let users = sqlx::query_as!(
User,
r#"
SELECT id, username, email, created_at, updated_at
FROM users
ORDER BY created_at DESC
LIMIT $1 OFFSET $2
"#,
per_page as i64,
offset as i64
)
.fetch_all(pool.get_ref())
.await;
match users {
Ok(users) => HttpResponse::Ok().json(users),
Err(e) => {
eprintln!("Failed to fetch users: {}", e);
HttpResponse::InternalServerError().body("Failed to fetch users")
}
}
}
#[derive(Debug, Deserialize)]
pub struct PaginationQuery {
pub page: Option<u32>,
pub per_page: Option<u32>,
}
4. 自定义中间件
// src/middleware/logger.rs
use actix_web::{
dev::{Service, ServiceRequest, ServiceResponse, Transform},
Error,
};
use futures::future::{ok, Ready};
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
time::Instant,
};
pub struct Logger;
impl<S, B> Transform<S, ServiceRequest> for Logger
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = LoggerMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(LoggerMiddleware { service })
}
}
pub struct LoggerMiddleware<S> {
service: S,
}
impl<S, B> Service<ServiceRequest> for LoggerMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&self, req: ServiceRequest) -> Self::Future {
let start_time = Instant::now();
let method = req.method().clone();
let path = req.path().to_string();
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
let duration = start_time.elapsed();
println!(
"{} {} - {}ms - Status: {}",
method,
path,
duration.as_millis(),
res.status()
);
Ok(res)
})
}
}
5. 路由配置
// src/routes/mod.rs
use actix_web::web;
use crate::handlers::user_handler