package router import ( "fmt" "net/http" ) // ErrorResponder responds with error type ErrorResponder interface { RespondError(w http.ResponseWriter, r *http.Request, re *Router) bool } // HTTPStatusError http statuscode errors type HTTPStatusError struct { statuscode int err error body interface{} output bool } // HTTPError handle HTTP error func HTTPError(statuscode int, err error) *HTTPStatusError { return &HTTPStatusError{statuscode: statuscode, err: err} } // HTTPErrorWithBody handle HTTP error with body func HTTPErrorWithBody(body interface{}, statuscode int, err error) *HTTPStatusError { return &HTTPStatusError{body: body, statuscode: statuscode, err: err} } // HTTPErrorWithReport handle HTTP error returning status report func HTTPErrorWithReport(statuscode int, err error) *HTTPStatusError { return &HTTPStatusError{statuscode: statuscode, err: err, output: true} } // RespondError HTTP error response func (e *HTTPStatusError) RespondError(w http.ResponseWriter, r *http.Request, re *Router) bool { if e.err != nil { if e.statuscode >= 200 && e.statuscode <= 499 { re.logger.Error.Warn(e.err) } else { re.logger.Error.Error(e.err) } } if e.output { re.Respond(struct { Status string Error string }{ Status: fmt.Sprintf("%d %s", e.statuscode, http.StatusText(e.statuscode)), Error: e.err.Error(), }, e.statuscode).ServeHTTP(w, r) } else if e.body == nil { re.handleError(e.statuscode).ServeHTTP(w, r) } else { re.Respond(e.body, e.statuscode).ServeHTTP(w, r) } return true } // Error returns HTTP error func (e *HTTPStatusError) Error() string { return e.err.Error() } // WithError error handler func (re *Router) WithError(h HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if err := h(w, r); err != nil { if er, ok := err.(ErrorResponder); ok { if er.RespondError(w, r, re) { return } } re.logger.Error.Error(err) re.handleError(http.StatusInternalServerError).ServeHTTP(w, r) } } } func (re *Router) handleError(statuscode int) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { re.logger.AccessMessage(r, statuscode) w.WriteHeader(statuscode) re.RenderTemplate(struct { Title string Status struct { Status string StatusCode int } }{ Title: http.StatusText(statuscode), Status: struct { Status string StatusCode int }{ Status: http.StatusText(statuscode), StatusCode: statuscode, }, }).ServeHTTP(w, r) } }