@zenweb/result
v5.5.0
Published
Zenweb Result module
Readme
@zenweb/result
Zenweb 结果处理模块,统一控制器返回结果,默认 JSON 格式输出。
安装
npm install @zenweb/result快速开始
import { Core } from '@zenweb/core';
import modInject from '@zenweb/inject';
import modResult from '@zenweb/result';
const app = new Core();
app.setup(modInject());
app.setup(modResult());功能说明
成功结果
控制器返回值自动包装为 JSON:
@Controller()
class UserController {
@Get('/user')
getUser() {
return { name: '张三', age: 25 };
// 输出: { "data": { "name": "张三", "age": 25 } }
}
}业务错误
使用 fail() 抛出预知的业务错误(参数校验失败、权限不足等),立即终止执行:
import { fail } from '@zenweb/result';
@Controller()
class UserController {
@Get('/user/:id')
getUser(ctx: Context) {
const id = Number(ctx.params.id);
if (!id || id <= 0) {
fail(400, '用户ID无效');
}
return { name: '张三' };
}
}fail() 调用后代码立即终止,后续代码不会执行。
意外错误
代码异常(如数据库连接失败、空指针)直接抛出 Error,框架自动处理:
@Controller()
class UserController {
@Get('/user/:id')
async getUser(ctx: Context) {
const user = await db.query('SELECT * FROM users WHERE id = ?', [ctx.params.id]);
if (!user) {
throw new Error('数据库查询失败'); // 意外错误,框架统一处理
}
return user;
}
}非生产环境下(或设置 EXPOSE_UNEXPECTED=1),意外错误的 message、stack 等信息会一并输出,便于排查;生产环境仅返回通用 500 错误。
Stream / Buffer 输出
返回 Stream 或 Buffer 时跳过渲染器和包装逻辑,直接写入 ctx.body,适合文件下载、二进制内容:
@Controller()
class ExportController {
@Get('/download')
download() {
return fs.createReadStream('/path/to/file');
// 或 return Buffer.from('...');
}
}字段筛选 x-result-pick
客户端通过请求头 x-result-pick 指定需要返回的字段,服务端按需裁剪结果,减少网络流量。
- 多个字段用
,分隔 - 嵌套字段用
.路径 - 同层多字段用
&分隔 - 支持数组结构
GET /user
x-result-pick: a,b.c.d&e// 原始数据: { a: 1, b: { c: { d: 2, e: 3, f: 4 } } }
// 返回: { a: 1, b: { c: { d: 2, e: 3 } } }可在配置中关闭:allowResultPick: false。
配置选项
| 配置项 | 默认值 | 说明 |
|-------|-------|------|
| failCode | - | 默认失败代码 |
| failCodeHeader | true ('X-Fail-Code') | 失败代码输出到响应头 |
| failMessage | 'request fail' | 默认失败消息 |
| failStatus | 422 | 默认失败 HTTP 状态码 |
| successWrap | (ctx, data) => ({ data }) | 成功结果包装函数 |
| failWrap | (ctx, err) => ({ code, data, message, ...extra }) | 错误结果包装函数 |
| exposeUnexpected | 开发环境自动开启 | 暴露意外错误详情 |
| unexpectedStatus | 500 | 意外错误 HTTP 状态码 |
| unexpectedCode | 500 | 意外错误代码 |
| renders | - | 自定义渲染器类列表 |
自定义输出格式
app.setup(modResult({
successWrap: (ctx, data) => ({ success: true, data }),
failWrap: (ctx, err) => ({ success: false, error: { code: err.code, message: err.message } }),
}));输出效果:
// 成功
{ "success": true, "data": { "name": "张三" } }
// 失败
{ "success": false, "error": { "code": 400, "message": "用户ID无效" } }API
fail() - 业务错误
fail('错误消息');
fail(400, '参数错误');
fail(400, '参数错误', { field: 'email' }); // 附加数据
fail({ code: 123, message: '自定义', status: 200, data: { id: 1 } });ctx.success() - 手动输出
@Controller()
class UserController {
@Get('/export')
async export(ctx: Context) {
const data = await generateReport();
await ctx.success(data); // 等待输出完成
await sendNotification(); // 输出后继续执行
}
}自定义渲染器
支持根据请求类型自动选择输出格式:
import { Injectable } from '@zenweb/inject';
import { Context } from '@zenweb/core';
import { ResultRender } from '@zenweb/result';
@Injectable('singleton')
class XMLRender implements ResultRender {
enwrap = false; // 不包装,直接输出
type = 'xml';
match(ctx: Context) {
return ctx.accepts('xml') === 'xml';
}
render(ctx: Context, data: unknown) {
return toXML(data);
}
}
app.setup(modResult({ renders: [XMLRender] }));匹配顺序:自定义渲染器按数组顺序依次匹配(越靠前越优先),JSONRender 始终作为最终兜底。
依赖
@zenweb/core@zenweb/inject
