wisski-cloud-distillery/pkg/httpx/errors.go
2022-11-24 14:19:17 +01:00

75 lines
2.1 KiB
Go

package httpx
import (
"encoding/json"
"errors"
"net/http"
)
// ErrInterceptor intercepts errors and directly returns specific responses for them
type ErrInterceptor struct {
Errors map[error]Response
Fallback Response
}
// Intercept attempts to intercept the given error.
// When err is nil, does nothing.
//
// When err is not nil, first attempts to find a static response in errors and respond with that.
// Otherwise it returns the Fallback response.
// intercepted indicates if some response was sent.
func (ei ErrInterceptor) Intercept(w http.ResponseWriter, r *http.Request, err error) (intercepted bool) {
if err == nil {
return false
}
res, ok := ei.Errors[err]
if !ok {
res = ei.Fallback
}
res.ServerHTTP(w, r)
return true
}
// StatusInterceptor creates a new ErrInterceptor handling default responses.
// If body returns err != nil, StatusInterceptor calls panic().
func StatusInterceptor(contentType string, body func(code int, text string) ([]byte, error)) ErrInterceptor {
makeResponse := func(code int) (res Response) {
var err error
res.Body, err = body(code, http.StatusText(code))
if err != nil {
panic("StatusInterceptor: err != nil")
}
res.ContentType = contentType
res.StatusCode = code
return
}
return ErrInterceptor{
Errors: map[error]Response{
ErrNotFound: makeResponse(http.StatusNotFound),
ErrForbidden: makeResponse(http.StatusForbidden),
},
Fallback: makeResponse(http.StatusInternalServerError),
}
}
// Common errors accepted by all httpx handlers
var (
ErrNotFound = errors.New("httpx: Not Found")
ErrForbidden = errors.New("httpx: Forbidden")
)
var (
textInterceptor = StatusInterceptor("text/plain", func(code int, text string) ([]byte, error) {
return []byte(text), nil
})
jsonInterceptor = StatusInterceptor("application/json", func(code int, text string) ([]byte, error) {
return json.Marshal(map[string]any{"status": text, "code": code})
})
htmlInterceptor = StatusInterceptor("text/html", func(code int, text string) ([]byte, error) {
return []byte(`<!DOCTYPE HTML><title>` + text + `</title>` + text), nil
})
)