register.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package errcode
  2. import (
  3. "fmt"
  4. "net/http"
  5. "sort"
  6. "sync"
  7. )
  8. var (
  9. errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{}
  10. idToDescriptors = map[string]ErrorDescriptor{}
  11. groupToDescriptors = map[string][]ErrorDescriptor{}
  12. )
  13. var (
  14. // ErrorCodeUnknown is a generic error that can be used as a last
  15. // resort if there is no situation-specific error message that can be used
  16. ErrorCodeUnknown = Register("errcode", ErrorDescriptor{
  17. Value: "UNKNOWN",
  18. Message: "unknown error",
  19. Description: `Generic error returned when the error does not have an
  20. API classification.`,
  21. HTTPStatusCode: http.StatusInternalServerError,
  22. })
  23. // ErrorCodeUnsupported is returned when an operation is not supported.
  24. ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{
  25. Value: "UNSUPPORTED",
  26. Message: "The operation is unsupported.",
  27. Description: `The operation was unsupported due to a missing
  28. implementation or invalid set of parameters.`,
  29. HTTPStatusCode: http.StatusMethodNotAllowed,
  30. })
  31. // ErrorCodeUnauthorized is returned if a request requires
  32. // authentication.
  33. ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{
  34. Value: "UNAUTHORIZED",
  35. Message: "authentication required",
  36. Description: `The access controller was unable to authenticate
  37. the client. Often this will be accompanied by a
  38. Www-Authenticate HTTP response header indicating how to
  39. authenticate.`,
  40. HTTPStatusCode: http.StatusUnauthorized,
  41. })
  42. // ErrorCodeDenied is returned if a client does not have sufficient
  43. // permission to perform an action.
  44. ErrorCodeDenied = Register("errcode", ErrorDescriptor{
  45. Value: "DENIED",
  46. Message: "requested access to the resource is denied",
  47. Description: `The access controller denied access for the
  48. operation on a resource.`,
  49. HTTPStatusCode: http.StatusForbidden,
  50. })
  51. // ErrorCodeUnavailable provides a common error to report unavailability
  52. // of a service or endpoint.
  53. ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{
  54. Value: "UNAVAILABLE",
  55. Message: "service unavailable",
  56. Description: "Returned when a service is not available",
  57. HTTPStatusCode: http.StatusServiceUnavailable,
  58. })
  59. // ErrorCodeTooManyRequests is returned if a client attempts too many
  60. // times to contact a service endpoint.
  61. ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{
  62. Value: "TOOMANYREQUESTS",
  63. Message: "too many requests",
  64. Description: `Returned when a client attempts to contact a
  65. service too many times`,
  66. HTTPStatusCode: http.StatusTooManyRequests,
  67. })
  68. )
  69. var nextCode = 1000
  70. var registerLock sync.Mutex
  71. // Register will make the passed-in error known to the environment and
  72. // return a new ErrorCode
  73. func Register(group string, descriptor ErrorDescriptor) ErrorCode {
  74. registerLock.Lock()
  75. defer registerLock.Unlock()
  76. descriptor.Code = ErrorCode(nextCode)
  77. if _, ok := idToDescriptors[descriptor.Value]; ok {
  78. panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value))
  79. }
  80. if _, ok := errorCodeToDescriptors[descriptor.Code]; ok {
  81. panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code))
  82. }
  83. groupToDescriptors[group] = append(groupToDescriptors[group], descriptor)
  84. errorCodeToDescriptors[descriptor.Code] = descriptor
  85. idToDescriptors[descriptor.Value] = descriptor
  86. nextCode++
  87. return descriptor.Code
  88. }
  89. type byValue []ErrorDescriptor
  90. func (a byValue) Len() int { return len(a) }
  91. func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  92. func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value }
  93. // GetGroupNames returns the list of Error group names that are registered
  94. func GetGroupNames() []string {
  95. keys := []string{}
  96. for k := range groupToDescriptors {
  97. keys = append(keys, k)
  98. }
  99. sort.Strings(keys)
  100. return keys
  101. }
  102. // GetErrorCodeGroup returns the named group of error descriptors
  103. func GetErrorCodeGroup(name string) []ErrorDescriptor {
  104. desc := groupToDescriptors[name]
  105. sort.Sort(byValue(desc))
  106. return desc
  107. }
  108. // GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are
  109. // registered, irrespective of what group they're in
  110. func GetErrorAllDescriptors() []ErrorDescriptor {
  111. result := []ErrorDescriptor{}
  112. for _, group := range GetGroupNames() {
  113. result = append(result, GetErrorCodeGroup(group)...)
  114. }
  115. sort.Sort(byValue(result))
  116. return result
  117. }