外观
API 设计规范
本文档介绍 API 设计规范、请求验证和响应格式。
路由命名
- RESTful 风格
- 使用复数形式:
/users、/articles - 嵌套资源:
/users/:userId/articles
请求验证
使用 Zod 进行参数验证(定义 Schema 时的命名应为以小写字母 s 开头的小驼峰写法):
typescript
// 定义验证 Schema
export const sCreateUser = zod.object({
username: zod.string().min(3),
email: zod.string().email(),
});
// 在路由中使用
router.post(
"/users",
bodyValidateMiddleware({ body: sCreateUser }),
cCreateUser,
);1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
响应格式
通过 ResponseMiddleware 中间件在 express 上集成了 res.success、res.successPage 和 res.fail 方法用来处理常规的 JSON 响应。
成功响应
typescript
// 标准响应
{
code: 200,
message: "success",
encrypted: false,
timestamp: 1762409800783,
data: { ... }
}
// 分页响应
{
code: 200,
message: "success",
encrypted: false,
timestamp: 1762409800783,
data: {
list: [...],
total: 100,
pageNo: 1,
pageSize: 20
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
错误响应
typescript
{
code: 500,
message: "错误信息",
encrypted: false,
timestamp: 1762409800783,
data: null
}1
2
3
4
5
6
7
2
3
4
5
6
7
代码中使用
typescript
// 成功响应
res.success(data);
// 分页响应
res.successPage({ list, total, pageNo, pageSize });
// 失败响应
res.fail(message, statusCode);1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
中间件使用
身份验证
typescript
router.use(userMiddleware()); // 获取用户信息
router.use(authMiddleware()); // 验证用户登录状态1
2
2
参数验证
typescript
router.post(
"/api/endpoint",
bodyValidateMiddleware({
body: schema, // 验证请求体
query: schema, // 验证查询参数
params: schema, // 验证路径参数
}),
controller,
);1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
错误处理
服务层错误处理
使用 TReturn<T> 类型表示可能返回错误的函数:
typescript
type TReturn<T> = [Error | null, T | undefined];
export async function getUserBalance(
userId: number,
): Promise<TReturn<{ balance: number }>> {
try {
// 业务逻辑
return [null, { balance: 100 }];
} catch (err) {
return [getError(err), undefined];
}
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
控制器错误处理
注意:控制器函数名应为以字符c开头的小驼峰写法。
typescript
export const cGetBalance: ExpressRequestHandler = async (req, res, next) => {
try {
const [err, data] = await getUserBalance(user.id);
if (err) {
res.fail(err.message);
return;
}
res.success(data);
} catch (err) {
logger.error("error in cGetBalance", err);
next(err); // 交给错误处理中间件
}
};1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13