Skip to content

Commit a9fac20

Browse files
virajbhartiyaAryan Tikarya
andauthored
feat: add optional data field to error returns (#123)
Co-authored-by: Aryan Tikarya <[email protected]>
1 parent c185272 commit a9fac20

File tree

7 files changed

+424
-78
lines changed

7 files changed

+424
-78
lines changed

client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ type clientResponse struct {
7171
Jsonrpc string `json:"jsonrpc"`
7272
Result json.RawMessage `json:"result"`
7373
ID interface{} `json:"id"`
74-
Error *respError `json:"error,omitempty"`
74+
Error *JSONRPCError `json:"error,omitempty"`
7575
}
7676

7777
type makeChanSink func() (context.Context, func([]byte, bool))

errors.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,8 @@ type marshalable interface {
5858
json.Marshaler
5959
json.Unmarshaler
6060
}
61+
62+
type RPCErrorCodec interface {
63+
FromJSONRPCError(JSONRPCError) error
64+
ToJSONRPCError() (JSONRPCError, error)
65+
}

handler.go

Lines changed: 17 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -65,71 +65,6 @@ type request struct {
6565
// Configured by WithMaxRequestSize.
6666
const DEFAULT_MAX_REQUEST_SIZE = 100 << 20 // 100 MiB
6767

68-
type respError struct {
69-
Code ErrorCode `json:"code"`
70-
Message string `json:"message"`
71-
Meta json.RawMessage `json:"meta,omitempty"`
72-
}
73-
74-
func (e *respError) Error() string {
75-
if e.Code >= -32768 && e.Code <= -32000 {
76-
return fmt.Sprintf("RPC error (%d): %s", e.Code, e.Message)
77-
}
78-
return e.Message
79-
}
80-
81-
var marshalableRT = reflect.TypeOf(new(marshalable)).Elem()
82-
83-
func (e *respError) val(errors *Errors) reflect.Value {
84-
if errors != nil {
85-
t, ok := errors.byCode[e.Code]
86-
if ok {
87-
var v reflect.Value
88-
if t.Kind() == reflect.Ptr {
89-
v = reflect.New(t.Elem())
90-
} else {
91-
v = reflect.New(t)
92-
}
93-
if len(e.Meta) > 0 && v.Type().Implements(marshalableRT) {
94-
_ = v.Interface().(marshalable).UnmarshalJSON(e.Meta)
95-
}
96-
if t.Kind() != reflect.Ptr {
97-
v = v.Elem()
98-
}
99-
return v
100-
}
101-
}
102-
103-
return reflect.ValueOf(e)
104-
}
105-
106-
type response struct {
107-
Jsonrpc string
108-
Result interface{}
109-
ID interface{}
110-
Error *respError
111-
}
112-
113-
func (r response) MarshalJSON() ([]byte, error) {
114-
// Custom marshal logic as per JSON-RPC 2.0 spec:
115-
// > `result`:
116-
// > This member is REQUIRED on success.
117-
// > This member MUST NOT exist if there was an error invoking the method.
118-
//
119-
// > `error`:
120-
// > This member is REQUIRED on error.
121-
// > This member MUST NOT exist if there was no error triggered during invocation.
122-
data := make(map[string]interface{})
123-
data["jsonrpc"] = r.Jsonrpc
124-
data["id"] = r.ID
125-
if r.Error != nil {
126-
data["error"] = r.Error
127-
} else {
128-
data["result"] = r.Result
129-
}
130-
return json.Marshal(data)
131-
}
132-
13368
type handler struct {
13469
methods map[string]methodHandler
13570
errors *Errors
@@ -334,7 +269,7 @@ func (s *handler) getSpan(ctx context.Context, req request) (context.Context, *t
334269
return ctx, span
335270
}
336271

337-
func (s *handler) createError(err error) *respError {
272+
func (s *handler) createError(err error) *JSONRPCError {
338273
var code ErrorCode = 1
339274
if s.errors != nil {
340275
c, ok := s.errors.byType[reflect.TypeOf(err)]
@@ -343,15 +278,25 @@ func (s *handler) createError(err error) *respError {
343278
}
344279
}
345280

346-
out := &respError{
281+
out := &JSONRPCError{
347282
Code: code,
348283
Message: err.Error(),
349284
}
350285

351-
if m, ok := err.(marshalable); ok {
352-
meta, err := m.MarshalJSON()
353-
if err == nil {
286+
switch m := err.(type) {
287+
case RPCErrorCodec:
288+
o, err := m.ToJSONRPCError()
289+
if err != nil {
290+
log.Errorf("Failed to convert error to JSONRPCError: %w", err)
291+
} else {
292+
out = &o
293+
}
294+
case marshalable:
295+
meta, marshalErr := m.MarshalJSON()
296+
if marshalErr == nil {
354297
out.Meta = meta
298+
} else {
299+
log.Errorf("Failed to marshal error metadata: %w", marshalErr)
355300
}
356301
}
357302

@@ -504,7 +449,8 @@ func (s *handler) handle(ctx context.Context, req request, w func(func(io.Writer
504449

505450
log.Warnf("failed to setup channel in RPC call to '%s': %+v", req.Method, err)
506451
stats.Record(ctx, metrics.RPCResponseError.M(1))
507-
resp.Error = &respError{
452+
453+
resp.Error = &JSONRPCError{
508454
Code: 1,
509455
Message: err.Error(),
510456
}

0 commit comments

Comments
 (0)