Rust 迎来零代码 APIJSON 实现:用声明式 JSON 统一接口、查询与文档

2026-07-13 37 预计阅读时间: 1 分钟
来源: oschina.net AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

腾讯 APIJSON 生态出现了首个面向 Rust 的零代码接口与文档开源项目。它试图解决一个长期存在的问题:业务表和查询条件频繁变化时,后端不必为每个列表、详情和增删改查需求重复编写 Controller、Service、DAO 以及配套接口文档。

APIJSON 既是一套面向 API 的 JSON 网络传输协议,也包含依据协议实现的 ORM 能力。客户端通过结构化 JSON 描述查询目标,服务端完成解析、权限检查、数据库访问和结果组装。对于需求变化快、采用前后端分离架构的中小型项目,这种模式有机会显著压缩接口开发和沟通成本。

零代码省掉的不是所有代码

传统 REST 接口通常按资源和场景拆分端点。例如,一个订单页面可能陆续需要:

  • 查询订单及用户信息;
  • 按状态、时间和金额筛选;
  • 增加分页、排序与聚合字段;
  • 为移动端返回稍有不同的数据结构。

常规做法会不断增加 DTO、查询方法和接口文档。APIJSON 则把一部分变化转移到请求 JSON 中,使客户端声明需要哪些表、字段、关联关系和过滤条件。后端保留统一入口,通过协议解释请求。

这里的“零代码”主要指常见 CRUD 接口无需逐个手写,并不意味着系统不再需要工程代码。数据库模型、访问权限、字段暴露规则、事务、审计、限流和复杂业务动作仍然需要明确配置或实现。支付、库存扣减、审批流等带有业务不变量的操作,也不适合被简单数据库写入取代。

Rust 实现带来的工程价值

Rust 适合构建长期运行的网络服务:它强调内存安全、明确的错误处理和可控的运行时成本。将 APIJSON 的协议解析、ORM、接口服务及文档能力带入 Rust 生态,意味着团队可以在 Rust 服务中采用统一的声明式数据接口,而不必额外维护另一种语言编写的网关。

更值得关注的是边界处理。一个 APIJSON 服务不能只是把任意 JSON 拼成 SQL。可靠实现至少要覆盖:

  • 将字段名、表名、操作符映射到受控的元数据,而不是直接拼接字符串;
  • 使用参数化查询处理外部输入;
  • 限制可访问的表、列、关联层数、分页大小和排序字段;
  • 在执行前完成身份认证、行级权限及字段级权限判断;
  • 为查询耗时、扫描行数、错误类型和调用方建立可观测性。

Rust 的类型系统能帮助实现者约束解析后的请求结构,但类型安全不能自动解决越权查询和昂贵查询。协议层仍需建立独立的安全策略。

可以这样实践:先验证统一查询入口

下面是一个可直接改造的 HTTP 调用示例。由于来源摘要没有给出该 Rust 项目的具体路由、表结构和启动参数,这里假设服务监听 http://127.0.0.1:8080,查询入口为 /get,数据库中存在 User 表。运行前请按照实际项目修改地址、鉴权头、表名和字段名。

curl --fail-with-body \
  -X POST 'http://127.0.0.1:8080/get' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer replace-with-your-token' \
  -d '{
    "User": {
      "id": 1001,
      "@column": "id,name,createdAt"
    }
  }'

列表查询可以把分页和排序也放进声明中。以下结构采用 APIJSON 常见的对象数组表达方式,但具体操作符应以该 Rust 项目的实现文档为准:

curl --fail-with-body \
  -X POST 'http://127.0.0.1:8080/get' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer replace-with-your-token' \
  -d '{
    "User[]": {
      "count": 20,
      "page": 0,
      "User": {
        "status": "ACTIVE",
        "@column": "id,name,status,createdAt",
        "@order": "createdAt-"
      }
    }
  }'

验证时不要只看能否返回数据,还应检查生成 SQL、查询计划和权限行为。可以准备三个测试账号,分别拥有管理员、普通用户和匿名权限,然后用同一请求确认返回字段与数据行是否正确收敛。

接入现有 Rust 服务时的安全外壳

如果项目需要在 APIJSON 服务前增加统一鉴权,可以这样实践。下面是一个基于 Axum 的最小代理示例,假设上游 APIJSON 服务运行在 127.0.0.1:8080。它只演示令牌检查和请求转发,生产环境还需加入超时、限流、请求体大小限制和结构化日志。

将以下依赖加入 Cargo.toml

[package]
name = "apijson-gateway"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.7"
reqwest = { version = "0.12", features = ["json"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }

再创建 src/main.rs

use axum::{
    extract::Json,
    http::{HeaderMap, StatusCode},
    routing::post,
    Router,
};
use serde_json::Value;

async fn query(
    headers: HeaderMap,
    Json(payload): Json<Value>,
) -> Result<Json<Value>, (StatusCode, String)> {
    let token = headers
        .get("authorization")
        .and_then(|value| value.to_str().ok());

    if token != Some("Bearer local-demo-token") {
        return Err((StatusCode::UNAUTHORIZED, "invalid token".into()));
    }

    let response = reqwest::Client::new()
        .post("http://127.0.0.1:8080/get")
        .json(&payload)
        .send()
        .await
        .map_err(|error| (StatusCode::BAD_GATEWAY, error.to_string()))?;

    let status = response.status();
    let body = response
        .json::<Value>()
        .await
        .map_err(|error| (StatusCode::BAD_GATEWAY, error.to_string()))?;

    if !status.is_success() {
        return Err((StatusCode::BAD_GATEWAY, body.to_string()));
    }

    Ok(Json(body))
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/api/query", post(query));
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    axum::serve(listener, app).await.unwrap();
}

运行并调用代理:

cargo run

curl --fail-with-body \
  -X POST 'http://127.0.0.1:3000/api/query' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer local-demo-token' \
  -d '{"User":{"id":1001}}'

这个代理不是完整的权限系统,但它展示了一个重要原则:即使 CRUD 由协议自动生成,身份、租户和安全策略仍应位于可信的服务端边界内。

采用前先做一轮约束测试

APIJSON 最适合数据模型相对清晰、查询变化频繁、业务动作较轻的系统,例如内部管理台、内容后台和中小型前后端分离项目。对于强事务、复杂领域规则或对接口形态有严格长期兼容要求的系统,可以把它用于查询和常规维护接口,同时保留显式编写的领域服务。

正式接入前,建议完成以下检查:

  • 确认 Rust 实现支持当前数据库、事务模式和必要的 APIJSON 操作符;
  • 建立表、字段、关联、排序和聚合函数的白名单;
  • 为分页上限、查询深度、执行时间和返回体大小设置硬限制;
  • 验证行级、列级及多租户隔离,特别关注批量更新和删除;
  • 将自动文档纳入版本管理,检查协议升级时的兼容性;
  • 对高频查询执行压测,并审查数据库执行计划;
  • 为复杂业务命令保留专用端点,不把所有行为都降格为 CRUD。

Rust 项目让 APIJSON 的零代码接口模式进入了新的技术栈,但真正决定它能否落地的不是“少写了多少 Controller”,而是团队能否把自动化能力放进严格的权限、资源和业务边界之内。


相关推荐