Pick up where you left off: The go-Zero architecture design and project design were covered in the previous article. This article follows up the project design by transforming gateway and RPC in the generated APP module. Without further ado, let’s get started!

gateway service

I have made some customization in Gateway. In the case that the end requests our background interface, although error codes are not needed in most cases, it is inevitable that some scenarios still need to do special processing according to fixed error codes. I have defined an error class by myself, which is only used in Gateway:

err.go:

package xerr

import "fmt"

type CodeError struct {
   errCode int
   errMsg  string
}

/ / property
func (e *CodeError) GetErrCode(a) int {
   return e.errCode
}

func (e *CodeError) GetErrMsg(a) string {
   return e.errMsg
}

func (e *CodeError) Error(a) string {
   return fmt.Sprintf(ErrCode: % d ", ErrMsg: % s", e.errCode, e.errMsg)
}

func New(errCode int, errMsg string) *CodeError {
   return &CodeError{errCode: errCode, errMsg: errMsg}
}

func NewErrCode(errCode int) *CodeError {
   return &CodeError{errCode: errCode, errMsg: MapErrMsg(errCode)}
}

func NewErrMsg(errMsg string) *CodeError {
   return &CodeError{errCode: BAD_REUQEST_ERROR, errMsg: errMsg}
}
Copy the code

errmsg.go

package xerr

var message map[int]string

func init(a)  {
   message = make(map[int]string)
   message[OK] = "SUCCESS"
   message[BAD_REUQEST_ERROR] = "Server busy, please try again later."
   message[REUQES_PARAM_ERROR] = "Parameter error"
   message[USER_NOT_FOUND] = "User does not exist"
}

func MapErrMsg(errcode int) string {
   if msg, ok := message[errcode]; ok {
      return msg
   } else {
      return "Server busy, please try again later."}}Copy the code

errcode.go

package xerr

// Successful return
const OK = 200

// Global error code
// The first three represent services, and the last three represent functions
const BAD_REUQEST_ERROR = 100001
const REUQES_PARAM_ERROR = 100002

// User module
const USER_NOT_FOUND = 200001
Copy the code

I put all three files in the lib/xerr directory

The default error code generated by goctl is fine, but it does not meet my requirements for returning custom error codes, so I have to write a uniform return result file:

httpresult:

package xhttp

import (
   "fishtwo/lib/xerr"
   "fmt"
   "github.com/tal-tech/go-zero/core/logx"
   "github.com/tal-tech/go-zero/rest/httpx"
   "google.golang.org/grpc/status"
   "net/http"
   "github.com/pkg/errors"
)

/ / HTTP method
func HttpResult(r *http.Request,w http.ResponseWriter,resp interface{},err error)  {
   if err == nil {
      // Successful return
      r:= Success(resp)
      httpx.WriteJson(w, http.StatusOK, r)
   } else {
      // Error return
      errcode := xerr.BAD_REUQEST_ERROR
      errmsg := "Server busy, please try again later."
      ife,ok := err.(*xerr.CodeError); ok{// Customize CodeError
         errcode = e.GetErrCode()
         errmsg = e.GetErrMsg()
      } else {
         originErr := errors.Cause(err) / / err type
         ifgstatus, ok := status.FromError(originErr); ok{// GRPC err error
            errmsg = gstatus.Message()
         }
      }
      logx.WithContext(r.Context()).Error("[gateway-srv-err] : % v",err)

      httpx.WriteJson(w, http.StatusBadRequest, Error(errcode,errmsg))
   }
}

// HTTP parameter error returned
func ParamErrorResult(r *http.Request,w http.ResponseWriter,err error)  {
   errMsg := fmt.Sprintf("%s ,%s", xerr.MapErrMsg(xerr.REUQES_PARAM_ERROR), err.Error())
   httpx.WriteJson(w, http.StatusBadRequest, Error(xerr.REUQES_PARAM_ERROR,errMsg))
}
Copy the code

responsebean

package xhttp

type (
   NullJson struct {}

   ResponseSuccessBean struct {
      Code int         `json:"code"`
      Msg  string      `json:"msg"`
      Data interface{} `json:"data"`})func Success(data interface{}) *ResponseSuccessBean {
   return &ResponseSuccessBean{200."OK", data}
}


type ResponseErrorBean struct {
   Code int         `json:"code"`
   Msg  string      `json:"msg"`
}

func Error(errCode int,errMsg string) *ResponseErrorBean {
   return &ResponseErrorBean{errCode, errMsg}
}
Copy the code

Put it under the lib/XHTTP

We then modified the code generated by goctl from internal/handler/ :

Of course you will say, every time after the creation of manual to change, good trouble!

Goctl template www.yuque.com/tal-tech/go…

Then modify ~/.goctl/ API /handler.tpl:

package handler

import (
	 "net/http"

	 {{.ImportPackages}}
)

func {{.HandlerName}}(ctx *svc.ServiceContext) http.HandlerFunc {
   return func(w http.ResponseWriter, r *http.Request){{{if .HasRequest}}var req types.{{.RequestType}}
      iferr := httpx.Parse(r, &req); err ! =nil {
         xhttp.ParamErrorResult(r,w,err)
         return
      }{{end}}

      l := logic.New{{.LogicType}}(r.Context(), ctx)
      resp, err := l.Login(req)
      xhttp.HttpResult(r,w,resp,err)
   }
}
Copy the code

Let’s see if it’s beautiful

Httpresult. go: httpresult.go: httpresult.go: Httpresult. go: Httpresult. go:

Yes, yes, this will do, so that whenever there is an error the log will be printed, Go-Zero has trace-id in, what? What is trace-id? Well, it’s basically concatenating a request through this ID, so if you’re using user-API to call user-> SRV or any other SRV, you want to concatenate all of their requests, you need a unique identifier, and that’s what this ID does, and there’s a lot of link tracing, Jaeger, Zipkin.

RPC service

The model: In RPC service, the official document recommended that model be placed in the services directory, one layer with each RPC service. However, I feel that each model corresponds to a table, and a table can only be controlled by one service. Whichever service controls this table has the right to control this model. Other services will be accessed through GRPC, which is my personal idea, so I put the model controlled by each service in internal

Enum: In addition, I added the enum directory under the service, because other RPC services or API services will call this enumeration to compare, I put it outside the internal

Framework to address

Github.com/tal-tech/go…

Welcome to Go-Zero and star support us at 👍


I’ve compiled a list of the go-Zero author’s acclaimed shared videos from last year, detailing the go-Zero design concepts and best practices. Pay attention to the public account “micro-service practice”, reply to the video to obtain; You can also join groups and learn from thousands of Go-Zero users.