package server import ( "net/http" "github.com/go-chi/render" ) // ErrResponse renderer type for handling all sorts of errors. // // In the best case scenario, the excellent github.com/pkg/errors package // helps reveal information on the error, setting it on Err, and in the Render() // method, using it to set the application-specific error code in AppCode. type ErrResponse struct { Err error `json:"-"` // low-level runtime error HTTPStatusCode int `json:"-"` // http response status code StatusText string `json:"status"` // user-level status message ErrorText string `json:"error,omitempty"` // application-level error message, for debugging } func (e *ErrResponse) Render(_ http.ResponseWriter, r *http.Request) error { render.Status(r, e.HTTPStatusCode) return nil } func ErrBasic(status int) *ErrResponse { return &ErrResponse{ HTTPStatusCode: status, StatusText: http.StatusText(status), } } func ErrGeneric(err error, status int) *ErrResponse { resp := ErrBasic(status) resp.Err = err resp.ErrorText = err.Error() return resp } func ErrBadRequest(err error) *ErrResponse { return ErrGeneric(err, http.StatusBadRequest) } func ErrNotFound() *ErrResponse { return ErrBasic(http.StatusNotFound) } func ErrUnauthorized() *ErrResponse { return ErrBasic(http.StatusUnauthorized) } func ErrForbidden() *ErrResponse { return ErrBasic(http.StatusForbidden) } func ErrRendering(err error) *ErrResponse { return &ErrResponse{ Err: err, HTTPStatusCode: http.StatusUnprocessableEntity, StatusText: "Error rendering response.", ErrorText: err.Error(), } } func RenderRender(w http.ResponseWriter, r *http.Request, resp render.Renderer) { // Try to render the response if err := render.Render(w, r, resp); err != nil { // If error, try to render that an error occurred if err := render.Render(w, r, ErrRendering(err)); err != nil { // If error, panic panic(err) } } } func RenderBadRequest(w http.ResponseWriter, r *http.Request, err error) { RenderRender(w, r, ErrBadRequest(err)) } func RenderServerError(_ http.ResponseWriter, _ *http.Request, err error) { // Panic so the stack trace is printed panic(err) } func RenderNotFound(w http.ResponseWriter, r *http.Request) { RenderRender(w, r, ErrNotFound()) } func RenderUnauthorized(w http.ResponseWriter, r *http.Request) { RenderRender(w, r, ErrUnauthorized()) } func RenderForbidden(w http.ResponseWriter, r *http.Request) { RenderRender(w, r, ErrForbidden()) }