120 lines
4.0 KiB
Go
120 lines
4.0 KiB
Go
package rest
|
|
|
|
import (
|
|
"net/http"
|
|
)
|
|
|
|
// REST API error.
|
|
var (
|
|
Err = Error{}
|
|
|
|
ErrMovedPermanently = NewError(http.StatusMovedPermanently, "") // 301
|
|
ErrFound = NewError(http.StatusFound, "") // 302
|
|
ErrTemporaryRedirect = NewError(http.StatusTemporaryRedirect, "") // 307
|
|
ErrPermanentRedirect = NewError(http.StatusPermanentRedirect, "") // 308
|
|
|
|
ErrBadRequest = NewError(http.StatusBadRequest, "") // 400
|
|
ErrUnauthorized = NewError(http.StatusUnauthorized, "") // 401
|
|
ErrPaymentRequired = NewError(http.StatusPaymentRequired, "") // 402
|
|
ErrForbidden = NewError(http.StatusForbidden, "") // 403
|
|
ErrNotFound = NewError(http.StatusNotFound, "") // 404
|
|
ErrMethodNotAllowed = NewError(http.StatusMethodNotAllowed, "") // 405
|
|
ErrNotAcceptable = NewError(http.StatusNotAcceptable, "") // 406
|
|
|
|
ErrInternalServerError = NewError(http.StatusInternalServerError, "") // 500
|
|
ErrNotImplemented = NewError(http.StatusNotImplemented, "") // 501
|
|
ErrBadGateway = NewError(http.StatusBadGateway, "") // 502
|
|
ErrServiceUnavailable = NewError(http.StatusServiceUnavailable, "") // 503
|
|
ErrGatewayTimeout = NewError(http.StatusGatewayTimeout, "") // 504
|
|
)
|
|
|
|
// Error represents a REST API error.
|
|
// It can be marshaled to JSON with ease and provides a standard format for printing errors and additional data.
|
|
type Error struct {
|
|
StatusCode int `json:"-"` // HTTP status code (200, 404, 500 etc.)
|
|
Message string `json:"message"` // Status message ("OK", "Not found", "Internal server error" etc.)
|
|
Data map[string]interface{} `json:"data,omitempty"` // Optional additional data.
|
|
}
|
|
|
|
// Error retrieves the message of a REST API error.
|
|
func (e Error) Error() string {
|
|
return e.Message
|
|
}
|
|
|
|
// Is determines whether the Error is an instance of the target.
|
|
// https://pkg.go.dev/errors#Is
|
|
//
|
|
// If the target is a REST API error and specifies a status code, this function returns true if the status codes match.
|
|
// If the target is an empty REST API error, this function always returns true.
|
|
func (e Error) Is(target error) bool {
|
|
if t, ok := target.(Error); ok {
|
|
return t.StatusCode == e.StatusCode || t.StatusCode == 0
|
|
}
|
|
return false
|
|
}
|
|
|
|
// WithData returns a copy of the HTTP error with the given data merged in.
|
|
func (e Error) WithData(data map[string]interface{}) Error {
|
|
if e.Data == nil {
|
|
e.Data = map[string]any{}
|
|
}
|
|
for key, value := range data {
|
|
e.Data[key] = value
|
|
}
|
|
return e
|
|
}
|
|
|
|
// WithError returns a copy of the HTTP error with the given error added either as the Message, if it empty, or as additional data.
|
|
func (e Error) WithError(err error) Error {
|
|
if e.Message == "" {
|
|
return e.WithMessage(err.Error())
|
|
}
|
|
|
|
return e.WithData(map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
// WithMessage returns a copy of the HTTP error with the given message.
|
|
func (e Error) WithMessage(message string) Error {
|
|
e.Message = message
|
|
return e
|
|
}
|
|
|
|
// WithValue returns a copy of the HTTP error with a single data value added.
|
|
func (e Error) WithValue(name string, value any) Error {
|
|
return e.WithData(map[string]any{
|
|
name: value,
|
|
})
|
|
}
|
|
|
|
// Write writes the HTTP error to an HTTP response as plain text.
|
|
// Additional data is omitted.
|
|
func (e Error) Write(w http.ResponseWriter) (int, error) {
|
|
if e.StatusCode == 0 {
|
|
e.StatusCode = 200
|
|
}
|
|
w.WriteHeader(e.StatusCode)
|
|
return w.Write([]byte(e.Message))
|
|
}
|
|
|
|
// WriteJSON writes the HTTP error to an HTTP response as JSON.
|
|
func (e Error) WriteJSON(w http.ResponseWriter) error {
|
|
if e.StatusCode == 0 {
|
|
e.StatusCode = 200
|
|
}
|
|
return WriteResponseJSON(w, e.StatusCode, e)
|
|
}
|
|
|
|
// NewError creates a new REST API error.
|
|
// If the message is empty, the standard text provided by http.StatusText is substituted.
|
|
func NewError(statusCode int, message string) Error {
|
|
if len(message) == 0 {
|
|
message = http.StatusText(statusCode)
|
|
}
|
|
return Error{
|
|
StatusCode: statusCode,
|
|
Message: message,
|
|
}
|
|
}
|