portainer/pkg/libhttp/error/error.go

62 lines
1.7 KiB
Go

// Package error provides error/logging functions that can be used in conjuction with http.Handler.
package error
import (
"errors"
"net/http"
"unicode"
"github.com/rs/zerolog/log"
"github.com/segmentio/encoding/json"
)
type (
// LoggerHandler defines a HTTP handler that includes a HandlerError return pointer
LoggerHandler func(http.ResponseWriter, *http.Request) *HandlerError
errorResponse struct {
Message string `json:"message,omitempty"`
Details string `json:"details,omitempty"`
}
)
func (handler LoggerHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
err := handler(rw, r)
if err != nil {
writeErrorResponse(rw, err)
}
}
func capitalize(s string) string {
if len(s) == 0 {
return s
}
// Capitalize the first letter of the word or sentence
firstLetter := unicode.ToUpper(rune(s[0]))
return string(firstLetter) + s[1:]
}
func writeErrorResponse(rw http.ResponseWriter, err *HandlerError) {
if err.Err == nil {
err.Err = errors.New(capitalize(err.Message))
}
log.Debug().CallerSkipFrame(2).Err(err.Err).Int("status_code", err.StatusCode).Str("msg", err.Message).Msg("HTTP error")
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(err.StatusCode)
enc := json.NewEncoder(rw)
enc.SetSortMapKeys(false)
enc.SetAppendNewline(false)
enc.Encode(&errorResponse{Message: err.Message, Details: capitalize(err.Err.Error())})
}
// WriteError is a convenience function that creates a new HandlerError before calling writeErrorResponse.
// For use outside of the standard http handlers.
func WriteError(rw http.ResponseWriter, code int, message string, err error) {
writeErrorResponse(rw, &HandlerError{code, message, err})
}