Package xerrors
provides extended error handling primitives to add a bit more information to errors returning from the function.
go get github.com/eugeneradionov/xerrors
Every API that handles HTTP requests, you need to work with error handling.
The standard errors
package does not bring the easy way to know what the error is and with which code to respond.
With xerrors
package, you can extend the error with missing information, such as HTTP status code to respond,
and better control the application flow.
Use XError
interface instead of standard error
func GetUserByID(id string) (*User, xerrors.XError) {
user, err := db.GetUserByID(id)
if err != nil {
return nil, xhttp.NewInternalServerError(err)
}
return user, nil
}
func GetUserHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json;charset=utf-8")
user, xErr := GetUserByID("user_id_1")
if xErr != nil {
LogXError(xErr)
SendXError(w, xErr)
return
}
}
func SendExtError(w http.ResponseWriter, xErr xerrors.XError) {
var statusCode = xErr.GetExtra()["http_code"].(int)
w.Header().Set("Content-Type", "application/json;charset=utf-8")
errResp, err := json.Marshal(xErr)
if err != nil {
statusCode = http.StatusInternalServerError
}
w.WriteHeader(statusCode)
w.Write(errResp)
}
func LogXError(xErr xerrors.XError) {
log.Printf("[ERR] %s: %s", xErr.Error(), xErr.GetInternalExtra()["error"].(error).Error())
}
The same with xerror
func GetUserByID(id string) (*User, xerrors.XError) {
user, err := db.GetUserByID(id)
if err != nil {
return nil, xerrors.New("Internal Server Error",
xerrors.WithExtra(map[string]interface{}{"http_code": http.StatusInternalServerError}),
xerrors.WithInternalExtra(map[string]interface{}{"error": err}),
)
}
return user, nil
}
Use XErrors
for handling multiple errors
func GetUsersHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json;charset=utf-8")
xErrs := xerrors.NewXErrs()
user1, xErr := GetUserByID("user_id_1")
if xErr != nil {
xErrs.Add(xErr)
}
user2, xErr := GetUserByID("user_id_2")
if xErr != nil {
xErrs.Add(xErr)
}
SendXErrs(w, http.StatusUnprocessableEntity, xErrs)
}
func SendXErrs(w http.ResponseWriter, statusCode int, xErrs xerrors.XErrs) {
w.Header().Set("Content-Type", "application/json;charset=utf-8")
errResp, err := json.Marshal(xErrs)
if err != nil {
statusCode = http.StatusInternalServerError
}
w.WriteHeader(statusCode)
w.Write(errResp)
}
As XError
requires implementation of standard error
interface to be compatible with it,
be careful, when trying to assign function result XError
to the variable with standard error
type.
This could cause unpredictable behavior.