ginWrapper v1.0: 统一响应格式

前言

  • 经历过前(web, 客户端,嵌入式,etc)后端联调的同学都知道,指定规范的交互协议是非常重要的。如果没有一定的规范,协议的格式必然是五花八门的,前端的小伙伴需要适配各种消息结构,带来巨大的工作量
  • 在后端开发的方法论中,少写重复的代码一直是我们追求的目标。该模块的初衷也是帮我们快速构造符合协议的数据结构,减少代码量
  • 在http请求中,最常用的格式为json。所以在的设计中,只考虑了json。后期有需要,会考虑更多的Content-Type
  • 总结一下,我们目标是:1. 统一前后端数据交互格式 2. 抽象出公共代码,快速构造响应数据

响应结构体

{
  "Result": {
    "Code": 0,
    "Message":"success"
  },
  "Data": null
}
  • code中传递的是业务码,0为成功,1为失败,还可以声明其他业务码,有兴趣的同学可以参照代码
  • message为业务响应信息
  • data用于传递业务数据
  • 前端的同学可以按照这个数据结构完成数据的解析

request.go

type GinContext struct {
	*gin.Context
}

func NewGinContext(c *gin.Context) *GinContext {
	return &GinContext{
		Context: c,
	}
}

type GinContextFunc func(ctx *GinContext)

func WrapGinContext(handler GinContextFunc) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		handler(NewGinContext(ctx))
	}
}

response.go

type ResponseInfo struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

type Response struct {
	Result ResponseInfo `json:"result"`
	Data   interface{}  `json:"data"`
}

const (
	CodeSuccess = 0
	CodeFailure = 1

	CodeBindError        = 10
	CodeRecordNotFound   = 11
	CodePermissionDenied = 12
)

var ResponseMap = map[int]ResponseInfo{
	CodeSuccess:   {http.StatusOK, http.StatusText(http.StatusOK)},
	CodeFailure:   {http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)},
	CodeBindError: {http.StatusInternalServerError, "params bind error"},
}

// SendResponse code为可变参数,code[0]为business code, code[1]为http code
func (c *GinContext) SendResponse(data interface{}, codes ...int) {
	httpCode := http.StatusOK
	response, exist := ResponseMap[codes[0]]
	if !exist {
		response = ResponseMap[CodeFailure]
	}

	result := ResponseInfo{codes[0], response.Message}
	if len(codes) > 1 {
		httpCode = codes[1]
	} else if result.Code <= 20 {
		httpCode = result.Code
	}
	c.JSON(httpCode, Response{result, data})
}

func (c *GinContext) OK(data interface{}) {
	c.SendResponse(data, CodeSuccess)
}

func (c *GinContext) BindFailure() {
	c.SendResponse(nil, CodeBindError)
}

func (c *GinContext) Failure(err error) {
	c.JSON(http.StatusInternalServerError, Response{
		Result: ResponseInfo{
			Code:    CodeFailure,
			Message: err.Error(),
		},
		Data: nil,
	})
}

举个栗子

package main

import (
	"ginWrapper"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
)

func main() {
	r := gin.Default()
	r.Use(ginWrapper.APILogger(ginWrapper.GinLog{})) // 在注册路由之前引入中间件
	r.POST("/health", ginWrapper.WrapGinContext(healthHandler))
}

func healthHandler(ctx *GinContext) {
	ctx.OK(nil)
}

有需要完整代码的同学可以参考github


golang

649 Words

2021-10-06 10:18