When business requirements call for complex error code definitions, it is recommended to flexibly use the Detail
parameter of error codes for extending error code functionality.
Let's look at an example that primarily implements the following features:
- Use middleware to identify the execution results of route functions and obtain the error code information returned by these functions, returning the error code information as part of the response to the caller.
- If an error occurs, record the current user information causing the error into the logs. This is achieved using the
Detail
extension parameter.
Business Error Codes
Error Code Definition
type BizCode struct {
User User
// ...
}
type User struct {
Id int
Name string
// ...
}
Using Error Codes
In most scenarios of error code extension, the gcode.WithCode
method is required:
// WithCode creates and returns a new error code based on given Code.
// The code and message is from given `code`, but the detail if from given `detail`.
func WithCode(code Code, detail interface{}) Code
Thus, our custom extension can be used as follows:
code := gcode.WithCode(gcode.CodeNotFound, BizCode{
User: User{
Id: 1,
Name: "John",
},
})
fmt.Println(code)
That is, in error codes, we can inject some customized error code extension data according to business scenarios to facilitate further processing by the upper layer.
Modifying Middleware
We will apply the custom error codes above in a request return middleware, allowing the top-layer business logic to obtain the details corresponding to the error code for further business processing. The data structure returned by the middleware can also be customized, such as the code
field which may not necessarily be an integer, and can be fully customized.
func ResponseHandler(r *ghttp.Request) {
r.Middleware.Next()
// There's custom buffer content, it then exits current handler.
if r.Response.BufferLength() > 0 {
return
}
var (
err = r.GetError()
res = r.GetHandlerResponse()
code = gerror.Code(err)
)
if code == gcode.CodeNil && err != nil {
code = gcode.CodeInternalError
}
if detail, ok := code.Detail().(BizCode); ok {
g.Log().Errorf(r.Context(), `error caused by user "%+v"`, detail.User)
}
r.Response.WriteJson(ghttp.DefaultHandlerResponse{
Code: gcode.CodeOK.Code(),
Message: gcode.CodeOK.Message(),
Data: res,
})
}
The Detail
data is automatically printed in the default logs of the Server
framework.