github.com/hellofresh/janus@v0.0.0-20230925145208-ce8de8183c67/pkg/errors/error.go (about) 1 /* 2 Package errors provides a nice way of handling http errors 3 4 Examples: 5 To create an error: 6 err := errors.New(http.StatusBadRequest, "Something went wrong") 7 */ 8 package errors 9 10 import ( 11 "net/http" 12 "runtime/debug" 13 14 log "github.com/sirupsen/logrus" 15 16 "github.com/hellofresh/janus/pkg/observability" 17 "github.com/hellofresh/janus/pkg/render" 18 ) 19 20 var ( 21 // ErrRouteNotFound happens when no route was matched 22 ErrRouteNotFound = New(http.StatusNotFound, "no API found with those values") 23 // ErrInvalidID represents an invalid identifier 24 ErrInvalidID = New(http.StatusBadRequest, "please provide a valid ID") 25 ) 26 27 // Error is a custom error that implements the `error` interface. 28 // When creating errors you should provide a code (could be and http status code) 29 // and a message, this way we can handle the errors in a centralized place. 30 type Error struct { 31 Code int `json:"-"` 32 Message string `json:"error"` 33 } 34 35 // New creates a new instance of Error 36 func New(code int, message string) *Error { 37 return &Error{code, message} 38 } 39 40 func (e *Error) Error() string { 41 return e.Message 42 } 43 44 // NotFound handler is called when no route is matched 45 func NotFound(w http.ResponseWriter, r *http.Request) { 46 Handler(w, r, ErrRouteNotFound) 47 } 48 49 // RecoveryHandler handler is used when a panic happens 50 func RecoveryHandler(w http.ResponseWriter, r *http.Request, err interface{}) { 51 Handler(w, r, err) 52 } 53 54 // Handler marshals an error to JSON, automatically escaping HTML and setting the 55 // Content-Type as application/json. 56 func Handler(w http.ResponseWriter, r *http.Request, err interface{}) { 57 entry := log.WithField("request-id", observability.RequestIDFromContext(r.Context())) 58 59 switch internalErr := err.(type) { 60 case *Error: 61 entry.WithFields(log.Fields{ 62 "code": internalErr.Code, 63 log.ErrorKey: internalErr.Error(), 64 }).Info("Internal error handled") 65 render.JSON(w, internalErr.Code, internalErr) 66 case error: 67 entry.WithError(internalErr).WithField("stack", string(debug.Stack())).Error("Internal server error handled") 68 render.JSON(w, http.StatusInternalServerError, internalErr.Error()) 69 default: 70 entry.WithFields(log.Fields{ 71 log.ErrorKey: err, 72 "stack": string(debug.Stack()), 73 }).Error("Internal server error handled") 74 render.JSON(w, http.StatusInternalServerError, err) 75 } 76 }