前后端联调时最耗时间的环节是什么?不是写业务逻辑,而是反复对接接口——新增一个字段要改后端代码、重新部署、通知前端、再联调。腾讯开源的 APIJSON 用一种截然不同的思路解决这个问题:后端只配置权限和表结构,前端通过 JSON 本身描述要查什么、怎么查,后端全自动执行并返回结果。8 年多迭代到 8.1.8,这次带来了两个实用特性:容量预估和 Rust 版本。
一个请求说明一切
传统方式查一个用户及其关联的评论列表,需要两个接口或一个手写联表 SQL。用 APIJSON,前端直接发一条 JSON:
{
"User": {
"id": 1
},
"Comment[]": {
"Comment": {
"userId": "/User/id"
}
}
}
后端解析这段 JSON,自动生成 SQL、执行查询、组装结果,返回:
{
"User": { "id": 1, "name": "张三", "age": 28 },
"Comment[]": [
{ "id": 101, "content": "不错", "userId": 1 },
{ "id": 102, "content": "再来看看", "userId": 1 }
]
}
/User/id 这种路径引用是 APIJSON 协议的核心语法——前端用 JSON 的键路径表达关联关系,后端自动解析成 JOIN 或子查询。增删改同理,JSON 结构即请求体,不需要写任何 Controller 或 SQL。
容量预估:上线前先算清楚
8.1.8 新增的容量预估功能,解决的是一个上线前经常被忽略的问题:这张表未来一年会占多少存储?查询性能会不会崩?
APIJSON 根据表结构定义(字段类型、索引)和业务增长参数,给出预估结果。在 Spring Boot 项目中可以这样调用:
// 在 APIJSON 配置完成后,通过预估接口查询
JSONObject request = new JSONObject();
request.put("Method", "预估");
request.put("Table", "Order");
request.put("avgRowLength", 256); // 平均行大小(字节)
request.put("dailyGrowth", 50000); // 日增行数
request.put("months", 12); // 预估月数
JSONObject response = apijsonController.post(request);
// 返回结果包含预估总行数、存储占用、索引大小等
System.out.println(response);
也可以直接通过 HTTP 请求:
curl -X POST http://localhost:8080/apijson/预估 \
-H "Content-Type: application/json" \
-d '{
"Table": "Order",
"avgRowLength": 256,
"dailyGrowth": 50000,
"months": 12
}'
返回结果会包含总行数预估、磁盘占用、是否建议分表等建议。这对中小团队做技术方案评审时尤其实用——不用再靠经验拍脑袋,有数据支撑。
Rust 版:性能敏感场景的新选择
APIJSON 原本是 Java 实现,依赖 Spring Boot 运行。对于高并发、低延迟的微服务网关或边缘计算场景,Java 的启动时间和内存开销有时不可接受。8.1.8 同步推出的 Rust 版,把协议解析和 SQL 生成核心用 Rust 重写,适合作为轻量 API 网关嵌入。
一个最小化的 Rust 版启动示例:
// Cargo.toml 中添加依赖
// apijson-rust = "0.1"
use apijson_rust::{Router, parse_request};
fn main() {
let router = Router::new()
.add_table("User", "user_table") // 注册表名映射
.add_table("Comment", "comment_table")
.set_secret("your_secret_key"); // 配置鉴权密钥
// 模拟接收前端 JSON 请求
let json_req = r#"{
"User": { "id": 1 },
"Comment[]": {
"Comment": { "userId": "/User/id" }
}
}"#;
let result = parse_request(json_req, &router).unwrap();
println!("生成的 SQL: {}", result.sql);
println!("返回的 JSON: {}", result.response_json);
}
Rust 版目前覆盖了查询(GET)和部分写入(POST)的协议解析,权限校验逻辑与 Java 版一致。如果你的服务已经在用 Rust 做网关层,可以直接把 APIJSON Rust 版作为中间件嵌入,避免再起一个 Java 服务。
实际接入:五分钟跑起来
以最常见的 Java + Spring Boot 接入为例,步骤非常短:
第一步:添加依赖
<!-- pom.xml -->
<dependency>
<groupId>com.github.tencent</groupId>
<artifactId>apijson-framework</artifactId>
<version>8.1.8</version>
</dependency>
第二步:配置数据源和权限
@Configuration
public class APIJSONConfig {
@Bean
public Function<Long, JSONObject> currentUserProvider() {
// 从你的鉴权体系获取当前用户信息
return id -> queryUserById(id);
}
@Bean
public APIJSONController apijsonController(DataSource ds) {
return new APIJSONController(ds);
}
}
第三步:声明表结构权限
// 在 Model 子类中声明哪些字段可查、可写
@MethodAccess(GET = {LOGIN, ADMIN}, POST = {ADMIN})
public class User extends BaseModel {
@ColumnComment("用户名")
@ColumnAccess(GET = {ALL}, PUT = {OWNER, ADMIN})
private String name;
@ColumnComment("年龄")
private Integer age;
}
@MethodAccess 控制整表操作权限,@ColumnAccess 控制字段级权限。LOGIN 表示已登录可访问,OWNER 表示只有记录所有者可改,ADMIN 是管理员。这套声明式权限模型是 APIJSON 安全体系的核心——前端能查什么、改什么,全由注解决定,不需要手写鉴权逻辑。
第四步:前端直接请求
# 查询用户及其评论
curl http://localhost:8080/apijson/get \
-d '{"User":{"id":1},"Comment[]":{"Comment":{"userId":"/User/id"}}}'
没有 Controller,没有 Service,没有 Mapper。后端只做了两件事:配权限、声明表结构。
什么时候该用,什么时候不该用
适合的场景:
- 中小型项目,接口数量多但复杂度不高(管理系统、内部工具、数据看板)
- 前端团队强、后端人少,希望前端自主组合数据减少联调
- 快速原型阶段,接口频繁变更
需要谨慎的场景:
- 涉及复杂事务(多表一致性写入),APIJSON 的批量写入支持有限
- 对 SQL 有极致优化需求(特定索引策略、复杂分页算法),自动生成的 SQL 不如手写可控
- 高安全要求的金融场景,动态 JSON 查询的攻击面比固定接口更大
接入前的检查清单:
- 确认数据库表有明确的主键和外键关系——APIJSON 的关联引用依赖这些
- 先在测试环境跑通权限配置,确保
@MethodAccess覆盖了所有表的访问边界 - 用容量预估功能评估核心表的增长趋势,提前规划分表或索引
- 如果部署环境对延迟敏感,评估 Rust 版是否更适合
APIJSON 不是万能银弹,但它确实把"写接口"这件事的边际成本压到了接近零。对于大量 CRUD 型需求的项目,省下来的联调时间足够让团队多做几轮功能迭代。8.1.8 的容量预估让上线更有底气,Rust 版让部署更轻——这两个方向都指向同一个目标:让 API 开发这件事越来越不需要"开发"。