Response Extensions
Overview
Section titled “Overview”Currently go-zero provides very strong http ability, but some features are still not go-zero implemented, there is a x repository dedicated to go-zero, where HTTP extensions are supported:
- Code-data response format support
- xml response support
- code-msg error type support
For more information, see https://github.com/zeroicro/x
code-data uniform response format usage
Section titled “code-data uniform response format usage”In many cases, in order to achieve a uniform response format with the front end, we usually encapsulate a layer of business code, msg and business data in the following common format:
{ "code": 0, "msg": "ok", "data": { ... }}There are currently two approaches if this format response is required:
- Custom response format
- Use go-zero extension to implement
We show below with a go-zero extension package.
- Initialize a demo project
$ mkdir demo && cd demo$ go mod init demo2 Create an api file in demo directory user.api, add the following
syntax = "v1"
type LoginRequest { Username string `json:"username"` Password string `json:"password"`}
type LoginResponse { UID int64 `json:"uid"` Name string `json:"name"`}
service user { @handler login post /user/login (LoginRequest) returns (LoginResponse)}3 Generate code by goctl
$ goctl api go --api user.api --dir .Done.- Add stock logic, modify
demo/internal/logic/loginlogic.gofile to make its code:
package logic
import ( "context"
"demo/internal/svc" "demo/internal/types"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/x/errors")
type LoginLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext}
func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic { return &LoginLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, }}
func (l *LoginLogic) Login(req *types.LoginRequest) (resp *types.LoginResponse, err error) { // mock login if req.Username != "go-zero" || req.Password != "123456" { return nil, errors.New(1001, "invalid username or password") }
resp = new(types.LoginResponse) resp.Name = "go-zero" resp.UID = 1 return resp, nil}So let’s first look at the format of the response before the file demo/internal/handler/loginhandler.go:
$ cd demo$ go mod tidy$ go run user.go# beforecurl --location '127.0.0.1:8888/user/login' \--header 'Content-Type: application/json' \--data '{ "username":"go-zero", "password":"123456"}'{"uid":1,"name":"go-zero"}
# aftercurl --location '127.0.0.1:8888/user/login' \--header 'Content-Type: application/json' \--data '{ "username":"go-zero", "password":"111111"}'code: 1001, msg: invalid username or password4 Next, we modify demo/internal/handler/loginhandler.go file, replacing the response method in loginHandler with the method in the extension pack
::tip tip tips This step can be implemented by modifying templates to prevent every time they are generated, custom templates can be referenced Template Customization :::
package handler
import ( "net/http"
"demo/internal/logic" "demo/internal/svc" "demo/internal/types" "github.com/zeromicro/go-zero/rest/httpx" xhttp "github.com/zeromicro/x/http")
func loginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.LoginRequest if err := httpx.Parse(r, &req); err != nil { httpx.ErrorCtx(r.Context(), w, err) return }
l := logic.NewLoginLogic(r.Context(), svcCtx) resp, err := l.Login(&req) if err != nil { // code-data response xhttp.JsonBaseResponseCtx(r.Context(), w, err) } else { // code-data response xhttp.JsonBaseResponseCtx(r.Context(), w, resp) } }}Restart user to request a response format:
$ go run user.go# no error casecurl --location '127.0.0.1:8888/user/login' \--header 'Content-Type: application/json' \--data '{ "username":"go-zero", "password":"123456"}'{"code":0,"msg":"ok","data":{"uid":1,"name":"go-zero"}}
# error casecurl --location '127.0.0.1:8888/user/login' \--header 'Content-Type: application/json' \--data '{ "username":"go-zero", "password":"111111"}'{"code":1001,"msg":"invalid username or password"}xml response support
Section titled “xml response support”Further to the above, we will change the response from demo/internal/handler/loginhandler.go to x http.xhttp.OkXml or OkXmlCtx if the same code-data response format is required, exchange x http. mlBaseResponse or x http.XmlBaseResponseCtx For example, we revised the following code: as an example: x http.XmlBaseResponseCtx
package handler
import ( "net/http"
"demo/internal/logic" "demo/internal/svc" "demo/internal/types" "github.com/zeromicro/go-zero/rest/httpx" xhttp "github.com/zeromicro/x/http")
func loginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.LoginRequest if err := httpx.Parse(r, &req); err != nil { httpx.ErrorCtx(r.Context(), w, err) return }
l := logic.NewLoginLogic(r.Context(), svcCtx) resp, err := l.Login(&req) if err != nil { //xhttp.XmlBaseResponse(w,err) xhttp.XmlBaseResponseCtx(r.Context(),w,err) } else { //xhttp.XmlBaseResponse(w,resp) xhttp.XmlBaseResponseCtx(r.Context(),w,resp) } }}We rerun user program to see the response format:
$ go run user.go# no errorcurl --location '127.0.0.1:8888/user/login' \--header 'Content-Type: application/json' \--data '{ "username":"go-zero", "password":"123456"}'<xml version="1.0" encoding="UTF-8"><code>0</code><msg>ok</msg><data><UID>1</UID><Name>go-zero</Name></data></xml>
# error casecurl --location '127.0.0.1:8888/user/login' \--header 'Content-Type: application/json' \--data '{ "username":"go-zero", "password":"111111"}'<xml version="1.0" encoding="UTF-8"><code>1001</code><msg>invalid username or password</msg></xml>