This is a creation in Article, where the information may have evolved or changed.
Objective
Golang error processing has been criticized, in fact, through the design pattern can be very good to deal with the error, here is a restful development as an example of error elegant processing
resuful Development, error processing has two purposes, one can return the error message to the user, two to facilitate debugging, in order to achieve elegance and a little, not everywhere is a variety of if language
Of course, as an elegant code, there is a point to ensure that you try not to write duplicate code
Panic processing
Here we take the panic processing, the panic if the judgment is also encapsulated in a method, and the package on the stack information (here to use the github.com/pkg/errors package, the specific use here will not repeat, you can see the documentation on GitHub), convenient debugging:
func ThrowError(err error) { ifnil { panic(errors.WithStack(err)) }}
It's pretty simple when we call it.
// MarshalJson 把对象以json格式放到response中funcinterface{}) { data, err := json.Marshal(v) ThrowError(err) w.Write(data)}// UnMarshalJson 从request中取出对象funcinterface{}) { result, err := ioutil.ReadAll(req.Body) err = errors.New("TEST") ThrowError(err) json.Unmarshal([]byte(bytes.NewBuffer(result).String()), v)}
This throws a mistake down the ladder until it encounters the recover of processing.
Revocer processing
We've encapsulated the corresponding recover.
func CatchError(w http.ResponseWriter, req *http.Request) { ifrecovernil { "9001", Msg: r.(error).Error()} MarshalJson(w, resp) fmt.Printf("%+v\n", r.(error)) }}
Return the error to the user and print the wrong information, including the stack
Unified Processing
As a RESTful unified processing place, generally is the Servehttp method, but if the use of third-party MUX, forced to change the source code is not too elegant, and the MUX also has an upgrade, you can not upgrade once, then use a packaging method
typestruct { *mux.Router}func (r *MyRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { defer tools.CatchError(w, req) r.Router.ServeHTTP(w, req)}func NewAPIMux() http.Handler { r := &MyRouter{mux.NewRouter()} s := r.PathPrefix("/api").Subrouter() initUserApi(s) r.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("web/")))) return r}
In this way, error is handled gracefully, anywhere, just by calling the ThrowError method by business, the client can receive an error message, and the server can print the wrong stack information at the same time.
Sample output