123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- // Package webhook provides functionality for sending and validating webhooks
- package webhook
- import (
- "errors"
- "fmt"
- "net/http"
- )
- // Common webhook error types
- var (
- // ErrInvalidConfig indicates missing or invalid configuration values
- ErrInvalidConfig = errors.New("invalid webhook configuration")
- // ErrPayloadMarshall indicates a failure to marshal the webhook payload
- ErrPayloadMarshall = errors.New("failed to marshal webhook payload")
- // ErrRequestCreation indicates a failure to create the HTTP request
- ErrRequestCreation = errors.New("failed to create webhook request")
- // ErrRequestFailed indicates a permanent failure in the webhook request
- ErrRequestFailed = errors.New("webhook request failed")
- // ErrTooManyRequests indicates rate limiting by the webhook endpoint
- ErrTooManyRequests = errors.New("rate limit exceeded")
- // ErrMaxRetriesReached indicates all retry attempts have been exhausted
- ErrMaxRetriesReached = errors.New("maximum retries reached")
- // ErrInvalidSignature indicates webhook signature validation failed
- ErrInvalidSignature = errors.New("invalid webhook signature")
- )
- // Error represents a webhook-specific error with detailed context
- type Error struct {
- // Op is the operation that failed (e.g., "send", "validate")
- Op string
- // Code is the HTTP status code (if applicable)
- Code int
- // Err is the underlying error
- Err error
- // Details contains additional error context
- Details string
- }
- // Error returns a string representation of the error
- func (e *Error) Error() string {
- var msg string
- if e.Code > 0 {
- msg = fmt.Sprintf("webhook %s failed with status %d", e.Op, e.Code)
- } else {
- msg = fmt.Sprintf("webhook %s failed", e.Op)
- }
- if e.Details != "" {
- msg = fmt.Sprintf("%s: %s", msg, e.Details)
- }
- if e.Err != nil {
- msg = fmt.Sprintf("%s: %v", msg, e.Err)
- }
- return msg
- }
- // Unwrap returns the underlying error
- func (e *Error) Unwrap() error {
- return e.Err
- }
- // Is reports whether target matches this error
- func (e *Error) Is(target error) bool {
- return errors.Is(e.Err, target)
- }
- // NewError creates a new webhook error
- func NewError(op string, err error, details string) *Error {
- return &Error{
- Op: op,
- Err: err,
- Details: details,
- }
- }
- // NewHTTPError creates a new webhook error with HTTP status code
- func NewHTTPError(op string, code int, err error, details string) *Error {
- return &Error{
- Op: op,
- Code: code,
- Err: err,
- Details: details,
- }
- }
- // IsTemporaryError returns true if the error is temporary and the operation can be retried
- func IsTemporaryError(err error) bool {
- var e *Error
- if errors.As(err, &e) {
- return e.Code == http.StatusTooManyRequests ||
- (e.Code >= 500 && e.Code <= 599) ||
- e.Is(ErrTooManyRequests)
- }
- return false
- }
|