feat(error): Create api error. WIP
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
a7b1989231
commit
77b4351ef1
109
aerr/aerr.go
Normal file
109
aerr/aerr.go
Normal file
@ -0,0 +1,109 @@
|
||||
package aerr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Error represent a API Error. It will mainly be used in the Handler.
|
||||
type Error struct {
|
||||
// shown in Json
|
||||
Code int `json:"code"`
|
||||
DebugId string `json:"debug_id"`
|
||||
Msg string `json:"message"`
|
||||
|
||||
// not in Json
|
||||
httpCode int `json:"-"`
|
||||
origin error `json:"-"`
|
||||
}
|
||||
|
||||
// Error implements error interface.
|
||||
func (e *Error) Error() string {
|
||||
s := fmt.Sprintf("Error: %d.", e.Code)
|
||||
|
||||
// if we have a message, add it
|
||||
if e.Msg != "" {
|
||||
s = fmt.Sprintf("%s Message: %s.", s, e.Msg)
|
||||
}
|
||||
|
||||
// if we have an origin message, add it.
|
||||
if e.origin != nil {
|
||||
s = fmt.Sprintf("%s Origin Message: %s.", s, e.origin.Error())
|
||||
}
|
||||
|
||||
// add debugId
|
||||
if e.DebugId != "" {
|
||||
s = fmt.Sprintf("%s - %s", s, e.DebugId)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// MarshalJSON will JSON marshal an Error. It will try to get message from the origin if there is none in the current Error.
|
||||
func (e *Error) MarshalJSON() ([]byte, error) {
|
||||
type TmpJson Error
|
||||
|
||||
// let's get the origin message if the current message is empty
|
||||
if e.Msg == "" && e.origin != nil {
|
||||
var originE *Error
|
||||
|
||||
if errors.As(e.origin, &originE) {
|
||||
e.Msg = originE.Message()
|
||||
} else {
|
||||
e.Msg = e.origin.Error()
|
||||
}
|
||||
}
|
||||
|
||||
return json.Marshal((*TmpJson)(e))
|
||||
}
|
||||
|
||||
// Add a bunch of setter / Getter
|
||||
|
||||
// SetDebugID allow to overide/set a debug Id and return the error.
|
||||
func (e *Error) SetDebugID(d string) *Error {
|
||||
e.DebugId = d
|
||||
return e
|
||||
}
|
||||
|
||||
// SetOrigin allow to set an origin error to the error and return that error.
|
||||
func (e *Error) SetOrigin(origin error) *Error {
|
||||
e.origin = origin
|
||||
return e
|
||||
}
|
||||
|
||||
// SetMessage allow to set a message to the error and return that error.
|
||||
func (e *Error) SetMessage(msg string) *Error {
|
||||
e.Msg = msg
|
||||
return e
|
||||
}
|
||||
|
||||
// SetCode allow to set a specific code to the error and return that error.
|
||||
func (e *Error) SetCode(code int) *Error {
|
||||
e.httpCode = code
|
||||
return e
|
||||
}
|
||||
|
||||
// Message will get the current error Msg. If none, it will try to go to origins until finding a message.
|
||||
func (e *Error) Message() string {
|
||||
if e.Msg == "" && e.origin != nil {
|
||||
var originE *Error
|
||||
|
||||
if errors.As(e.origin, &originE) {
|
||||
return originE.Message()
|
||||
}
|
||||
|
||||
return e.origin.Error()
|
||||
}
|
||||
return e.Msg
|
||||
}
|
||||
|
||||
// HttpCode will return the http code of the error.
|
||||
func (e *Error) HttpCode() int {
|
||||
return e.httpCode
|
||||
}
|
||||
|
||||
// Unwrap will return the origin error.
|
||||
func (e *Error) Unwrap() error {
|
||||
return e.origin
|
||||
}
|
425
aerr/client.go
Normal file
425
aerr/client.go
Normal file
@ -0,0 +1,425 @@
|
||||
package aerr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// NewBadRequest will generate an HTTP Error 400.
|
||||
func NewBadRequest() *Error {
|
||||
return &Error{
|
||||
Code: 400,
|
||||
httpCode: 400,
|
||||
Msg: "Bad Request",
|
||||
}
|
||||
}
|
||||
|
||||
// NewBadRequestf will generate an HTTP Error 400 with a custom message.
|
||||
func NewBadRequestf(format string, a ...any) *Error {
|
||||
aErr := NewBadRequest()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewUnauthorized will generate an HTTP Error 401.
|
||||
func NewUnauthorized() *Error {
|
||||
return &Error{
|
||||
Code: 401,
|
||||
httpCode: 401,
|
||||
Msg: "Unauthorized",
|
||||
}
|
||||
}
|
||||
|
||||
// NewUnauthorizedf will generate an HTTP Error 401 with a custom message.
|
||||
func NewUnauthorizedf(format string, a ...any) *Error {
|
||||
aErr := NewUnauthorized()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewPaymentRequired will generate an HTTP Error 402.
|
||||
func NewPaymentRequired() *Error {
|
||||
return &Error{
|
||||
Code: 402,
|
||||
httpCode: 402,
|
||||
Msg: "Payment Required",
|
||||
}
|
||||
}
|
||||
|
||||
// NewPaymentRequiredf will generate an HTTP Error 402 with a custom message.
|
||||
func NewPaymentRequiredf(format string, a ...any) *Error {
|
||||
aErr := NewPaymentRequired()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewForbidden will generate an HTTP Error 403.
|
||||
func NewForbidden() *Error {
|
||||
return &Error{
|
||||
Code: 403,
|
||||
httpCode: 403,
|
||||
Msg: "Forbidden",
|
||||
}
|
||||
}
|
||||
|
||||
// NewForbiddenf will generate an HTTP Error 403 with a custom message.
|
||||
func NewForbiddenf(format string, a ...any) *Error {
|
||||
aErr := NewForbidden()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewNotFound will generate an HTTP Error 404.
|
||||
func NewNotFound() *Error {
|
||||
return &Error{
|
||||
Code: 404,
|
||||
httpCode: 404,
|
||||
Msg: "Not Found",
|
||||
}
|
||||
}
|
||||
|
||||
// NewNotFoundf will generate an HTTP Error 404 with a custom message.
|
||||
func NewNotFoundf(format string, a ...any) *Error {
|
||||
aErr := NewNotFound()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewMethodNotAllowed will generate an HTTP Error 405.
|
||||
func NewMethodNotAllowed() *Error {
|
||||
return &Error{
|
||||
Code: 405,
|
||||
httpCode: 405,
|
||||
Msg: "Method Not Allowed",
|
||||
}
|
||||
}
|
||||
|
||||
// NewMethodNotAllowedf will generate an HTTP Error 405 with a custom message.
|
||||
func NewMethodNotAllowedf(format string, a ...any) *Error {
|
||||
aErr := NewMethodNotAllowed()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewNotAcceptable will generate an HTTP Error 406.
|
||||
func NewNotAcceptable() *Error {
|
||||
return &Error{
|
||||
Code: 406,
|
||||
httpCode: 406,
|
||||
Msg: "Not Acceptable",
|
||||
}
|
||||
}
|
||||
|
||||
// NewNotAcceptablef will generate an HTTP Error 406 with a custom message.
|
||||
func NewNotAcceptablef(format string, a ...any) *Error {
|
||||
aErr := NewNotAcceptable()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewProxyAuthenticationRequired will generate an HTTP Error 407.
|
||||
func NewProxyAuthenticationRequired() *Error {
|
||||
return &Error{
|
||||
Code: 407,
|
||||
httpCode: 407,
|
||||
Msg: "Proxy Authentication Required",
|
||||
}
|
||||
}
|
||||
|
||||
// NewProxyAuthenticationRequiredf will generate an HTTP Error 407 with a custom message.
|
||||
func NewProxyAuthenticationRequiredf(format string, a ...any) *Error {
|
||||
aErr := NewProxyAuthenticationRequired()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewRequestTimeout will generate an HTTP Error 408.
|
||||
func NewRequestTimeout() *Error {
|
||||
return &Error{
|
||||
Code: 408,
|
||||
httpCode: 408,
|
||||
Msg: "Request Timeout",
|
||||
}
|
||||
}
|
||||
|
||||
// NewRequestTimeoutf will generate an HTTP Error 408 with a custom message.
|
||||
func NewRequestTimeoutf(format string, a ...any) *Error {
|
||||
aErr := NewRequestTimeout()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewConflict will generate an HTTP Error 409.
|
||||
func NewConflict() *Error {
|
||||
return &Error{
|
||||
Code: 409,
|
||||
httpCode: 409,
|
||||
Msg: "Conflict",
|
||||
}
|
||||
}
|
||||
|
||||
// NewConflictf will generate an HTTP Error 409 with a custom message.
|
||||
func NewConflictf(format string, a ...any) *Error {
|
||||
aErr := NewConflict()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewGone will generate an HTTP Error 410.
|
||||
func NewGone() *Error {
|
||||
return &Error{
|
||||
Code: 410,
|
||||
httpCode: 410,
|
||||
Msg: "Gone",
|
||||
}
|
||||
}
|
||||
|
||||
// NewGonef will generate an HTTP Error 410 with a custom message.
|
||||
func NewGonef(format string, a ...any) *Error {
|
||||
aErr := NewGone()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewLengthRequired will generate an HTTP Error 411.
|
||||
func NewLengthRequired() *Error {
|
||||
return &Error{
|
||||
Code: 411,
|
||||
httpCode: 411,
|
||||
Msg: "Length Required",
|
||||
}
|
||||
}
|
||||
|
||||
// NewLengthRequiredf will generate an HTTP Error 411 with a custom message.
|
||||
func NewLengthRequiredf(format string, a ...any) *Error {
|
||||
aErr := NewLengthRequired()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewPreconditionFailed will generate an HTTP Error 412.
|
||||
func NewPreconditionFailed() *Error {
|
||||
return &Error{
|
||||
Code: 412,
|
||||
httpCode: 412,
|
||||
Msg: "Precondition Failed",
|
||||
}
|
||||
}
|
||||
|
||||
// NewPreconditionFailedf will generate an HTTP Error 412 with a custom message.
|
||||
func NewPreconditionFailedf(format string, a ...any) *Error {
|
||||
aErr := NewPreconditionFailed()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewPayloadTooLarge will generate an HTTP Error 413.
|
||||
func NewPayloadTooLarge() *Error {
|
||||
return &Error{
|
||||
Code: 413,
|
||||
httpCode: 413,
|
||||
Msg: "Payload Too Large",
|
||||
}
|
||||
}
|
||||
|
||||
// NewPayloadTooLargef will generate an HTTP Error 413 with a custom message.
|
||||
func NewPayloadTooLargef(format string, a ...any) *Error {
|
||||
aErr := NewPayloadTooLarge()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewURITooLong will generate an HTTP Error 414.
|
||||
func NewURITooLong() *Error {
|
||||
return &Error{
|
||||
Code: 414,
|
||||
httpCode: 414,
|
||||
Msg: "URI Too Long",
|
||||
}
|
||||
}
|
||||
|
||||
// NewURITooLongf will generate an HTTP Error 414 with a custom message.
|
||||
func NewURITooLongf(format string, a ...any) *Error {
|
||||
aErr := NewURITooLong()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewUnsupportedMediaType will generate an HTTP Error 415.
|
||||
func NewUnsupportedMediaType() *Error {
|
||||
return &Error{
|
||||
Code: 415,
|
||||
httpCode: 415,
|
||||
Msg: "Unsupported Media Type",
|
||||
}
|
||||
}
|
||||
|
||||
// NewUnsupportedMediaTypef will generate an HTTP Error 415 with a custom message.
|
||||
func NewUnsupportedMediaTypef(format string, a ...any) *Error {
|
||||
aErr := NewUnsupportedMediaType()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewRangeNotSatisfiable will generate an HTTP Error 416.
|
||||
func NewRangeNotSatisfiable() *Error {
|
||||
return &Error{
|
||||
Code: 416,
|
||||
httpCode: 416,
|
||||
Msg: "Range Not Satisfiable",
|
||||
}
|
||||
}
|
||||
|
||||
// NewRangeNotSatisfiablef will generate an HTTP Error 416 with a custom message.
|
||||
func NewRangeNotSatisfiablef(format string, a ...any) *Error {
|
||||
aErr := NewRangeNotSatisfiable()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewExpectationFailed will generate an HTTP Error 417.
|
||||
func NewExpectationFailed() *Error {
|
||||
return &Error{
|
||||
Code: 417,
|
||||
httpCode: 417,
|
||||
Msg: "Expectation Failed",
|
||||
}
|
||||
}
|
||||
|
||||
// NewExpectationFailedf will generate an HTTP Error 417 with a custom message.
|
||||
func NewExpectationFailedf(format string, a ...any) *Error {
|
||||
aErr := NewExpectationFailed()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewMisdirectedRequest will generate an HTTP Error 421.
|
||||
func NewMisdirectedRequest() *Error {
|
||||
return &Error{
|
||||
Code: 421,
|
||||
httpCode: 421,
|
||||
Msg: "Misdirected Request",
|
||||
}
|
||||
}
|
||||
|
||||
// NewMisdirectedRequestf will generate an HTTP Error 421 with a custom message.
|
||||
func NewMisdirectedRequestf(format string, a ...any) *Error {
|
||||
aErr := NewMisdirectedRequest()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewUnprocessableEntity will generate an HTTP Error 422.
|
||||
func NewUnprocessableEntity() *Error {
|
||||
return &Error{
|
||||
Code: 422,
|
||||
httpCode: 422,
|
||||
Msg: "Unprocessable Entity",
|
||||
}
|
||||
}
|
||||
|
||||
// NewUnprocessableEntityf will generate an HTTP Error 422 with a custom message.
|
||||
func NewUnprocessableEntityf(format string, a ...any) *Error {
|
||||
aErr := NewUnprocessableEntity()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewLocked will generate an HTTP Error 423.
|
||||
func NewLocked() *Error {
|
||||
return &Error{
|
||||
Code: 423,
|
||||
httpCode: 423,
|
||||
Msg: "Locked",
|
||||
}
|
||||
}
|
||||
|
||||
// NewLockedf will generate an HTTP Error 423 with a custom message.
|
||||
func NewLockedf(format string, a ...any) *Error {
|
||||
aErr := NewLocked()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewFailedDependency will generate an HTTP Error 424.
|
||||
func NewFailedDependency() *Error {
|
||||
return &Error{
|
||||
Code: 424,
|
||||
httpCode: 424,
|
||||
Msg: "Failed Dependency",
|
||||
}
|
||||
}
|
||||
|
||||
// NewFailedDependencyf will generate an HTTP Error 424 with a custom message.
|
||||
func NewFailedDependencyf(format string, a ...any) *Error {
|
||||
aErr := NewFailedDependency()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewTooEarly will generate an HTTP Error 425.
|
||||
func NewTooEarly() *Error {
|
||||
return &Error{
|
||||
Code: 425,
|
||||
httpCode: 425,
|
||||
Msg: "Too Early",
|
||||
}
|
||||
}
|
||||
|
||||
// NewTooEarlyf will generate an HTTP Error 425 with a custom message.
|
||||
func NewTooEarlyf(format string, a ...any) *Error {
|
||||
aErr := NewTooEarly()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewUpgradeRequired will generate an HTTP Error 426.
|
||||
func NewUpgradeRequired() *Error {
|
||||
return &Error{
|
||||
Code: 426,
|
||||
httpCode: 426,
|
||||
Msg: "Upgrade Required",
|
||||
}
|
||||
}
|
||||
|
||||
// NewUpgradeRequiredf will generate an HTTP Error 426 with a custom message.
|
||||
func NewUpgradeRequiredf(format string, a ...any) *Error {
|
||||
aErr := NewUpgradeRequired()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewPreconditionRequired will generate an HTTP Error 428.
|
||||
func NewPreconditionRequired() *Error {
|
||||
return &Error{
|
||||
Code: 428,
|
||||
httpCode: 428,
|
||||
Msg: "Precondition Required",
|
||||
}
|
||||
}
|
||||
|
||||
// NewPreconditionRequiredf will generate an HTTP Error 428 with a custom message.
|
||||
func NewPreconditionRequiredf(format string, a ...any) *Error {
|
||||
aErr := NewPreconditionRequired()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewTooManyRequests will generate an HTTP Error 429.
|
||||
func NewTooManyRequests() *Error {
|
||||
return &Error{
|
||||
Code: 429,
|
||||
httpCode: 429,
|
||||
Msg: "Too Many Requests",
|
||||
}
|
||||
}
|
||||
|
||||
// NewTooManyRequestsf will generate an HTTP Error 429 with a custom message.
|
||||
func NewTooManyRequestsf(format string, a ...any) *Error {
|
||||
aErr := NewTooManyRequests()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewRequestHeaderFieldsTooLarge will generate an HTTP Error 431.
|
||||
func NewRequestHeaderFieldsTooLarge() *Error {
|
||||
return &Error{
|
||||
Code: 431,
|
||||
httpCode: 431,
|
||||
Msg: "Request Header Fields Too Large",
|
||||
}
|
||||
}
|
||||
|
||||
// NewRequestHeaderFieldsTooLargef will generate an HTTP Error 431 with a custom message.
|
||||
func NewRequestHeaderFieldsTooLargef(format string, a ...any) *Error {
|
||||
aErr := NewRequestHeaderFieldsTooLarge()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewUnavailableForLegalReasons will generate an HTTP Error 451.
|
||||
func NewUnavailableForLegalReasons() *Error {
|
||||
return &Error{
|
||||
Code: 451,
|
||||
httpCode: 451,
|
||||
Msg: "Unavailable For Legal Reasons",
|
||||
}
|
||||
}
|
||||
|
||||
// NewUnavailableForLegalReasonsf will generate an HTTP Error 451 with a custom message.
|
||||
func NewUnavailableForLegalReasonsf(format string, a ...any) *Error {
|
||||
aErr := NewUnavailableForLegalReasons()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
28
aerr/client.txt
Normal file
28
aerr/client.txt
Normal file
@ -0,0 +1,28 @@
|
||||
400BadRequest Bad Request
|
||||
401Unauthorized Unauthorized
|
||||
402PaymentRequired Payment Required
|
||||
403Forbidden Forbidden
|
||||
404NotFound Not Found
|
||||
405MethodNotAllowed Method Not Allowed
|
||||
406NotAcceptable Not Acceptable
|
||||
407ProxyAuthenticationRequired Proxy Authentication Required
|
||||
408RequestTimeout Request Timeout
|
||||
409Conflict Conflict
|
||||
410Gone Gone
|
||||
411LengthRequired Length Required
|
||||
412PreconditionFailed Precondition Failed
|
||||
413PayloadTooLarge Payload Too Large
|
||||
414URITooLong URI Too Long
|
||||
415UnsupportedMediaType Unsupported Media Type
|
||||
416RangeNotSatisfiable Range Not Satisfiable
|
||||
417ExpectationFailed Expectation Failed
|
||||
421MisdirectedRequest Misdirected Request
|
||||
422UnprocessableEntity Unprocessable Entity
|
||||
423Locked Locked
|
||||
424FailedDependency Failed Dependency
|
||||
425TooEarly Too Early
|
||||
426UpgradeRequired Upgrade Required
|
||||
428PreconditionRequired Precondition Required
|
||||
429TooManyRequests Too Many Requests
|
||||
431RequestHeaderFieldsTooLarge Request Header Fields Too Large
|
||||
451UnavailableForLegalReasons Unavailable For Legal Reasons
|
18
aerr/note.txt
Normal file
18
aerr/note.txt
Normal file
@ -0,0 +1,18 @@
|
||||
IN
|
||||
(\d+)([a-zA-Z]+) (.*)
|
||||
|
||||
OUT
|
||||
|
||||
// New$2 will generate an HTTP Error $1.
|
||||
func New$2() *Error {
|
||||
return &Error{
|
||||
Code: $1,
|
||||
httpCode: $1,
|
||||
Msg: "$3",
|
||||
}
|
||||
}
|
||||
// New$2f will generate an HTTP Error $1 with a custom message.
|
||||
func New$2f(format string, a ...any) *Error {
|
||||
aErr := New$2()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
155
aerr/server.go
Normal file
155
aerr/server.go
Normal file
@ -0,0 +1,155 @@
|
||||
package aerr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// NewInternalServerError will generate an HTTP Error 500.
|
||||
func NewInternalServerError() *Error {
|
||||
return &Error{
|
||||
Code: 500,
|
||||
httpCode: 500,
|
||||
Msg: "Internal Server Error",
|
||||
}
|
||||
}
|
||||
|
||||
// NewInternalServerErrorf will generate an HTTP Error 500 with a custom message.
|
||||
func NewInternalServerErrorf(format string, a ...any) *Error {
|
||||
aErr := NewInternalServerError()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewNotImplemented will generate an HTTP Error 501.
|
||||
func NewNotImplemented() *Error {
|
||||
return &Error{
|
||||
Code: 501,
|
||||
httpCode: 501,
|
||||
Msg: "Not Implemented",
|
||||
}
|
||||
}
|
||||
|
||||
// NewNotImplementedf will generate an HTTP Error 501 with a custom message.
|
||||
func NewNotImplementedf(format string, a ...any) *Error {
|
||||
aErr := NewNotImplemented()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewBadGateway will generate an HTTP Error 502.
|
||||
func NewBadGateway() *Error {
|
||||
return &Error{
|
||||
Code: 502,
|
||||
httpCode: 502,
|
||||
Msg: "Bad Gateway",
|
||||
}
|
||||
}
|
||||
|
||||
// NewBadGatewayf will generate an HTTP Error 502 with a custom message.
|
||||
func NewBadGatewayf(format string, a ...any) *Error {
|
||||
aErr := NewBadGateway()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewServiceUnavailable will generate an HTTP Error 503.
|
||||
func NewServiceUnavailable() *Error {
|
||||
return &Error{
|
||||
Code: 503,
|
||||
httpCode: 503,
|
||||
Msg: "Service Unavailable",
|
||||
}
|
||||
}
|
||||
|
||||
// NewServiceUnavailablef will generate an HTTP Error 503 with a custom message.
|
||||
func NewServiceUnavailablef(format string, a ...any) *Error {
|
||||
aErr := NewServiceUnavailable()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewGatewayTimeout will generate an HTTP Error 504.
|
||||
func NewGatewayTimeout() *Error {
|
||||
return &Error{
|
||||
Code: 504,
|
||||
httpCode: 504,
|
||||
Msg: "Gateway Timeout",
|
||||
}
|
||||
}
|
||||
|
||||
// NewGatewayTimeoutf will generate an HTTP Error 504 with a custom message.
|
||||
func NewGatewayTimeoutf(format string, a ...any) *Error {
|
||||
aErr := NewGatewayTimeout()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewHTTPVersionNotSupported will generate an HTTP Error 505.
|
||||
func NewHTTPVersionNotSupported() *Error {
|
||||
return &Error{
|
||||
Code: 505,
|
||||
httpCode: 505,
|
||||
Msg: "HTTP Version Not Supported",
|
||||
}
|
||||
}
|
||||
|
||||
// NewHTTPVersionNotSupportedf will generate an HTTP Error 505 with a custom message.
|
||||
func NewHTTPVersionNotSupportedf(format string, a ...any) *Error {
|
||||
aErr := NewHTTPVersionNotSupported()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewVariantAlsoNegotiates will generate an HTTP Error 506.
|
||||
func NewVariantAlsoNegotiates() *Error {
|
||||
return &Error{
|
||||
Code: 506,
|
||||
httpCode: 506,
|
||||
Msg: "Variant Also Negotiates",
|
||||
}
|
||||
}
|
||||
|
||||
// NewVariantAlsoNegotiatesf will generate an HTTP Error 506 with a custom message.
|
||||
func NewVariantAlsoNegotiatesf(format string, a ...any) *Error {
|
||||
aErr := NewVariantAlsoNegotiates()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewInsufficientStorage will generate an HTTP Error 507.
|
||||
func NewInsufficientStorage() *Error {
|
||||
return &Error{
|
||||
Code: 507,
|
||||
httpCode: 507,
|
||||
Msg: "Insufficient Storage",
|
||||
}
|
||||
}
|
||||
|
||||
// NewInsufficientStoragef will generate an HTTP Error 507 with a custom message.
|
||||
func NewInsufficientStoragef(format string, a ...any) *Error {
|
||||
aErr := NewInsufficientStorage()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewLoopDetected will generate an HTTP Error 508.
|
||||
func NewLoopDetected() *Error {
|
||||
return &Error{
|
||||
Code: 508,
|
||||
httpCode: 508,
|
||||
Msg: "Loop Detected",
|
||||
}
|
||||
}
|
||||
|
||||
// NewLoopDetectedf will generate an HTTP Error 508 with a custom message.
|
||||
func NewLoopDetectedf(format string, a ...any) *Error {
|
||||
aErr := NewLoopDetected()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// NewNotExtended will generate an HTTP Error 510.
|
||||
func NewNotExtended() *Error {
|
||||
return &Error{
|
||||
Code: 510,
|
||||
httpCode: 510,
|
||||
Msg: "Not Extended",
|
||||
}
|
||||
}
|
||||
|
||||
// NewNotExtendedf will generate an HTTP Error 510 with a custom message.
|
||||
func NewNotExtendedf(format string, a ...any) *Error {
|
||||
aErr := NewNotExtended()
|
||||
return aErr.SetMessage(fmt.Sprintf(format, a...))
|
||||
}
|
10
aerr/server.txt
Normal file
10
aerr/server.txt
Normal file
@ -0,0 +1,10 @@
|
||||
500InternalServerError Internal Server Error
|
||||
501NotImplemented Not Implemented
|
||||
502BadGateway Bad Gateway
|
||||
503ServiceUnavailable Service Unavailable
|
||||
504GatewayTimeout Gateway Timeout
|
||||
505HTTPVersionNotSupported HTTP Version Not Supported
|
||||
506VariantAlsoNegotiates Variant Also Negotiates
|
||||
507InsufficientStorage Insufficient Storage
|
||||
508LoopDetected Loop Detected
|
||||
510NotExtended Not Extended
|
@ -12,7 +12,12 @@ func AddRequestID(ctx context.Context, requestID string) context.Context {
|
||||
// GetRequestID retrieve a requestID from the context.
|
||||
func GetRequestID(ctx context.Context) *string {
|
||||
if requestID := ctx.Value(ContextKey_RequestID); requestID != nil {
|
||||
return requestID.(*string)
|
||||
requestIDStr, cast := requestID.(string)
|
||||
if !cast {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &requestIDStr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package ginutils
|
||||
package constant
|
||||
|
||||
type contextKey string
|
||||
|
||||
@ -28,4 +28,6 @@ const (
|
||||
LogField_Username logField = "username"
|
||||
LogField_IP logField = "real_ip"
|
||||
LogField_Duration logField = "duration_ms"
|
||||
LogField_Error logField = "error"
|
||||
LogField_ErrorCode logField = "error_code"
|
||||
)
|
@ -1,6 +1,8 @@
|
||||
package ginutils
|
||||
|
||||
import (
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/aerr"
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@ -8,15 +10,12 @@ import (
|
||||
func SimpleTokens(tokens []string, forbiddenHandler gin.HandlerFunc) gin.HandlerFunc {
|
||||
if forbiddenHandler == nil {
|
||||
forbiddenHandler = func(c *gin.Context) {
|
||||
c.AbortWithStatusJSON(403, map[string]string{
|
||||
"message": "Forbidden",
|
||||
"debugId": c.GetString(string(ContextKey_RequestID)),
|
||||
})
|
||||
errorHandler(c, aerr.NewForbidden())
|
||||
}
|
||||
}
|
||||
return func(c *gin.Context) {
|
||||
|
||||
requestToken := c.GetHeader(string(HeaderKey_Token))
|
||||
requestToken := c.GetHeader(string(constant.HeaderKey_Token))
|
||||
isAuthorized := false
|
||||
for _, key := range tokens {
|
||||
if key == requestToken {
|
||||
|
@ -3,6 +3,7 @@ package ginutils
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/constant"
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/webserver"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -16,17 +17,17 @@ func Log(l *logrus.Entry) gin.HandlerFunc {
|
||||
|
||||
// construct default fields
|
||||
fields := logrus.Fields{
|
||||
string(LogField_IP): webserver.GetClientIP(c.Request),
|
||||
string(constant.LogField_IP): webserver.GetClientIP(c.Request),
|
||||
// Request information
|
||||
string(LogField_Method): c.Request.Method,
|
||||
string(LogField_CanonPath): c.FullPath(),
|
||||
string(LogField_Path): c.Request.URL.String(),
|
||||
string(LogField_RequestID): c.GetString(string(ContextKey_RequestID)),
|
||||
string(constant.LogField_Method): c.Request.Method,
|
||||
string(constant.LogField_CanonPath): c.FullPath(),
|
||||
string(constant.LogField_Path): c.Request.URL.String(),
|
||||
string(constant.LogField_RequestID): c.GetString(string(constant.ContextKey_RequestID)),
|
||||
}
|
||||
|
||||
// create the logrus entry and add it to gin context
|
||||
log := l.Logger.WithFields(fields)
|
||||
c.Set(string(ContextKey_Logger), log)
|
||||
c.Set(string(constant.ContextKey_Logger), log)
|
||||
|
||||
log.Info("[start]")
|
||||
|
||||
@ -34,15 +35,15 @@ func Log(l *logrus.Entry) gin.HandlerFunc {
|
||||
|
||||
log.WithFields(
|
||||
logrus.Fields{
|
||||
string(LogField_Duration): time.Since(start).Microseconds(),
|
||||
string(LogField_StatusCode): c.Writer.Status(),
|
||||
string(constant.LogField_Duration): time.Since(start).Microseconds(),
|
||||
string(constant.LogField_StatusCode): c.Writer.Status(),
|
||||
}).Info("[end]")
|
||||
}
|
||||
}
|
||||
|
||||
// GetLogger will retrieve a logger instance from gin context and return it or return false.
|
||||
func GetLogger(c *gin.Context) (*logrus.Entry, bool) {
|
||||
if log, exist := c.Get(string(ContextKey_Logger)); exist {
|
||||
if log, exist := c.Get(string(constant.ContextKey_Logger)); exist {
|
||||
return log.(*logrus.Entry), true
|
||||
}
|
||||
|
||||
@ -51,7 +52,7 @@ func GetLogger(c *gin.Context) (*logrus.Entry, bool) {
|
||||
|
||||
// GetLoggerWithField will add a key and value field to the logger, update the gin context, and return the new logger.
|
||||
func GetLoggerWithField(c *gin.Context, key string, value interface{}) *logrus.Entry {
|
||||
iLog, exist := c.Get(string(ContextKey_Logger))
|
||||
iLog, exist := c.Get(string(constant.ContextKey_Logger))
|
||||
if !exist {
|
||||
panic("no logger in context")
|
||||
}
|
||||
@ -62,13 +63,13 @@ func GetLoggerWithField(c *gin.Context, key string, value interface{}) *logrus.E
|
||||
}
|
||||
|
||||
log = log.WithField(key, value)
|
||||
c.Set(string(ContextKey_Logger), log)
|
||||
c.Set(string(constant.ContextKey_Logger), log)
|
||||
return log
|
||||
}
|
||||
|
||||
// GetLoggerWithFields will add provided fields to the logger, update the gin context, and return the new logger.
|
||||
func GetLoggerWithFields(c *gin.Context, fields logrus.Fields) *logrus.Entry {
|
||||
iLog, exist := c.Get(string(ContextKey_Logger))
|
||||
iLog, exist := c.Get(string(constant.ContextKey_Logger))
|
||||
if !exist {
|
||||
panic("no logger in context")
|
||||
}
|
||||
@ -79,6 +80,6 @@ func GetLoggerWithFields(c *gin.Context, fields logrus.Fields) *logrus.Entry {
|
||||
}
|
||||
|
||||
log = log.WithFields(fields)
|
||||
c.Set(string(ContextKey_Logger), log)
|
||||
c.Set(string(constant.ContextKey_Logger), log)
|
||||
return log
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/aerr"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -15,10 +16,7 @@ import (
|
||||
func Recovery(handler gin.HandlerFunc) gin.HandlerFunc {
|
||||
if handler == nil {
|
||||
handler = func(c *gin.Context) {
|
||||
c.AbortWithStatusJSON(500, map[string]string{
|
||||
"message": "Internal Server Error",
|
||||
"debugId": c.GetString(string(ContextKey_RequestID)),
|
||||
})
|
||||
errorHandler(c, aerr.NewInternalServerError())
|
||||
}
|
||||
}
|
||||
return func(c *gin.Context) {
|
||||
@ -37,7 +35,6 @@ func Recovery(handler gin.HandlerFunc) gin.HandlerFunc {
|
||||
}
|
||||
}()
|
||||
c.Next()
|
||||
gin.Recovery()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package ginutils
|
||||
|
||||
import (
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
@ -10,16 +11,16 @@ import (
|
||||
func RequestID() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
requestID := c.GetHeader(string(HeaderKey_RequestID))
|
||||
requestID := c.GetHeader(string(constant.HeaderKey_RequestID))
|
||||
if _, err := uuid.Parse(requestID); err != nil {
|
||||
// no request ID or invalid. let's generate a new one
|
||||
requestID = uuid.New().String()
|
||||
}
|
||||
|
||||
// Adding to context
|
||||
c.Set(string(ContextKey_RequestID), requestID)
|
||||
c.Set(string(constant.ContextKey_RequestID), requestID)
|
||||
// Add request-id to the header before sending the response
|
||||
c.Header(string(HeaderKey_RequestID), requestID)
|
||||
c.Header(string(constant.HeaderKey_RequestID), requestID)
|
||||
// Let's the next part run
|
||||
c.Next()
|
||||
}
|
||||
|
50
ginutils/wrapper.go
Normal file
50
ginutils/wrapper.go
Normal file
@ -0,0 +1,50 @@
|
||||
package ginutils
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/aerr"
|
||||
"git.dev.m-and-m.ovh/mderasse/gocommon/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// HandlerFunc represent the type of function expected by the wrapper.
|
||||
type HandlerFunc func(*gin.Context) error
|
||||
|
||||
// HandlerWrapper will wrap a handler to handle error.
|
||||
func HandlerWrapper(h HandlerFunc) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
err := h(c)
|
||||
if err != nil {
|
||||
errorHandler(c, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func errorHandler(c *gin.Context, err error) {
|
||||
//nolint: errorlint // Ignore linter to avoid creating useless complexity in the code.
|
||||
switch e := err.(type) {
|
||||
case *aerr.Error:
|
||||
log := GetLoggerWithFields(c, logrus.Fields{
|
||||
string(constant.LogField_Error): e.Error(),
|
||||
string(constant.LogField_ErrorCode): e.Code,
|
||||
})
|
||||
log.Warn("An error occurred")
|
||||
if e.DebugId == "" {
|
||||
e = e.SetDebugID(c.GetString(string(constant.ContextKey_RequestID)))
|
||||
}
|
||||
c.AbortWithStatusJSON(e.HttpCode(), e)
|
||||
default:
|
||||
log := GetLoggerWithFields(c, logrus.Fields{
|
||||
string(constant.LogField_Error): e.Error(),
|
||||
string(constant.LogField_ErrorCode): "500",
|
||||
})
|
||||
log.Warn("An error occurred")
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, aerr.Error{
|
||||
Msg: e.Error(),
|
||||
Code: 500,
|
||||
DebugId: c.GetString(string(constant.ContextKey_RequestID)),
|
||||
})
|
||||
}
|
||||
}
|
4
go.mod
4
go.mod
@ -6,7 +6,7 @@ require (
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
|
||||
github.com/gemnasium/logrus-graylog-hook/v3 v3.1.1
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/google/uuid v1.3.1
|
||||
github.com/juju/errors v1.0.0
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
@ -27,7 +27,7 @@ require (
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.15.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.15.1 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/jonboulle/clockwork v0.3.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
|
8
go.sum
8
go.sum
@ -32,8 +32,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.15.0 h1:nDU5XeOKtB3GEa+uB7GNYwhVKsgjAR7VgKoNB6ryXfw=
|
||||
github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2raYcGffYWZEjZzM=
|
||||
github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
@ -41,8 +41,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg=
|
||||
github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
|
Loading…
Reference in New Issue
Block a user