go-kratos接口的自定义返回格式

1,756 阅读1分钟

引言

业务实现过程中,一般会形成约定俗成的一些默认格式,前后端对于接口格式的约定,多服务之间的接口交互格式等等。所以需要对于接口进行返回格式进行自定义实现。

go-kratos 接口返回格式

默认格式:

{
    // 错误码,跟 http-status 一致,并且在 grpc 中可以转换成 grpc-status
    "code": 500,
    // 错误原因,定义为业务判定错误码
    "reason": "USER_NOT_FOUND",
    // 错误信息,为用户可读的信息,可作为用户提示内容
    "message": "invalid argument error",
    // 错误元信息,为错误添加附加可扩展信息
    "metadata": {
      "foo": "bar"
    }
}

相关实现规范

自定义实现

自定义格式如下:

// httpResponse 响应结构体
type httpResponse struct {
    Code    int         `json:"code"`
    Message string      `json:"message"`
    Data    interface{} `json:"data"`
}

接口响应:即http响应状态码为 200 时的实现

// EncoderResponse  请求响应封装
func EncoderResponse() http.EncodeResponseFunc {
    return func(w stdhttp.ResponseWriter, request *stdhttp.Request, i interface{}) error {
        if i == nil {
            return nil
        }
        resp := &httpResponse{
            Code:    stdhttp.StatusOK,
            Message: "",
            Data:    i,
        }
        codec := encoding.GetCodec("json")
        data, err := codec.Marshal(resp)
        if err != nil {
            return err
        }
        w.Header().Set("Content-Type", "application/json")
        _, err = w.Write(data)
        if err != nil {
            return err
        }
        return nil
    }
}

错误响应:即对于error的处理响应

// EncoderError 错误响应封装
func EncoderError() http.EncodeErrorFunc {
    return func(w stdhttp.ResponseWriter, r *stdhttp.Request, err error) {
        if err == nil {
            return
        }
        se := &httpResponse{}
        gs, ok := status.FromError(err)
        if !ok {
            se = &httpResponse{Code: stdhttp.StatusInternalServerError}
        }
        se = &httpResponse{
            Code:    httpstatus.FromGRPCCode(gs.Code()),
            Message: gs.Message(),
            Data:    nil,
        }
        codec, _ := http.CodecForRequest(r, "Accept")
        body, err := codec.Marshal(se)
        if err != nil {
            w.WriteHeader(stdhttp.StatusInternalServerError)
            return
        }
        w.Header().Set("Content-Type", "application/"+codec.Name())
        w.WriteHeader(se.Code)
        _, _ = w.Write(body)
    }
}

server引入

    // 请求响应封装
    opts = append(opts, http.ResponseEncoder(EncoderResponse()))
    // 错误响应封装`
    opts = append(opts, http.ErrorEncoder(EncoderError()))
    srv := http.NewServer(opts...)

完整实现