error.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package rest
  2. import (
  3. "net/http"
  4. )
  5. // REST API error.
  6. var (
  7. Err = Error{}
  8. ErrMovedPermanently = NewError(http.StatusMovedPermanently, "") // 301
  9. ErrFound = NewError(http.StatusFound, "") // 302
  10. ErrTemporaryRedirect = NewError(http.StatusTemporaryRedirect, "") // 307
  11. ErrPermamentRedirect = NewError(http.StatusPermanentRedirect, "") // 308
  12. ErrBadRequest = NewError(http.StatusBadRequest, "") // 400
  13. ErrUnauthorized = NewError(http.StatusUnauthorized, "") // 401
  14. ErrPaymentRequired = NewError(http.StatusPaymentRequired, "") // 402
  15. ErrForbidden = NewError(http.StatusForbidden, "") // 403
  16. ErrNotFound = NewError(http.StatusNotFound, "") // 404
  17. ErrMethodNotAllowed = NewError(http.StatusMethodNotAllowed, "") // 405
  18. ErrNotAcceptable = NewError(http.StatusNotAcceptable, "") // 406
  19. ErrInternalServerError = NewError(http.StatusInternalServerError, "") // 500
  20. ErrNotImplemented = NewError(http.StatusNotImplemented, "") // 501
  21. ErrBadGateway = NewError(http.StatusBadGateway, "") // 502
  22. ErrServiceUnavailable = NewError(http.StatusServiceUnavailable, "") // 503
  23. ErrGatewayTimeout = NewError(http.StatusGatewayTimeout, "") // 504
  24. )
  25. // Error represents a REST API error.
  26. // It can be marshaled to JSON with ease and provides a standard format for printing errors and additional data.
  27. type Error struct {
  28. StatusCode int `json:"statusCode"` // HTTP status code (200, 404, 500 etc.)
  29. Message string `json:"message"` // Status message ("OK", "Not found", "Internal server error" etc.)
  30. Data map[string]interface{} `json:"data,omitempty"` // Optional additional data.
  31. }
  32. // Error retrieves the message of a REST API Error.
  33. // If it has a "error" string attached using WithData or WithError, that message is returned.
  34. // Otherwise, the Error's own message is returned.
  35. func (e Error) Error() string {
  36. if e.Data != nil && e.Data["error"] != nil {
  37. if value, ok := e.Data["error"].(string); ok {
  38. return value
  39. }
  40. }
  41. return e.Message
  42. }
  43. // Is determines whether the Error is an instance of the target.
  44. // https://pkg.go.dev/errors#Is
  45. //
  46. // If the target is a REST API error and specifies a status code, this function returns true if the status codes match.
  47. // If the target is an empty REST API error, this function always returns true.
  48. func (e Error) Is(target error) bool {
  49. t, ok := target.(Error)
  50. if !ok {
  51. return false
  52. }
  53. if t.StatusCode == 0 {
  54. return true
  55. }
  56. return t.StatusCode == e.StatusCode
  57. }
  58. // WithData returns a copy of the HTTP error with the given data merged in.
  59. func (e Error) WithData(data map[string]interface{}) Error {
  60. if e.Data == nil {
  61. e.Data = map[string]any{}
  62. }
  63. if data != nil {
  64. for key, value := range data {
  65. e.Data[key] = value
  66. }
  67. }
  68. return e
  69. }
  70. // WithError returns a copy of the HTTP error with the given error's message merged in to its additional data.
  71. func (e Error) WithError(err error) Error {
  72. return e.WithData(map[string]interface{}{
  73. "error": err.Error(),
  74. })
  75. }
  76. // WithMessage returns a copy of the HTTP error with the given message.
  77. func (e Error) WithMessage(message string) Error {
  78. e.Message = message
  79. return e
  80. }
  81. // WithValue returns a copy of the HTTP error with a single data value added.
  82. func (e Error) WithValue(name string, value any) Error {
  83. return e.WithData(map[string]any{
  84. name: value,
  85. })
  86. }
  87. // Write writes the HTTP error to an HTTP response as plain text.
  88. // Additional data is omitted.
  89. func (e Error) Write(w http.ResponseWriter) {
  90. w.WriteHeader(e.StatusCode)
  91. w.Write([]byte(e.Message))
  92. }
  93. // WriteJSON writes the HTTP error to an HTTP response as JSON.
  94. func (e Error) WriteJSON(w http.ResponseWriter) error {
  95. return WriteResponseJSON(w, e.StatusCode, e)
  96. }
  97. // NewError creates a new REST API error.
  98. // If the message is empty, the standard text provided by http.StatusText is substituted.
  99. func NewError(statusCode int, message string) Error {
  100. if len(message) == 0 {
  101. message = http.StatusText(statusCode)
  102. }
  103. return Error{
  104. StatusCode: statusCode,
  105. Message: message,
  106. }
  107. }