统一错误结构
本课属于 Coddy Node.js 学习旅程的“REST API”单元。第 12 课,共 25 课。
你的 API 现在会以两种格式返回错误:404 错误返回字符串,400 错误返回 zod 的对象。客户端必须分别处理这两种格式。为所有错误统一使用一种格式:
{ "error": { "code": "not_found", "message": "Invoice not found" } }
{ "error": { "code": "invalid_body", "message": "Too small: ...",
"fields": { "amount": ["Too small: expected number to be >0"] } } }code 面向程序:它永远不会改变,因此客户端可以对它进行比较。message 面向人,它的措辞可能会改变。fields 会告诉表单要标记哪个输入项。把这种格式写在一个函数中,并在每个路由中调用它,这样所有路由的格式都一致:
sendError(res, 404, 'not_found', 'Invoice not found');挑战
简单你的 API 现在会以两种格式发送错误:404 错误使用普通字符串,400 错误使用 zod 对象。让所有错误都使用相同的格式,这样客户端就能用同一种方式读取它们。从现在起,所有错误都采用以下格式,只有在有内容可列出时才添加 fields:
{ "error": { "code": "not_found", "message": "Task not found" } }- 在
errors.js中,完成sendError(res, status, code, message, fields)。它会使用给定的状态码和上述格式发送响应。只有在传入了fields参数时,才将它添加到内部对象中。下面的sendInvalid已经写好,会调用你的函数。 - 在
routes/tasks.js中,导入这两个辅助函数:- 将四个 404 响应(针对单个任务的 GET、PATCH、PUT 和 DELETE)替换为
sendError,使用代码not_found和消息Task not found。 - 将三个针对错误请求体的 400 响应(POST、PATCH 和 PUT)替换为
sendInvalid(res, result.error)。
错误的请求体会显示如下内容(消息由 zod 生成):
{ "error": { "code": "invalid_body", "message": "Invalid input: expected string, received number", "fields": { "title": ["Invalid input: expected string, received number"] } } } - 将四个 404 响应(针对单个任务的 GET、PATCH、PUT 和 DELETE)替换为
- 在
server.js中,导入sendError,并在底部的错误处理程序中使用它:- 无效的 JSON 请求体会返回状态码 400、代码
invalid_json和消息The body is not valid JSON。 - 其他错误会返回状态码 500、代码
server_error和消息Something went wrong。
- 无效的 JSON 请求体会返回状态码 400、代码
试试看:DELETE /api/tasks/99 会返回 404,内容为 { "error": { "code": "not_found", "message": "Task not found" } },且不包含 fields。向 /api/tasks 发送 POST 请求,内容为 { "title": 123 }:你会收到 400 响应,内容为上面的 invalid_body 错误。请求栏会拒绝发送格式错误的 JSON,因此检查会替你测试 invalid_json 情况。
亲手试试
import { z } from 'zod';
// 将所有错误按统一格式发送:
// { "error": { "code": "not_found", "message": "Task not found" } }
// 只有提供了 "fields" 时才添加它。
export const sendError = (res, status, code, message, fields) => {
// 在这里发送响应
};
// 将 zod 错误作为 400 错误发送:第一个问题作为消息,各字段的
// 问题放在 fields 中。
export const sendInvalid = (res, zodError) =>
sendError(res, 400, 'invalid_body', zodError.issues[0].message, z.flattenError(zodError).fieldErrors);
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
REST API中的所有课
自己练习: Express 在线编辑器