背景
在完成API接口、公共包给他人使用等类似工作时,除了对外提供功能外,文档也是非常重要的内容。文档输出的是可复制的能力,使用者通过文档快速学习了解使用,而不用多次找到开发人员重复答疑。
其中问的最多最频繁的就是错误码定义了,通常是需要给出所有返回错误的文档。
本文将分享我golang中error最佳实践,该实践不仅编码非常简单,而且做到了代码即文档,写完就自动生成了交付文档。
直接上代码
package api import ( "fmt" "runtime" "strconv" "strings" ) type Error int16 const ( ErrOK = Error(0) // 大于0的异常属于业务调用方错误,通常是需要调用方自行处理 ErrForbidden = Error(1000) ErrParams = Error(1001) ErrInvalidToken = Error(2001) // 小于0的错误码为系统内部异常,通常是需要开发运维去解决的 ErrBugInvalidData = Error(-1001) ErrDbFail = Error(-1002) ) func (me Error) detail() (string, string) { switch me { case ErrOK: return "OK", "正常" case ErrDbFail: return "ErrDbFail", "数据库操作异常,内部服务请转运维处理" case ErrBugInvalidData: return "ErrBugInvalidData", "内部产生了异常数据,属于BUG请开发处理" case ErrForbidden: return "ErrForbidden", "未授权" case ErrParams: return "ErrParams", "请求参数错误" case ErrInvalidToken: return "ErrInvalidToken", "鉴权Token不合法" default: return "Unknown", strconv.Itoa(int(me)) } } // ##### 以下代码无需任何变更 ##### func (me Error) Error() string { s, _ := me.detail() return s } // 转整数,返回错误码时使用 func (me Error) Code() int16 { return int16(me) } // 生成文档 func (me Error) Doc() string { sb := &strings.Builder{} _, file, _, _ := runtime.Caller(0) sb.WriteString(file) sb.WriteString("\n") fn := func(sb *strings.Builder, start, end, step int16) { for { e := Error(start) s, d := e.detail() if "Unknown" != s { sb.WriteString(fmt.Sprintf("%d %s %s\n", e.Code(), s, d)) } if start == end { break } else { start += step } } } fn(sb, 0, 0, 1) fn(sb, 1, 32767, 1) fn(sb, -1, -32768, -1) return sb.String() }复制代码
一行代码生成文档
fmt.Println(Error(0).Doc()) 输出: /woo/litim/errdef.go 0 OK 正常 1000 ErrForbidden 未授权 1001 ErrParams 请求参数错误 2001 ErrInvalidToken 鉴权Token不合法 -1001 ErrBugInvalidData 内部产生了异常数据,属于BUG请开发处理 -1002 ErrDbFail 数据库操作异常,内部服务请转运维处理复制代码
其它优点
- 作为error类型非常通用同时做到了const定义,防止运行时修改。这样外部调用接口后可以通过返回的Error做判断
err:=api.Call() if err == api.ErrForbidden { }复制代码
- 只需三行代码增加新的Error,非常方便
const ErrXXXX=Error(6) // 定义 // 加入case 返回错误提示 switch me { case ErrXXXX: return "ErrXXXX", "something wrong" }复制代码
编译阶段检查防止Error Code重复定义
switch不允许重复的case项,如果重复会编译错误,智能的ide将自动定位到重复的项通过大于0和小于0来将错误进行分类,快速定位
故障单瞄一眼心里就有底,大于0业务方先查起,小于0低调点默默的找问题。降低强势扯皮最后啪啪啪打脸发生概率。建议
将错误码从正负1000开始,999以内的作为救命用保留。祝愿您永远用不到999(救救救)以内。
有疑问加站长微信联系(非本文作者)