feat(smalltrip,exceptions): use a JSON handler if none is provided via the context
This commit is contained in:
@@ -12,6 +12,11 @@ type Exception struct {
|
||||
Message string `json:"message"` // User friendly message
|
||||
Err error `json:"error,omitempty"` // Go error
|
||||
Severity Severity `json:"severity"` // Exception level
|
||||
|
||||
// Handler to be used. This is normally provided by a middleware via the
|
||||
// request context. Setting this field overrides any provided by the middleware
|
||||
// and can be used to add a handler when using a middleware is not possible.
|
||||
handler HandlerFunc `json:"-"`
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -33,6 +38,8 @@ func (e Exception) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
e.handler(e, w, r)
|
||||
}
|
||||
|
||||
e.handler = HandlerJSON(HandlerText)
|
||||
|
||||
handler, ok := r.Context().Value(handlerFuncCtxKey).(HandlerFunc)
|
||||
if !ok {
|
||||
e.handler(e, w, r)
|
||||
|
||||
71
smalltrip/exceptions/middleware.go
Normal file
71
smalltrip/exceptions/middleware.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package exceptions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func HandlerJSON(fallback HandlerFunc) HandlerFunc {
|
||||
return func(e Exception, w http.ResponseWriter, r *http.Request) {
|
||||
j, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
e.Err = errors.Join(fmt.Errorf("marshalling Exception struct: %s", e.Error()), e.Err)
|
||||
|
||||
fallback(e, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(e.Status)
|
||||
|
||||
_, err = w.Write(j)
|
||||
if err != nil {
|
||||
e.Err = errors.Join(fmt.Errorf("writing JSON response to body: %s", e.Error()), e.Err)
|
||||
|
||||
HandlerText(e, w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _ HandlerFunc = HandlerJSON(HandlerText)
|
||||
|
||||
func HandlerText(e Exception, w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(e.Status)
|
||||
|
||||
_, err := w.Write([]byte(fmt.Sprintf(
|
||||
"Status: %3d\n"+
|
||||
"Code: %s"+
|
||||
"Message: %s\n"+
|
||||
"Err: %s\n"+
|
||||
"Severity: %s\n\n"+
|
||||
"%+v\n\n"+
|
||||
"%#v",
|
||||
e.Status,
|
||||
e.Code,
|
||||
e.Message,
|
||||
e.Err,
|
||||
e.Severity,
|
||||
|
||||
e, e,
|
||||
)))
|
||||
if err != nil {
|
||||
_, _ = w.Write([]byte(fmt.Sprintf(
|
||||
"Ok, what should we do at this point? You fucked up so bad that this message " +
|
||||
"shouldn't even be able to be sent in the first place. If you are a normal user I'm " +
|
||||
"so sorry for you to be reading this. If you're a developer, go fix your ResponseWriter " +
|
||||
"implementation, because this should never happen in any normal codebase. " +
|
||||
"I hope for the life of anyone you love you don't use this message in some " +
|
||||
"error checking or any sort of API-contract, because there will be no more hope " +
|
||||
"for you or your project. May God or any other or any other divinity that you may " +
|
||||
"or may not believe be with you when trying to fix this mistake, you will need it.",
|
||||
// If someone use this as part of the API-contract I'll not even be surprised.
|
||||
// So any change to this message is still considered a breaking change.
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
var _ HandlerFunc = HandlerText
|
||||
Reference in New Issue
Block a user