-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy patherrors.go
More file actions
130 lines (112 loc) · 3.52 KB
/
errors.go
File metadata and controls
130 lines (112 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package middleware
import (
"errors"
"fmt"
"net/http"
"github.com/labstack/echo/v4"
"github.com/storacha/piri/pkg/pdp/apiv2"
)
// ContextualError is a richer error interface that provides additional context
// about an error that occurred during request handling.
type ContextualError interface {
error
// StatusCode returns the HTTP status code that should be returned to the client
StatusCode() int
// LogContext returns a map of additional context for logging
LogContext() map[string]interface{}
// PublicMessage returns a message safe to return to the client
PublicMessage() string
// OriginalError returns the underlying error, if any
OriginalError() error
}
// PDPError implements the ContextualError interface
type PDPError struct {
Operation string // The operation that failed (e.g., "ProofSetAddRoot")
Message string // Internal error message (for logs)
ClientMessage string // Message safe to return to clients
Code int // HTTP status code
Err error // Original error, if any
Context map[string]interface{} // Additional context for logging
}
// Error satisfies the error interface
func (e *PDPError) Error() string {
if e.Err != nil {
return fmt.Sprintf("%s: %s: %v", e.Operation, e.Message, e.Err)
}
return fmt.Sprintf("%s: %s", e.Operation, e.Message)
}
// StatusCode returns the HTTP status code
func (e *PDPError) StatusCode() int {
return e.Code
}
// LogContext returns context information for logging
func (e *PDPError) LogContext() map[string]interface{} {
ctx := make(map[string]interface{})
for k, v := range e.Context {
ctx[k] = v
}
ctx["operation"] = e.Operation
return ctx
}
// PublicMessage returns a message safe for client consumption
func (e *PDPError) PublicMessage() string {
if e.ClientMessage != "" {
return e.ClientMessage
}
return http.StatusText(e.Code)
}
// OriginalError returns the underlying error
func (e *PDPError) OriginalError() error {
return e.Err
}
// NewError creates a new PDPError
func NewError(operation string, message string, err error, code int) *PDPError {
return &PDPError{
Operation: operation,
Message: message,
ClientMessage: message, // By default, use the same message (override for sensitive errors)
Code: code,
Err: err,
Context: make(map[string]interface{}),
}
}
func FromAPIError(operation string, err error) *PDPError {
code, msg := apiv2.GetAPIError(err)
return &PDPError{
Operation: operation,
Message: msg,
Code: code,
}
}
// WithContext adds context information to the error
func (e *PDPError) WithContext(key string, value interface{}) *PDPError {
e.Context[key] = value
return e
}
// WithPublicMessage sets a client-safe message
func (e *PDPError) WithPublicMessage(message string) *PDPError {
e.ClientMessage = message
return e
}
// HandleError converts any error to an HTTP response
// It's especially helpful for handling our custom ContextualError
func HandleError(err error, c echo.Context) {
if err == nil {
return
}
// Check if it's our custom error type
var cErr ContextualError
if errors.As(err, &cErr) {
// Return the appropriate status code and message
_ = c.String(cErr.StatusCode(), cErr.PublicMessage())
return
}
// Handle echo's HTTPError
var he *echo.HTTPError
if errors.As(err, &he) {
_ = c.String(he.Code, fmt.Sprintf("%v", he.Message))
return
}
// Generic error handling
_ = c.String(http.StatusInternalServerError, "Internal server error")
}