深色模式
go-zero定制handler返回数据 
go-zero的goctl工具,对生成的xxhandler.go的代码进行定制。
默认行为 
默认模板,生成的handler,返回的json是类似这样的:
json
{
    "result": 100
}我希望它是这样的:
json
{
    "code": 0,
    "msg": "success",
    "result": 100
}解决办法,就是修改goctl工具的模板。
准备工作 
定义错误码 
在logic目录中,新建errors.go:
go
package logic
import "fmt"
// 错误分为以下几类
// - 成功
// - 不规范错误
// - 规范错误
// - 未使用的错误
const (
	ErrOk = iota + 0
)
const (
	ErrUnspecified = -1 // 不规范错误,未分类的错误
)
const (
	ErrInvalidToken = iota + 100
	ErrInvalidParam
	ErrNoPermission
)
const (
	ErrInternalError = iota + 500
)
// 此类型代表是规范错误
type GyError struct {
	Code int64  `json:"code"`
	Msg  string `json:"msg"`
}
func (e GyError) Error() string {
	return e.Msg
}
// 使用默认message
func NewGyError(code int64) GyError {
	return GyError{
		Code: code,
		Msg:  defaultMessage(code),
	}
}
// 指定message
func NewGyErrorReplaceMsg(code int64, message string) GyError {
	return GyError{
		Code: code,
		Msg:  message,
	}
}
// 追加message
func NewGyErrorAppendMsg(code int64, message string) GyError {
	return GyError{
		Code: code,
		Msg:  fmt.Sprintf("%s >> %s", defaultMessage(code), message),
	}
}
// 默认的->错误码说明信息
func defaultMessage(code int64) string {
	var msg string
	switch code {
	case ErrOk:
		msg = "success"
	case ErrUnspecified:
		msg = "[unspecified error]"
	case ErrInvalidToken:
		msg = "token不合法"
	case ErrInvalidParam:
		msg = "参数不合法"
	case ErrNoPermission:
		msg = "无权限"
	case ErrInternalError:
		msg = "内部错误"
	default:
		msg = "未使用"
	}
	return msg
}编写响应函数 
在internal中新建一个文件夹hresp(取这个名字是因为我希望它和handler挨在一起),在hresp中新建hresp.go文件,文件内容如下:
go
// Response
// 如果没有错误,err传空
// 如果有错误:err非空
// - 非规范错误:未指定错误码
// - 规范错误:根据错误类型,指定错误码
func Response(w http.ResponseWriter, resp any, err error) {
	var body Body
	var gyError logic.GyError
	if err == nil {
		// 1. [没有错误]
		gyError = logic.NewGyError(logic.ErrOk)
	} else {
		var target logic.GyError
		if !errors.As(err, &target) {
			// 2.1 [不规范错误]
			gyError = logic.NewGyErrorAppendMsg(logic.ErrUnspecified, err.Error())
		} else {
			// 2.2 [规范错误]
			gyError = target
		}
	}
	body = Body{
		Code:   gyError.Code,
		Msg:    gyError.Msg,
		Result: resp,
	}
	httpx.OkJson(w, body)
}调用函数 
调用上面的Response()函数,即可返回我们想要的json结构。
所以,我们通过修改goctl的模板文件,让goctl生成的代码去调用Response()函数,而不必我们手写调用。
定制 
修改模板 
执行命令:
sh
goctl template init会在~/.goctl中初始化默认的模板文件。
找到api/handler.tpl文件,它的内容是:
go
package {{.PkgName}}
import (
	"net/http"
	"github.com/zeromicro/go-zero/rest/httpx"
	{{.ImportPackages}}
)
func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		{{if .HasRequest}}var req types.{{.RequestType}}
		if err := httpx.Parse(r, &req); err != nil {
			httpx.ErrorCtx(r.Context(), w, err)
			return
		}
		{{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)
		{{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})
		if err != nil {
			httpx.ErrorCtx(r.Context(), w, err)
		} else {
			{{if .HasResp}}httpx.OkJsonCtx(r.Context(), w, resp){{else}}httpx.Ok(w){{end}}
		}
	}
}将其修改为:
go
package {{.PkgName}}
import (
  "net/http"
  "github.com/zeromicro/go-zero/rest/httpx"
  {{.ImportPackages}}
)
func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
  return func(w http.ResponseWriter, r *http.Request) {
    {{if .HasRequest}}var req types.{{.RequestType}}
    if err := httpx.Parse(r, &req); err != nil {
      hresp.Response(w, nil, err)
      return
    }
    {{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)
    {{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})
    {{if .HasResp}}hresp.Response(w, resp, err){{else}}hresp.Response(w, nil, err){{end}}
  }
}生成代码 
使用goctl api go即可生成想要的代码。
sh
goctl api go --api app/api.api --dir app --style go_zerohandler的代码,从默认的:
go
func AppHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var req types.Request
		if err := httpx.Parse(r, &req); err != nil {
			httpx.ErrorCtx(r.Context(), w, err)
			return
		}
		l := logic.NewAppLogic(r.Context(), svcCtx)
		resp, err := l.App(&req)
		if err != nil {
			httpx.ErrorCtx(r.Context(), w, err)
		} else {
			httpx.OkJsonCtx(r.Context(), w, resp)
		}
	}
}变为:
go
func AppHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var req types.Request
		if err := httpx.Parse(r, &req); err != nil {
			hresp.Response(w, nil, err)
			return
		}
		l := logic.NewAppLogic(r.Context(), svcCtx)
		resp, err := l.App(&req)
		hresp.Response(w, resp, err)
	}
}