Closed Gn3po4g closed 5 months ago
哈喽!
这个功能(大概)已经有啦,在这里:失败处理
每一个失败码都会返回不同的消息,你也可以通过为失败码添加参数,来使主动抛出失败的时候,动态返回不同的消息
Milkio 遵循约定大于配置的原则,当你想修改类型不正确时的返回的文案,编辑 /src/fail-code.ts
文件就好啦
默认情况下返回的 message,确实容易让人感到迷惑,以为是报错,未来这方面我会优化一下下~
哈喽!
这个功能(大概)已经有啦,在这里:失败处理
每一个失败码都会返回不同的消息,你也可以通过为失败码添加参数,来使主动抛出失败的时候,动态返回不同的消息
Milkio 遵循约定大于配置的原则,当你想修改类型不正确时的返回的文案,编辑
/src/fail-code.ts
文件就好啦
是的,但是默认是系统自己处理返回的TYPE_SAFE_ERROR,希望在这部分能有更多自定义的内容。
比如说怎么自定义哇?编辑 /src/fail-code.ts
文件有哪些需求不能满足哇?
type(string | typia.tags.MaxLength<2>).with_message("参数不满足要求") 类似这样的功能?
这确实是个问题!Typia 还没有这样的功能,目前,我想到了这样的解决方案:
/src/fail-code.ts
其实返回的 message 是个方法,因此,你可以控制它的逻辑:
import type { MilkioFailCode } from "milkio";
export const failCode = {
...
TYPE_SAFE_ERROR: (data: { path: string; expected: string; value: string }) => {
if (path === 'password') return '密码不正确哦'
if (path === 'phone') return '手机号不正确,注意请不要加+86'
},
} satisfies MilkioFailCode;
这样做有一个潜在好处,也许我们许多个接口都有名为 password
的参数,对于同一个变量名,我们就不必“翻译”很多遍
但也有个问题, 万一遇到了同值显示不同的消息需要时,除了改变字段名之外,很难做出不同的处理
最好的办法其实是向 Typia 提 issue,建议对方支持此功能,这是 Typia 的仓库:https://github.com/samchon/typia
我会继续思考,对于 Milkio 而言,是否应该在 Typia 之外,去面对这个需求去设计一些功能
但坦白讲,目前我还没有一些好的灵感,包括如何实现、语法设计成什么样子。一但我有一些想法,我会在这里回复
好的!
hmmmm....
没记错的话,很多提供 API 接口的平台,都是提供英文的错误信息和数字的错误码,除非是这个接口要提交给前端显示给用户,不然一律提示网络出现问题,然后开发者得到日志之后再去后台的表格(或者 API 文档公开的表格)中查询就是了……?
关于这个问题我思考了很多,例如,有想过添加一个专门处理 TypeSafeError 的中间件,或者在 defineApi 中增加一个选项,专门处理这方面等
可以确认的是,这个需求很常见(是的,我自己也需要),经过我的思考后,我认为,这个需求实际上,是由两部分种需求耦合在一起的:
一种是展示给用户人性化的错误信息的需求,例如,不能是 参数错误:当前值 "password" 不符合 string 类型的预期
,而应该是 密码不正确,可能太长或者太短啦
一种是国际化/本地化的需求,要将代码中的参数名称,翻译为对应的中文
以往主流的解决方案是将错误信息和类型是耦合在一起,以老牌验证器 class-validator
为例:
export class CreateUserDto {
@IsNotEmpty({ message: '用户名不能为空' })
@MaxLength(20, { message: '用户名不能超过20个字符' })
username: string;
@IsNotEmpty({ message: '密码不能为空' })
password: string;
}
这种方案我认为还不够好,可以预见,它有这些问题:
类型和错误信息耦合在一起
要为每一种错误都编写人性化的提示语
难以实现多语言功能,因为在编写类型或者 DTO 时,我们无法得知 Header 中的 Accept-Language
是什么
经过我的思考,我觉得我自己(和以往的 Validator 库)都陷入了一个误区:
用户实际上是不直接与服务器沟通的,实现类似的功能是否真的是必要的?
对于前端而言,本身就会做许多的判断,例如许多流行的 UI 框架都会有校验表单数据是否符合预期的功能,用户的非合理输入,都会直接在 UI 层面被拦截。只有开发者和黑客才会看得到服务器的实际 message
消息
即使是在后端中完成了多语言的功能,前端的多语言也是必需的,有大量的文字都由前端来呈现,而且前端可以很简单地实现用户自由切换语言的功能,后端则只能依赖于 Accept-Language
所以,实际上,返回友好的自定义消息,其实是将许多前端的工作转移到了后端,这会迫使我们在前后端将逻辑重复编写两次
等等,所以…… 你就是说,应该用前端的 UI 组件库来校验数据?这么做不对呀!直接利用后端来做校验,可以让我能够节省许多代码量!
绝大多数情况下,简单地提交后校验,并弹出 toast 就可以满足我的需求了,如果我要使用前端 UI 框架提供的校验功能,相当于我要在视图中再把类型重复定义一遍,这样太麻烦了。
是的,绝大多数情况下,简单地提交后校验,并弹出 toast 就可以满足我的需求了。但这并非是说,toast 所显示的消息,一定是要后端所返回的,由于我们可以知道错误的原因,所以,我们可以在前端控制:
const result = await client.execute(...);
if (!result.success) {
if (foo.fail.code !== "TYPE_SAFE_ERROR") return alert(foo.fail.message); // 不想自定义类型安全错误以外的消息
if (foo.fail.data.path === "$input.password") return alert("密码太长或者太短");
if (foo.fail.data.path === "$input.username") return alert("用户名不符合规范,需要不包含汉字和符号");
...
}
前端来显示用户友好的失败消息,与后端以往的失败信息和类型耦合在一起的方案相比,可以解决以下问题:
如果有多语言的需求,就不用前端与后端一起痛苦的改造了,可以完全在前端实现
我们可以只关注用户可能会遇到的失败消息,用户不可能遇到的失败消息,我们可以不用写
代码量并没有提升多少,也不需要重复定义类型。想要修改消息时,不用去思考当初消息是写在前端还是写在后端里了
在此前版本的 Milkio 中,fail.data
的类型永远是 any
,在 milkio >= 0.3.1
且 milkio-client >= 0.3.9
(刚刚更新的版本)后,fail.data
将会有实际的类型提示了
我们甚至可以利用编辑器自动补全诸如 foo.fail.data.path === "$input.password"
这样的代码,是的,"$input.password"
这种字符串,也能够被补全和检查出错误
你说的很有道理!其实我提issue的本意是TYPE_SAFE_ERROR
的错误消息太代码化了,比如"$input.by Parameter Error: The current value is 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', which does not meet 'string & MaxLength<16>' requirements"
中的string & MaxLength<16>
。感觉很多情况下前端很难知道后端所有的错误类型,所以一般情况下会直接将错误信息展示给用户,导致可读性大大降低。
是这样的!我开始使用 Typia 时,也因为这一点所困扰,但也能够理解 Typia 这样设计的初衷,因为传统的 Validator 库实际上是对“Form”的升级,所处理的都是无嵌套的 Key-Value Object 数据,而 Typia 所处理的类型是不固定的,可能有既可能有多层嵌套的对象,也可能本身是个数组或者基础类型,这导致 Typia 只能通过 $input.foo.bar.baz
的方式告知我们出现错误的位置,难以对用户友好
如果未来 Typia 一旦像类似传统的 Validator 库一样,支持了自定义错误消息,我会尽快适配兼容的
感谢你的问题!这是一个很有意义的问题,能够收到问题说明有人正在用或者玩 Milkio,这会让我感到很开心❤️
类似于这种吧。