Files
rust-user-api/implementation_details.md
enoch 28afc7532f feat: [阶段1] 项目初始化和基础设置
- 创建 Cargo.toml 配置文件,包含所有必要依赖
- 建立完整的项目模块结构(config, models, handlers, routes, services, storage, middleware, utils)
- 实现用户数据模型和内存存储
- 创建基础的 HTTP 处理器和路由配置
- 添加错误处理和 JWT 认证中间件
- 配置环境变量和日志系统
- 创建项目文档和学习指南
- 服务器可以成功编译和启动
2025-08-04 16:49:50 +08:00

719 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Rust REST API Server - 详细实现指南
## 阶段 1: 项目初始化和基础设置
### 1.1 创建项目和基础配置
**目标**: 建立 Rust 项目基础结构和依赖管理
**具体步骤**:
1. 使用 `cargo new rust-user-api --bin` 创建新项目
2. 配置 `Cargo.toml` 文件,添加必要依赖
3. 创建基础目录结构
4. 设置开发环境配置
**Cargo.toml 配置**:
```toml
[package]
name = "rust-user-api"
version = "0.1.0"
edition = "2021"
[dependencies]
# Web 框架
axum = "0.7"
tokio = { version = "1.0", features = ["full"] }
# 序列化
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
# 时间处理
chrono = { version = "0.4", features = ["serde"] }
# UUID 生成
uuid = { version = "1.0", features = ["v4", "serde"] }
# 环境变量
dotenv = "0.15"
# 日志
tracing = "0.1"
tracing-subscriber = "0.3"
# HTTP 客户端(用于测试)
[dev-dependencies]
reqwest = { version = "0.11", features = ["json"] }
```
**学习重点**:
- Cargo 包管理器的使用
- Rust 项目结构约定
- 依赖版本管理和特性选择
---
## 阶段 2: 创建基本的 HTTP Server 和路由结构
### 2.1 实现基础 HTTP 服务器
**目标**: 创建一个能够响应 HTTP 请求的基础服务器
**核心文件**:
- `src/main.rs` - 应用入口点
- `src/lib.rs` - 库入口
- `src/routes/mod.rs` - 路由配置
**main.rs 实现**:
```rust
use axum::{
routing::get,
Router,
response::Json,
};
use serde_json::{json, Value};
use std::net::SocketAddr;
use tracing_subscriber;
#[tokio::main]
async fn main() {
// 初始化日志
tracing_subscriber::init();
// 创建路由
let app = Router::new()
.route("/", get(root))
.route("/health", get(health_check));
// 启动服务器
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("Server running on http://{}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
async fn root() -> Json<Value> {
Json(json!({
"message": "Welcome to Rust User API",
"version": "0.1.0"
}))
}
async fn health_check() -> Json<Value> {
Json(json!({
"status": "healthy",
"timestamp": chrono::Utc::now()
}))
}
```
**学习重点**:
- Axum 框架基础概念
- 异步编程 (`async/await`)
- 路由定义和处理器函数
- JSON 响应处理
### 2.2 模块化路由结构
**routes/mod.rs 实现**:
```rust
use axum::{Router, routing::get};
use crate::handlers;
pub fn create_routes() -> Router {
Router::new()
.route("/", get(handlers::root))
.route("/health", get(handlers::health_check))
.nest("/api", api_routes())
}
fn api_routes() -> Router {
Router::new()
.route("/users", get(handlers::user::list_users))
// 后续添加更多路由
}
```
**学习重点**:
- 模块系统和代码组织
- 路由嵌套和分组
- 处理器函数的分离
---
## 阶段 3: 实现用户数据模型和内存存储
### 3.1 定义数据模型
**目标**: 创建类型安全的数据模型和序列化支持
**models/user.rs 实现**:
```rust
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct User {
pub id: Uuid,
pub username: String,
pub email: String,
pub password_hash: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Serialize)]
pub struct UserResponse {
pub id: Uuid,
pub username: String,
pub email: String,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
pub struct CreateUserRequest {
pub username: String,
pub email: String,
pub password: String,
}
#[derive(Debug, Deserialize)]
pub struct UpdateUserRequest {
pub username: Option<String>,
pub email: Option<String>,
}
impl From<User> for UserResponse {
fn from(user: User) -> Self {
UserResponse {
id: user.id,
username: user.username,
email: user.email,
created_at: user.created_at,
}
}
}
```
**学习重点**:
- Rust 结构体定义
- Serde 序列化和反序列化
- 类型转换和 `From` trait
- 可选字段处理
### 3.2 实现内存存储
**storage/memory.rs 实现**:
```rust
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use uuid::Uuid;
use crate::models::user::User;
pub type UserStorage = Arc<RwLock<HashMap<Uuid, User>>>;
#[derive(Clone)]
pub struct MemoryUserStore {
users: UserStorage,
}
impl MemoryUserStore {
pub fn new() -> Self {
Self {
users: Arc::new(RwLock::new(HashMap::new())),
}
}
pub async fn create_user(&self, user: User) -> Result<User, String> {
let mut users = self.users.write().unwrap();
users.insert(user.id, user.clone());
Ok(user)
}
pub async fn get_user(&self, id: &Uuid) -> Option<User> {
let users = self.users.read().unwrap();
users.get(id).cloned()
}
pub async fn list_users(&self) -> Vec<User> {
let users = self.users.read().unwrap();
users.values().cloned().collect()
}
pub async fn update_user(&self, id: &Uuid, updated_user: User) -> Option<User> {
let mut users = self.users.write().unwrap();
users.insert(*id, updated_user.clone());
Some(updated_user)
}
pub async fn delete_user(&self, id: &Uuid) -> bool {
let mut users = self.users.write().unwrap();
users.remove(id).is_some()
}
}
```
**学习重点**:
- HashMap 数据结构
- 线程安全 (`Arc<RwLock<T>>`)
- 异步方法定义
- 错误处理基础
---
## 阶段 4: 实现用户 CRUD API 端点
### 4.1 创建处理器函数
**handlers/user.rs 实现**:
```rust
use axum::{
extract::{Path, State},
http::StatusCode,
response::Json,
Json as RequestJson,
};
use uuid::Uuid;
use chrono::Utc;
use crate::models::user::{User, UserResponse, CreateUserRequest, UpdateUserRequest};
use crate::storage::memory::MemoryUserStore;
pub async fn create_user(
State(store): State<MemoryUserStore>,
RequestJson(payload): RequestJson<CreateUserRequest>,
) -> Result<(StatusCode, Json<UserResponse>), StatusCode> {
let user = User {
id: Uuid::new_v4(),
username: payload.username,
email: payload.email,
password_hash: hash_password(&payload.password),
created_at: Utc::now(),
updated_at: Utc::now(),
};
match store.create_user(user).await {
Ok(user) => Ok((StatusCode::CREATED, Json(user.into()))),
Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
}
}
pub async fn get_user(
State(store): State<MemoryUserStore>,
Path(id): Path<Uuid>,
) -> Result<Json<UserResponse>, StatusCode> {
match store.get_user(&id).await {
Some(user) => Ok(Json(user.into())),
None => Err(StatusCode::NOT_FOUND),
}
}
pub async fn list_users(
State(store): State<MemoryUserStore>,
) -> Json<Vec<UserResponse>> {
let users = store.list_users().await;
let responses: Vec<UserResponse> = users.into_iter().map(|u| u.into()).collect();
Json(responses)
}
pub async fn update_user(
State(store): State<MemoryUserStore>,
Path(id): Path<Uuid>,
RequestJson(payload): RequestJson<UpdateUserRequest>,
) -> Result<Json<UserResponse>, StatusCode> {
match store.get_user(&id).await {
Some(mut user) => {
if let Some(username) = payload.username {
user.username = username;
}
if let Some(email) = payload.email {
user.email = email;
}
user.updated_at = Utc::now();
match store.update_user(&id, user).await {
Some(updated_user) => Ok(Json(updated_user.into())),
None => Err(StatusCode::INTERNAL_SERVER_ERROR),
}
}
None => Err(StatusCode::NOT_FOUND),
}
}
pub async fn delete_user(
State(store): State<MemoryUserStore>,
Path(id): Path<Uuid>,
) -> StatusCode {
if store.delete_user(&id).await {
StatusCode::NO_CONTENT
} else {
StatusCode::NOT_FOUND
}
}
fn hash_password(password: &str) -> String {
// 简单的密码哈希(生产环境应使用 bcrypt
format!("hashed_{}", password)
}
```
**学习重点**:
- Axum 提取器 (`State`, `Path`, `Json`)
- HTTP 状态码处理
- 错误处理和 `Result` 类型
- 异步处理器函数
### 4.2 完整路由配置
**更新 routes/mod.rs**:
```rust
use axum::{
Router,
routing::{get, post, put, delete},
};
use crate::handlers;
use crate::storage::memory::MemoryUserStore;
pub fn create_routes(store: MemoryUserStore) -> Router {
Router::new()
.route("/", get(handlers::root))
.route("/health", get(handlers::health_check))
.nest("/api", api_routes())
.with_state(store)
}
fn api_routes() -> Router<MemoryUserStore> {
Router::new()
.route("/users", get(handlers::user::list_users).post(handlers::user::create_user))
.route("/users/:id",
get(handlers::user::get_user)
.put(handlers::user::update_user)
.delete(handlers::user::delete_user)
)
}
```
**学习重点**:
- 状态管理和依赖注入
- RESTful 路由设计
- HTTP 方法映射
---
## 阶段 5: 添加请求验证和错误处理
### 5.1 自定义错误类型
**utils/errors.rs 实现**:
```rust
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use serde_json::json;
#[derive(Debug)]
pub enum ApiError {
ValidationError(String),
NotFound(String),
InternalError(String),
Unauthorized,
}
impl IntoResponse for ApiError {
fn into_response(self) -> Response {
let (status, error_message) = match self {
ApiError::ValidationError(msg) => (StatusCode::BAD_REQUEST, msg),
ApiError::NotFound(msg) => (StatusCode::NOT_FOUND, msg),
ApiError::InternalError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
ApiError::Unauthorized => (StatusCode::UNAUTHORIZED, "Unauthorized".to_string()),
};
let body = Json(json!({
"error": error_message,
"status": status.as_u16()
}));
(status, body).into_response()
}
}
```
### 5.2 请求验证
**添加验证逻辑**:
```rust
use validator::{Validate, ValidationError};
#[derive(Debug, Deserialize, Validate)]
pub struct CreateUserRequest {
#[validate(length(min = 3, max = 50))]
pub username: String,
#[validate(email)]
pub email: String,
#[validate(length(min = 8))]
pub password: String,
}
// 在处理器中使用验证
pub async fn create_user(
State(store): State<MemoryUserStore>,
RequestJson(payload): RequestJson<CreateUserRequest>,
) -> Result<(StatusCode, Json<UserResponse>), ApiError> {
// 验证请求数据
payload.validate()
.map_err(|e| ApiError::ValidationError(format!("Validation failed: {:?}", e)))?;
// ... 其余逻辑
}
```
**学习重点**:
- 自定义错误类型
- `IntoResponse` trait 实现
- 请求验证和数据校验
- 错误传播 (`?` 操作符)
---
## 阶段 6: 实现基础的身份认证 (JWT)
### 6.1 JWT 中间件
**middleware/auth.rs 实现**:
```rust
use axum::{
extract::{Request, State},
http::{header, StatusCode},
middleware::Next,
response::Response,
};
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
pub sub: String, // 用户ID
pub exp: usize, // 过期时间
}
pub async fn auth_middleware(
mut req: Request,
next: Next,
) -> Result<Response, StatusCode> {
let auth_header = req.headers()
.get(header::AUTHORIZATION)
.and_then(|header| header.to_str().ok());
let auth_header = if let Some(auth_header) = auth_header {
auth_header
} else {
return Err(StatusCode::UNAUTHORIZED);
};
if let Some(token) = auth_header.strip_prefix("Bearer ") {
match verify_jwt(token) {
Ok(claims) => {
req.extensions_mut().insert(claims);
Ok(next.run(req).await)
}
Err(_) => Err(StatusCode::UNAUTHORIZED),
}
} else {
Err(StatusCode::UNAUTHORIZED)
}
}
fn verify_jwt(token: &str) -> Result<Claims, jsonwebtoken::errors::Error> {
let key = DecodingKey::from_secret("secret".as_ref());
let validation = Validation::default();
decode::<Claims>(token, &key, &validation)
.map(|data| data.claims)
}
pub fn create_jwt(user_id: &str) -> Result<String, jsonwebtoken::errors::Error> {
let expiration = chrono::Utc::now()
.checked_add_signed(chrono::Duration::hours(24))
.expect("valid timestamp")
.timestamp() as usize;
let claims = Claims {
sub: user_id.to_string(),
exp: expiration,
};
let key = EncodingKey::from_secret("secret".as_ref());
encode(&Header::default(), &claims, &key)
}
```
### 6.2 登录端点
**添加认证处理器**:
```rust
#[derive(Deserialize)]
pub struct LoginRequest {
pub username: String,
pub password: String,
}
#[derive(Serialize)]
pub struct LoginResponse {
pub token: String,
pub user: UserResponse,
}
pub async fn login(
State(store): State<MemoryUserStore>,
RequestJson(payload): RequestJson<LoginRequest>,
) -> Result<Json<LoginResponse>, ApiError> {
// 查找用户(简化版本,实际应该按用户名查找)
let users = store.list_users().await;
let user = users.into_iter()
.find(|u| u.username == payload.username)
.ok_or_else(|| ApiError::NotFound("User not found".to_string()))?;
// 验证密码(简化版本)
if user.password_hash != format!("hashed_{}", payload.password) {
return Err(ApiError::Unauthorized);
}
// 生成 JWT
let token = create_jwt(&user.id.to_string())
.map_err(|_| ApiError::InternalError("Failed to create token".to_string()))?;
Ok(Json(LoginResponse {
token,
user: user.into(),
}))
}
```
**学习重点**:
- JWT 概念和实现
- 中间件设计模式
- 请求扩展和状态传递
- 身份认证流程
---
## 阶段 7: 添加 API 文档和测试用例
### 7.1 集成测试
**tests/api_tests.rs 实现**:
```rust
use reqwest;
use serde_json::json;
use tokio;
#[tokio::test]
async fn test_create_user() {
let client = reqwest::Client::new();
let user_data = json!({
"username": "testuser",
"email": "test@example.com",
"password": "password123"
});
let response = client
.post("http://localhost:3000/api/users")
.json(&user_data)
.send()
.await
.expect("Failed to send request");
assert_eq!(response.status(), 201);
let user: serde_json::Value = response.json().await.expect("Failed to parse JSON");
assert_eq!(user["username"], "testuser");
assert_eq!(user["email"], "test@example.com");
}
#[tokio::test]
async fn test_get_user() {
// 首先创建用户,然后获取
// ... 测试逻辑
}
```
### 7.2 API 文档
**docs/api.md**:
```markdown
# User API Documentation
## Authentication
All protected endpoints require a Bearer token in the Authorization header:
```
Authorization: Bearer <jwt_token>
```
## Endpoints
### POST /api/auth/login
Login with username and password.
**Request Body:**
```json
{
"username": "string",
"password": "string"
}
```
**Response:**
```json
{
"token": "jwt_token_string",
"user": {
"id": "uuid",
"username": "string",
"email": "string",
"created_at": "timestamp"
}
}
```
### GET /api/users
Get all users (requires authentication).
**Response:**
```json
[
{
"id": "uuid",
"username": "string",
"email": "string",
"created_at": "timestamp"
}
]
```
```
**学习重点**:
- 集成测试编写
- HTTP 客户端测试
- API 文档编写规范
- 测试驱动开发
---
## 后续阶段概览
### 阶段 8-12: 高级功能
- **数据库集成**: SQLite/PostgreSQL 集成ORM 使用
- **高级功能**: 分页、搜索、过滤、排序
- **生产准备**: 配置管理、日志记录、错误监控
- **部署**: Docker 容器化、环境配置
每个阶段都建立在前一个阶段的基础上,确保学习的连续性和实用性。通过这种渐进式的方法,您将全面掌握 Rust web 开发的各个方面。