anycms-core 0.5.4

A unified API response library supporting multiple Rust web frameworks
Documentation
use actix_web::{App, HttpServer, Responder, get, post, web};
use anycms_core::{ApiResult, ResultPagination};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct User {
    id: u32,
    name: String,
    email: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct CreateUserRequest {
    name: String,
    email: String,
}

// 模拟用户数据
async fn get_users() -> Vec<User> {
    vec![
        User {
            id: 1,
            name: "张三".to_string(),
            email: "zhangsan@example.com".to_string(),
        },
        User {
            id: 2,
            name: "李四".to_string(),
            email: "lisi@example.com".to_string(),
        },
        User {
            id: 3,
            name: "王五".to_string(),
            email: "wangwu@example.com".to_string(),
        },
    ]
}

// 获取单个用户
async fn get_user_by_id(id: u32) -> Option<User> {
    let users = get_users().await;
    users.into_iter().find(|u| u.id == id)
}

#[get("/")]
async fn index() -> ApiResult<()> {
    ApiResult::ok()
}

#[get("/users")]
async fn list_users() -> impl Responder {
    let users = get_users().await;
    let pagination = ResultPagination::new(100, 1, 10);

    ApiResult::list(users)
        .with_pagination(pagination)
        .with_extra("total_count", serde_json::json!(100))
        .with_extra("has_more", serde_json::json!(true))
}

#[get("/users/{id}")]
async fn get_user(path: web::Path<u32>) -> impl Responder {
    let user_id = path.into_inner();

    match get_user_by_id(user_id).await {
        Some(user) => ApiResult::value(user),
        None => {
            let result = ApiResult::<User>::fail("用户不存在");
            result
        }
    }
}

#[post("/users")]
async fn create_user(user_data: web::Json<CreateUserRequest>) -> impl Responder {
    // 模拟创建用户
    let new_user = User {
        id: 999,
        name: user_data.name.clone(),
        email: user_data.email.clone(),
    };

    ApiResult::value(new_user)
        .with_extra("created_at", serde_json::json!("2024-01-01T00:00:00Z"))
        .with_extra("status", serde_json::json!("active"))
}

#[get("/error")]
async fn error_demo() -> ApiResult<()> {
    ApiResult::fail("这是一个错误示例")
}

#[get("/error-with-code")]
async fn error_with_code_demo() -> ApiResult<()> {
    ApiResult::fail("这是一个带错误码的示例").with_code(400)
}

// ========== 使用 ApiResult<impl Responder> 的示例 ==========

#[get("/default/users/{id}")]
async fn get_user_default(path: web::Path<u32>) -> ApiResult<User> {
    let user_id = path.into_inner();

    match get_user_by_id(user_id).await {
        Some(user) => ApiResult::value(user),
        None => ApiResult::<User>::fail("用户不存在").with_code(404),
    }
}

#[post("/default/users")]
async fn create_user_default(
    user_data: web::Json<CreateUserRequest>,
) -> ApiResult<User> {
    // 模拟验证逻辑
    if user_data.name.is_empty() {
        return ApiResult::<User>::fail("用户名不能为空").with_code(400);
    }

    if !user_data.email.contains('@') {
        return ApiResult::<User>::fail("邮箱格式不正确").with_code(400);
    }

    // 模拟创建用户
    let new_user = User {
        id: 999,
        name: user_data.name.clone(),
        email: user_data.email.clone(),
    };

    ApiResult::value(new_user)
        .with_message("用户创建成功")
        .with_extra("created_at", serde_json::json!("2024-01-01T00:00:00Z"))
        .with_extra("status", serde_json::json!("active"))
}

#[get("/default/health")]
async fn health_check_default() -> ApiResult<()> {
    ApiResult::<()>::ok()
        .with_message("服务运行正常")
        .with_extra("timestamp", serde_json::json!("2024-01-17T10:30:00Z"))
        .with_extra("version", serde_json::json!("1.0.0"))
}

#[get("/default/users/{id}/profile")]
async fn get_user_profile_default(path: web::Path<u32>) -> ApiResult<serde_json::Value> {
    let user_id = path.into_inner();

    match get_user_by_id(user_id).await {
        Some(user) => {
            // 模拟构建用户详细信息
            let profile = serde_json::json!({
                "user": user,
                "role": "admin",
                "permissions": ["read", "write", "delete"],
                "last_login": "2024-01-15T10:30:00Z"
            });

            ApiResult::value(profile)
                .with_extra("cache_ttl", serde_json::json!(3600))
                .with_extra("is_cached", serde_json::json!(false))
        }
        None => ApiResult::<serde_json::Value>::fail("用户不存在")
            .with_code(404)
            .with_extra("user_id", serde_json::json!(user_id)),
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    println!("启动 anycms-core 演示服务器...");
    println!("访问以下端点来测试不同的 API 响应:");
    println!("  GET  /              - 基本成功响应");
    println!("  GET  /users         - 用户列表(带分页和额外信息)");
    println!("  GET  /users/1       - 获取单个用户");
    println!("  GET  /users/999     - 不存在的用户(错误响应)");
    println!("  POST /users         - 创建用户(需要 JSON body)");
    println!("  GET  /error         - 基本错误响应");
    println!("  GET  /error-with-code - 带错误码的错误响应");
    println!();
    println!("使用 ApiResult<T> 的端点:");
    println!("  GET  /default/users/1 - 获取用户");
    println!("  GET  /default/users/999 - 不存在的用户(错误示例)");
    println!("  POST /default/users - 创建用户(带验证)");
    println!("  GET  /default/health - 健康检查(带额外元数据)");
    println!("  GET  /default/users/1/profile - 获取用户详细资料");
    println!();
    println!("示例 POST 请求:");
    println!("curl -X POST http://localhost:8080/default/users \\");
    println!("  -H \"Content-Type: application/json\" \\");
    println!("  -d '{{\"name\":\"测试用户\",\"email\":\"test@example.com\"}}'");

    HttpServer::new(|| {
        App::new()
            .service(index)
            .service(list_users)
            .service(get_user)
            .service(create_user)
            .service(error_demo)
            .service(error_with_code_demo)
            // ApiResult 示例路由
            .service(get_user_default)
            .service(create_user_default)
            .service(health_check_default)
            .service(get_user_profile_default)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await?;

    Ok(())
}