Files
udmin/docs/ROUTES.md
ayou a3f2f99a68 docs: 添加项目文档包括总览、架构、流程引擎和服务层
新增以下文档文件:
- PROJECT_OVERVIEW.md 项目总览文档
- BACKEND_ARCHITECTURE.md 后端架构文档
- FRONTEND_ARCHITECTURE.md 前端架构文档
- FLOW_ENGINE.md 流程引擎文档
- SERVICES.md 服务层文档
- ERROR_HANDLING.md 错误处理模块文档

文档内容涵盖项目整体介绍、技术架构、核心模块设计和实现细节
2025-09-24 20:21:45 +08:00

31 KiB

路由层文档

概述

路由层是 UdminAI 的 HTTP API 接口层,负责处理客户端请求、参数验证、权限检查、调用服务层业务逻辑,并返回统一格式的响应。基于 Axum 框架构建,提供 RESTful API 接口。

架构设计

路由模块结构

routes/
├── mod.rs              # 路由模块导出和总路由配置
├── auth.rs             # 认证相关路由
├── user.rs             # 用户管理路由
├── role.rs             # 角色管理路由
├── permission.rs       # 权限管理路由
├── flow.rs             # 流程管理路由
├── schedule_job.rs     # 定时任务路由
├── system.rs           # 系统管理路由
├── log.rs              # 日志查询路由
├── notification.rs     # 通知管理路由
└── websocket.rs        # WebSocket 路由

设计原则

  • RESTful 设计: 遵循 REST API 设计规范
  • 统一响应格式: 所有接口返回统一的响应格式
  • 参数验证: 在路由层进行请求参数验证
  • 权限控制: 集成权限中间件进行访问控制
  • 错误处理: 统一的错误处理和响应
  • 文档支持: 支持 OpenAPI/Swagger 文档生成

总路由配置 (mod.rs)

路由树结构

pub fn create_routes() -> Router {
    Router::new()
        // 认证路由 (无需认证)
        .nest("/auth", auth::routes())
        
        // API 路由 (需要认证)
        .nest("/api", 
            Router::new()
                .nest("/users", user::routes())
                .nest("/roles", role::routes())
                .nest("/permissions", permission::routes())
                .nest("/flows", flow::routes())
                .nest("/jobs", schedule_job::routes())
                .nest("/system", system::routes())
                .nest("/logs", log::routes())
                .nest("/notifications", notification::routes())
                .layer(AuthMiddleware::new())
        )
        
        // WebSocket 路由
        .nest("/ws", websocket::routes())
        
        // 静态文件路由
        .nest("/static", static_files::routes())
        
        // 健康检查
        .route("/health", get(health_check))
        
        // 中间件层
        .layer(CorsLayer::permissive())
        .layer(TraceLayer::new_for_http())
        .layer(CompressionLayer::new())
}

中间件配置

/// 应用中间件
pub fn apply_middlewares(app: Router) -> Router {
    app
        // 请求追踪
        .layer(TraceLayer::new_for_http())
        
        // CORS 支持
        .layer(CorsLayer::new()
            .allow_origin(Any)
            .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE])
            .allow_headers([AUTHORIZATION, CONTENT_TYPE])
        )
        
        // 请求压缩
        .layer(CompressionLayer::new())
        
        // 请求限流
        .layer(RateLimitLayer::new(100, Duration::from_secs(60)))
        
        // 请求日志
        .layer(RequestLogLayer::new())
}

认证路由 (auth.rs)

路由定义

pub fn routes() -> Router {
    Router::new()
        .route("/login", post(login))
        .route("/logout", post(logout))
        .route("/refresh", post(refresh_token))
        .route("/register", post(register))
        .route("/forgot-password", post(forgot_password))
        .route("/reset-password", post(reset_password))
        .route("/verify-email", post(verify_email))
}

接口实现

用户登录

/// POST /auth/login
/// 用户登录接口
pub async fn login(
    State(app_state): State<AppState>,
    Json(req): Json<LoginReq>,
) -> Result<Json<ApiResponse<LoginResp>>, AppError> {
    // 参数验证
    req.validate().map_err(|e| AppError::BadRequest(e.to_string()))?;
    
    // 用户认证
    let user = user_service::authenticate(
        &app_state.db,
        &req.username,
        &req.password,
    ).await?;
    
    // 生成 JWT Token
    let token = jwt::generate_token(&user.id, &app_state.jwt_secret)?;
    let refresh_token = jwt::generate_refresh_token(&user.id, &app_state.jwt_secret)?;
    
    // 记录登录日志
    log_service::log_operation(
        &app_state.db,
        OperationLog {
            user_id: user.id.clone(),
            operation: "login".to_string(),
            resource: "auth".to_string(),
            resource_id: None,
            details: json!({ "username": req.username }),
            ip_address: extract_client_ip(&req),
            user_agent: extract_user_agent(&req),
            timestamp: now_fixed_offset(),
        },
    ).await?;
    
    Ok(Json(ApiResponse::success(LoginResp {
        user,
        token,
        refresh_token,
        expires_in: 3600,
    })))
}

请求/响应结构

#[derive(Debug, Deserialize, Validate)]
pub struct LoginReq {
    #[validate(length(min = 3, max = 50))]
    pub username: String,
    #[validate(length(min = 6))]
    pub password: String,
    pub remember_me: Option<bool>,
}

#[derive(Debug, Serialize)]
pub struct LoginResp {
    pub user: UserDoc,
    pub token: String,
    pub refresh_token: String,
    pub expires_in: u64,
}

用户管理路由 (user.rs)

路由定义

pub fn routes() -> Router {
    Router::new()
        .route("/", get(list_users).post(create_user))
        .route("/:id", get(get_user).put(update_user).delete(delete_user))
        .route("/:id/roles", get(get_user_roles).put(update_user_roles))
        .route("/:id/permissions", get(get_user_permissions))
        .route("/:id/password", put(change_password))
        .route("/:id/status", put(update_user_status))
        .route("/profile", get(get_current_user).put(update_profile))
        .route("/avatar", post(upload_avatar))
}

接口实现

用户列表查询

/// GET /api/users
/// 分页查询用户列表
pub async fn list_users(
    State(app_state): State<AppState>,
    Query(params): Query<ListUsersQuery>,
    Extension(current_user): Extension<CurrentUser>,
) -> Result<Json<ApiResponse<PageResp<UserDoc>>>, AppError> {
    // 权限检查
    permission_service::check_user_permission(
        &app_state.db,
        &current_user.id,
        "user",
        "read",
    ).await?;
    
    // 构建过滤条件
    let filters = UserFilters {
        username: params.username,
        email: params.email,
        status: params.status,
        role_ids: params.role_ids,
        created_after: params.created_after,
        created_before: params.created_before,
    };
    
    // 查询用户列表
    let result = user_service::list_users(
        &app_state.db,
        params.page.unwrap_or(1),
        params.page_size.unwrap_or(20),
        Some(filters),
    ).await?;
    
    Ok(Json(ApiResponse::success(result)))
}

创建用户

/// POST /api/users
/// 创建新用户
pub async fn create_user(
    State(app_state): State<AppState>,
    Extension(current_user): Extension<CurrentUser>,
    Json(req): Json<CreateUserReq>,
) -> Result<Json<ApiResponse<UserDoc>>, AppError> {
    // 参数验证
    req.validate().map_err(|e| AppError::BadRequest(e.to_string()))?;
    
    // 权限检查
    permission_service::check_user_permission(
        &app_state.db,
        &current_user.id,
        "user",
        "create",
    ).await?;
    
    // 创建用户
    let user = user_service::create_user(&app_state.db, req).await?;
    
    // 记录操作日志
    log_service::log_operation(
        &app_state.db,
        OperationLog {
            user_id: current_user.id,
            operation: "create_user".to_string(),
            resource: "user".to_string(),
            resource_id: Some(user.id.clone()),
            details: json!({ "username": user.username }),
            ip_address: None,
            user_agent: None,
            timestamp: now_fixed_offset(),
        },
    ).await?;
    
    Ok(Json(ApiResponse::success(user)))
}

查询参数结构

#[derive(Debug, Deserialize)]
pub struct ListUsersQuery {
    pub page: Option<u64>,
    pub page_size: Option<u64>,
    pub username: Option<String>,
    pub email: Option<String>,
    pub status: Option<UserStatus>,
    pub role_ids: Option<Vec<String>>,
    pub created_after: Option<DateTime<FixedOffset>>,
    pub created_before: Option<DateTime<FixedOffset>>,
    pub sort_by: Option<String>,
    pub sort_order: Option<SortOrder>,
}

流程管理路由 (flow.rs)

路由定义

pub fn routes() -> Router {
    Router::new()
        .route("/", get(list_flows).post(create_flow))
        .route("/:id", get(get_flow).put(update_flow).delete(delete_flow))
        .route("/:id/versions", get(list_flow_versions).post(create_flow_version))
        .route("/:id/publish", post(publish_flow))
        .route("/:id/execute", post(execute_flow))
        .route("/:id/executions", get(list_flow_executions))
        .route("/executions/:execution_id", get(get_execution_detail))
        .route("/executions/:execution_id/stop", post(stop_execution))
        .route("/categories", get(list_flow_categories))
        .route("/templates", get(list_flow_templates))
}

接口实现

执行流程

/// POST /api/flows/:id/execute
/// 执行指定流程
pub async fn execute_flow(
    State(app_state): State<AppState>,
    Path(flow_id): Path<String>,
    Extension(current_user): Extension<CurrentUser>,
    Json(req): Json<ExecuteFlowReq>,
) -> Result<Json<ApiResponse<ExecutionResult>>, AppError> {
    // 权限检查
    permission_service::check_user_permission(
        &app_state.db,
        &current_user.id,
        "flow",
        "execute",
    ).await?;
    
    // 获取流程信息
    let flow = flow_service::get_flow_by_id(&app_state.db, &flow_id).await?
        .ok_or_else(|| AppError::NotFound("流程不存在".to_string()))?;
    
    // 检查流程状态
    if flow.status != FlowStatus::Published {
        return Err(AppError::BadRequest("只能执行已发布的流程".to_string()));
    }
    
    // 执行选项
    let options = ExecuteOptions {
        max_steps: req.max_steps,
        timeout_ms: req.timeout_ms,
        parallel: req.parallel.unwrap_or(false),
        stream_events: req.stream_events.unwrap_or(false),
    };
    
    // 执行流程
    let result = flow_service::execute_flow(
        &app_state.db,
        &flow_id,
        req.input.unwrap_or(json!({})),
        options,
    ).await?;
    
    // 记录执行日志
    log_service::log_operation(
        &app_state.db,
        OperationLog {
            user_id: current_user.id,
            operation: "execute_flow".to_string(),
            resource: "flow".to_string(),
            resource_id: Some(flow_id),
            details: json!({
                "execution_id": result.execution_id,
                "status": result.status
            }),
            ip_address: None,
            user_agent: None,
            timestamp: now_fixed_offset(),
        },
    ).await?;
    
    Ok(Json(ApiResponse::success(result)))
}

请求/响应结构

#[derive(Debug, Deserialize, Validate)]
pub struct ExecuteFlowReq {
    pub input: Option<serde_json::Value>,
    pub max_steps: Option<usize>,
    pub timeout_ms: Option<u64>,
    pub parallel: Option<bool>,
    pub stream_events: Option<bool>,
}

#[derive(Debug, Serialize)]
pub struct ExecutionResult {
    pub execution_id: String,
    pub status: ExecutionStatus,
    pub result: Option<serde_json::Value>,
    pub error: Option<String>,
    pub start_time: DateTime<FixedOffset>,
    pub end_time: Option<DateTime<FixedOffset>>,
    pub duration_ms: Option<u64>,
}

定时任务路由 (schedule_job.rs)

路由定义

pub fn routes() -> Router {
    Router::new()
        .route("/", get(list_jobs).post(create_job))
        .route("/:id", get(get_job).put(update_job).delete(delete_job))
        .route("/:id/enable", post(enable_job))
        .route("/:id/disable", post(disable_job))
        .route("/:id/trigger", post(trigger_job))
        .route("/:id/executions", get(list_job_executions))
        .route("/executions/:execution_id", get(get_execution_detail))
        .route("/cron/validate", post(validate_cron))
        .route("/cron/next-runs", post(get_next_runs))
}

接口实现

创建定时任务

/// POST /api/jobs
/// 创建定时任务
pub async fn create_job(
    State(app_state): State<AppState>,
    Extension(current_user): Extension<CurrentUser>,
    Json(req): Json<CreateScheduleJobReq>,
) -> Result<Json<ApiResponse<ScheduleJobDoc>>, AppError> {
    // 参数验证
    req.validate().map_err(|e| AppError::BadRequest(e.to_string()))?;
    
    // 权限检查
    permission_service::check_user_permission(
        &app_state.db,
        &current_user.id,
        "job",
        "create",
    ).await?;
    
    // 验证 Cron 表达式
    cron::Schedule::from_str(&req.cron_expression)
        .map_err(|_| AppError::BadRequest("无效的 Cron 表达式".to_string()))?;
    
    // 创建任务
    let job = schedule_job_service::create_schedule_job(&app_state.db, req).await?;
    
    // 注册到调度器
    if job.enabled {
        schedule_job_service::register_job_to_scheduler(
            &app_state.scheduler,
            &job,
        ).await?;
    }
    
    Ok(Json(ApiResponse::success(job)))
}

Cron 表达式验证

/// POST /api/jobs/cron/validate
/// 验证 Cron 表达式
pub async fn validate_cron(
    Json(req): Json<ValidateCronReq>,
) -> Result<Json<ApiResponse<ValidateCronResp>>, AppError> {
    let schedule = cron::Schedule::from_str(&req.cron_expression)
        .map_err(|e| AppError::BadRequest(format!("无效的 Cron 表达式: {}", e)))?;
    
    // 计算接下来的执行时间
    let now = Utc::now();
    let next_runs: Vec<DateTime<Utc>> = schedule
        .upcoming(Utc)
        .take(5)
        .collect();
    
    Ok(Json(ApiResponse::success(ValidateCronResp {
        valid: true,
        next_runs,
        description: describe_cron(&req.cron_expression),
    })))
}

WebSocket 路由 (websocket.rs)

路由定义

pub fn routes() -> Router {
    Router::new()
        .route("/flow-execution/:execution_id", get(flow_execution_ws))
        .route("/system-monitor", get(system_monitor_ws))
        .route("/notifications", get(notifications_ws))
        .route("/logs", get(logs_ws))
}

WebSocket 处理

流程执行监控

/// GET /ws/flow-execution/:execution_id
/// 流程执行实时监控
pub async fn flow_execution_ws(
    ws: WebSocketUpgrade,
    Path(execution_id): Path<String>,
    Extension(current_user): Extension<CurrentUser>,
    State(app_state): State<AppState>,
) -> Result<Response, AppError> {
    // 权限检查
    permission_service::check_user_permission(
        &app_state.db,
        &current_user.id,
        "flow",
        "read",
    ).await?;
    
    Ok(ws.on_upgrade(move |socket| {
        handle_flow_execution_ws(socket, execution_id, current_user, app_state)
    }))
}

async fn handle_flow_execution_ws(
    socket: WebSocket,
    execution_id: String,
    current_user: CurrentUser,
    app_state: AppState,
) {
    let (mut sender, mut receiver) = socket.split();
    
    // 订阅执行事件
    let mut event_stream = app_state.event_bus
        .subscribe(&format!("flow_execution:{}", execution_id))
        .await;
    
    // 发送事件到客户端
    tokio::spawn(async move {
        while let Ok(event) = event_stream.recv().await {
            let message = serde_json::to_string(&event).unwrap();
            if sender.send(Message::Text(message)).await.is_err() {
                break;
            }
        }
    });
    
    // 处理客户端消息
    while let Some(msg) = receiver.next().await {
        match msg {
            Ok(Message::Text(text)) => {
                // 处理客户端命令
                if let Ok(command) = serde_json::from_str::<WsCommand>(&text) {
                    handle_ws_command(command, &app_state).await;
                }
            }
            Ok(Message::Close(_)) => break,
            _ => {}
        }
    }
}

系统管理路由 (system.rs)

路由定义

pub fn routes() -> Router {
    Router::new()
        .route("/info", get(get_system_info))
        .route("/status", get(get_system_status))
        .route("/health", get(health_check))
        .route("/metrics", get(get_metrics))
        .route("/config", get(get_system_config).put(update_system_config))
        .route("/cache/clear", post(clear_cache))
        .route("/backup", post(create_backup))
        .route("/restore", post(restore_backup))
}

接口实现

系统状态监控

/// GET /api/system/status
/// 获取系统运行状态
pub async fn get_system_status(
    State(app_state): State<AppState>,
    Extension(current_user): Extension<CurrentUser>,
) -> Result<Json<ApiResponse<SystemStatus>>, AppError> {
    // 权限检查
    permission_service::check_user_permission(
        &app_state.db,
        &current_user.id,
        "system",
        "read",
    ).await?;
    
    // 获取系统状态
    let status = system_service::get_system_status(
        &app_state.db,
        &app_state.redis,
    ).await?;
    
    Ok(Json(ApiResponse::success(status)))
}

健康检查

/// GET /health
/// 系统健康检查
pub async fn health_check(
    State(app_state): State<AppState>,
) -> Result<Json<HealthCheckResp>, AppError> {
    let mut checks = HashMap::new();
    
    // 数据库健康检查
    let db_health = system_service::check_database_health(&app_state.db).await
        .unwrap_or(HealthStatus::Unhealthy);
    checks.insert("database".to_string(), db_health);
    
    // Redis 健康检查
    let redis_health = system_service::check_redis_health(&app_state.redis).await
        .unwrap_or(HealthStatus::Unhealthy);
    checks.insert("redis".to_string(), redis_health);
    
    // 整体健康状态
    let overall_status = if checks.values().all(|&status| status == HealthStatus::Healthy) {
        HealthStatus::Healthy
    } else {
        HealthStatus::Unhealthy
    };
    
    Ok(Json(HealthCheckResp {
        status: overall_status,
        timestamp: Utc::now(),
        checks,
    }))
}

响应格式

统一响应结构

#[derive(Debug, Serialize)]
pub struct ApiResponse<T> {
    pub success: bool,
    pub data: Option<T>,
    pub message: String,
    pub code: u32,
    pub timestamp: DateTime<Utc>,
}

impl<T> ApiResponse<T> {
    pub fn success(data: T) -> Self {
        Self {
            success: true,
            data: Some(data),
            message: "操作成功".to_string(),
            code: 200,
            timestamp: Utc::now(),
        }
    }
    
    pub fn error(message: String, code: u32) -> ApiResponse<()> {
        ApiResponse {
            success: false,
            data: None,
            message,
            code,
            timestamp: Utc::now(),
        }
    }
}

分页响应结构

#[derive(Debug, Serialize)]
pub struct PageResp<T> {
    pub items: Vec<T>,
    pub total: u64,
    pub page: u64,
    pub page_size: u64,
    pub total_pages: u64,
    pub has_next: bool,
    pub has_prev: bool,
}

错误处理

错误类型定义

#[derive(Debug, thiserror::Error)]
pub enum AppError {
    #[error("请求参数错误: {0}")]
    BadRequest(String),
    
    #[error("未授权访问")]
    Unauthorized,
    
    #[error("权限不足: {0}")]
    Forbidden(String),
    
    #[error("资源不存在: {0}")]
    NotFound(String),
    
    #[error("请求冲突: {0}")]
    Conflict(String),
    
    #[error("请求过于频繁")]
    TooManyRequests,
    
    #[error("内部服务器错误: {0}")]
    InternalServerError(String),
}

错误响应处理

impl IntoResponse for AppError {
    fn into_response(self) -> Response {
        let (status, code, message) = match self {
            AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, 400, msg),
            AppError::Unauthorized => (StatusCode::UNAUTHORIZED, 401, "未授权访问".to_string()),
            AppError::Forbidden(msg) => (StatusCode::FORBIDDEN, 403, msg),
            AppError::NotFound(msg) => (StatusCode::NOT_FOUND, 404, msg),
            AppError::Conflict(msg) => (StatusCode::CONFLICT, 409, msg),
            AppError::TooManyRequests => (StatusCode::TOO_MANY_REQUESTS, 429, "请求过于频繁".to_string()),
            AppError::InternalServerError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, 500, msg),
        };
        
        let response = ApiResponse::<()>::error(message, code);
        (status, Json(response)).into_response()
    }
}

中间件

认证中间件

#[derive(Clone)]
pub struct AuthMiddleware {
    jwt_secret: String,
}

impl AuthMiddleware {
    pub fn new(jwt_secret: String) -> Self {
        Self { jwt_secret }
    }
}

#[async_trait]
impl<S> FromRequestParts<S> for CurrentUser
where
    S: Send + Sync,
{
    type Rejection = AppError;
    
    async fn from_request_parts(
        parts: &mut Parts,
        state: &S,
    ) -> Result<Self, Self::Rejection> {
        // 从请求头获取 Token
        let auth_header = parts.headers
            .get(AUTHORIZATION)
            .and_then(|header| header.to_str().ok())
            .ok_or(AppError::Unauthorized)?;
        
        // 验证 Bearer Token 格式
        let token = auth_header
            .strip_prefix("Bearer ")
            .ok_or(AppError::Unauthorized)?;
        
        // 验证 JWT Token
        let claims = jwt::verify_token(token, &jwt_secret)
            .map_err(|_| AppError::Unauthorized)?;
        
        // 获取用户信息
        let app_state = parts.extensions.get::<AppState>()
            .ok_or(AppError::InternalServerError("应用状态未找到".to_string()))?;
        
        let user = user_service::get_user_by_id(&app_state.db, &claims.user_id).await
            .map_err(|e| AppError::InternalServerError(e.to_string()))?
            .ok_or(AppError::Unauthorized)?;
        
        Ok(CurrentUser {
            id: user.id,
            username: user.username,
            roles: user.roles,
        })
    }
}

权限中间件

pub struct PermissionMiddleware {
    resource: String,
    action: String,
}

impl PermissionMiddleware {
    pub fn new(resource: &str, action: &str) -> Self {
        Self {
            resource: resource.to_string(),
            action: action.to_string(),
        }
    }
}

#[async_trait]
impl<S> FromRequestParts<S> for PermissionGuard
where
    S: Send + Sync,
{
    type Rejection = AppError;
    
    async fn from_request_parts(
        parts: &mut Parts,
        state: &S,
    ) -> Result<Self, Self::Rejection> {
        // 获取当前用户
        let current_user = CurrentUser::from_request_parts(parts, state).await?;
        
        // 获取权限要求
        let permission_req = parts.extensions.get::<PermissionRequirement>()
            .ok_or(AppError::InternalServerError("权限要求未设置".to_string()))?;
        
        // 检查权限
        let app_state = parts.extensions.get::<AppState>()
            .ok_or(AppError::InternalServerError("应用状态未找到".to_string()))?;
        
        let has_permission = permission_service::check_user_permission(
            &app_state.db,
            &current_user.id,
            &permission_req.resource,
            &permission_req.action,
        ).await
        .map_err(|e| AppError::InternalServerError(e.to_string()))?;
        
        if !has_permission {
            return Err(AppError::Forbidden("权限不足".to_string()));
        }
        
        Ok(PermissionGuard { current_user })
    }
}

请求日志中间件

pub struct RequestLogMiddleware;

impl<S> Layer<S> for RequestLogMiddleware {
    type Service = RequestLogService<S>;
    
    fn layer(&self, inner: S) -> Self::Service {
        RequestLogService { inner }
    }
}

pub struct RequestLogService<S> {
    inner: S,
}

impl<S> Service<Request<Body>> for RequestLogService<S>
where
    S: Service<Request<Body>, Response = Response> + Clone + Send + 'static,
    S::Future: Send + 'static,
{
    type Response = S::Response;
    type Error = S::Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
    
    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.inner.poll_ready(cx)
    }
    
    fn call(&mut self, request: Request<Body>) -> Self::Future {
        let start_time = Instant::now();
        let method = request.method().clone();
        let uri = request.uri().clone();
        let user_agent = request.headers()
            .get(USER_AGENT)
            .and_then(|h| h.to_str().ok())
            .unwrap_or("")
            .to_string();
        
        let future = self.inner.call(request);
        
        Box::pin(async move {
            let response = future.await?;
            let duration = start_time.elapsed();
            
            info!(
                target = "udmin",
                method = %method,
                uri = %uri,
                status = %response.status(),
                duration_ms = %duration.as_millis(),
                user_agent = %user_agent,
                "http.request.completed"
            );
            
            Ok(response)
        })
    }
}

API 文档

OpenAPI 集成

use utoipa::{OpenApi, ToSchema};
use utoipa_swagger_ui::SwaggerUi;

#[derive(OpenApi)]
#[openapi(
    paths(
        auth::login,
        auth::logout,
        user::list_users,
        user::create_user,
        flow::execute_flow,
    ),
    components(
        schemas(
            LoginReq,
            LoginResp,
            UserDoc,
            CreateUserReq,
            ExecuteFlowReq,
            ExecutionResult,
        )
    ),
    tags(
        (name = "auth", description = "认证相关接口"),
        (name = "user", description = "用户管理接口"),
        (name = "flow", description = "流程管理接口"),
    )
)]
struct ApiDoc;

pub fn create_swagger_routes() -> Router {
    Router::new()
        .merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", ApiDoc::openapi()))
}

接口文档注解

#[utoipa::path(
    post,
    path = "/auth/login",
    tag = "auth",
    summary = "用户登录",
    description = "用户名密码登录,返回 JWT Token",
    request_body = LoginReq,
    responses(
        (status = 200, description = "登录成功", body = ApiResponse<LoginResp>),
        (status = 400, description = "请求参数错误", body = ApiResponse<()>),
        (status = 401, description = "用户名或密码错误", body = ApiResponse<()>),
    )
)]
pub async fn login(
    State(app_state): State<AppState>,
    Json(req): Json<LoginReq>,
) -> Result<Json<ApiResponse<LoginResp>>, AppError> {
    // 实现代码...
}

性能优化

请求缓存

pub struct CacheMiddleware {
    redis: RedisConnection,
    ttl: Duration,
}

impl CacheMiddleware {
    pub fn new(redis: RedisConnection, ttl: Duration) -> Self {
        Self { redis, ttl }
    }
    
    async fn get_cache_key(&self, request: &Request<Body>) -> String {
        let method = request.method();
        let uri = request.uri();
        let query = uri.query().unwrap_or("");
        format!("api_cache:{}:{}:{}", method, uri.path(), query)
    }
}

响应压缩

pub fn create_compression_layer() -> CompressionLayer {
    CompressionLayer::new()
        .gzip(true)
        .br(true)
        .deflate(true)
        .quality(CompressionLevel::Default)
}

请求限流

pub struct RateLimitMiddleware {
    redis: RedisConnection,
    max_requests: u32,
    window: Duration,
}

impl RateLimitMiddleware {
    pub async fn check_rate_limit(
        &self,
        client_id: &str,
    ) -> Result<bool, AppError> {
        let key = format!("rate_limit:{}", client_id);
        let current_count: u32 = self.redis.get(&key).await.unwrap_or(0);
        
        if current_count >= self.max_requests {
            return Ok(false);
        }
        
        let _: () = self.redis.incr(&key, 1).await?;
        let _: () = self.redis.expire(&key, self.window.as_secs() as usize).await?;
        
        Ok(true)
    }
}

测试策略

单元测试

#[cfg(test)]
mod tests {
    use super::*;
    use axum_test::TestServer;
    
    #[tokio::test]
    async fn test_login_success() {
        let app = create_test_app().await;
        let server = TestServer::new(app).unwrap();
        
        let response = server
            .post("/auth/login")
            .json(&json!({
                "username": "admin",
                "password": "password123"
            }))
            .await;
        
        response.assert_status_ok();
        
        let body: ApiResponse<LoginResp> = response.json();
        assert!(body.success);
        assert!(body.data.is_some());
    }
    
    #[tokio::test]
    async fn test_login_invalid_credentials() {
        let app = create_test_app().await;
        let server = TestServer::new(app).unwrap();
        
        let response = server
            .post("/auth/login")
            .json(&json!({
                "username": "admin",
                "password": "wrong_password"
            }))
            .await;
        
        response.assert_status(StatusCode::UNAUTHORIZED);
    }
}

集成测试

#[tokio::test]
async fn test_user_crud_flow() {
    let app = create_test_app().await;
    let server = TestServer::new(app).unwrap();
    
    // 登录获取 Token
    let login_response = server
        .post("/auth/login")
        .json(&json!({
            "username": "admin",
            "password": "password123"
        }))
        .await;
    
    let login_body: ApiResponse<LoginResp> = login_response.json();
    let token = login_body.data.unwrap().token;
    
    // 创建用户
    let create_response = server
        .post("/api/users")
        .add_header(AUTHORIZATION, format!("Bearer {}", token))
        .json(&json!({
            "username": "test_user",
            "password": "password123",
            "email": "test@example.com"
        }))
        .await;
    
    create_response.assert_status_ok();
    
    let create_body: ApiResponse<UserDoc> = create_response.json();
    let user_id = create_body.data.unwrap().id;
    
    // 获取用户
    let get_response = server
        .get(&format!("/api/users/{}", user_id))
        .add_header(AUTHORIZATION, format!("Bearer {}", token))
        .await;
    
    get_response.assert_status_ok();
    
    // 删除用户
    let delete_response = server
        .delete(&format!("/api/users/{}", user_id))
        .add_header(AUTHORIZATION, format!("Bearer {}", token))
        .await;
    
    delete_response.assert_status_ok();
}

最佳实践

路由设计

  • RESTful 风格: 遵循 REST API 设计原则
  • 资源命名: 使用复数名词表示资源
  • HTTP 方法: 正确使用 GET、POST、PUT、DELETE
  • 状态码: 返回合适的 HTTP 状态码

参数验证

  • 输入验证: 使用 validator 进行参数验证
  • 类型安全: 使用强类型结构体
  • 错误信息: 提供清晰的验证错误信息
  • 安全过滤: 过滤恶意输入

错误处理

  • 统一格式: 使用统一的错误响应格式
  • 错误分类: 合理分类不同类型的错误
  • 日志记录: 记录详细的错误日志
  • 用户友好: 提供用户友好的错误信息

安全考虑

  • 认证授权: 实现完善的认证授权机制
  • 输入验证: 严格验证所有输入参数
  • HTTPS: 在生产环境使用 HTTPS
  • CORS: 正确配置 CORS 策略