Skip to content

Commit 1a0e322

Browse files
authored
fix: allow JSON-RPC error data in responses (#56)
Passes JSON-RPC error `Data` through server responses when a method returns it. Adds a new method `writeJSONRPCErrorWithData`. Alternatives: This is simpler than changing `writeJSONRPCError` everywhere and passing Data as `nil`.
1 parent 9643d5e commit 1a0e322

2 files changed

Lines changed: 37 additions & 2 deletions

File tree

rpcserver/jsonrpc_server.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,14 +157,22 @@ func (h *JSONRPCHandler) writeJSONRPCResponse(w http.ResponseWriter, response JS
157157
}
158158

159159
func (h *JSONRPCHandler) writeJSONRPCError(w http.ResponseWriter, id any, code int, msg string) {
160+
h.writeJSONRPCErrorWithData(w, id, code, msg, nil)
161+
}
162+
163+
func (h *JSONRPCHandler) writeJSONRPCErrorWithData(w http.ResponseWriter, id any, code int, msg string, data any) {
164+
var dataPtr *any
165+
if data != nil {
166+
dataPtr = &data
167+
}
160168
res := JSONRPCResponse{
161169
JSONRPC: "2.0",
162170
ID: id,
163171
Result: nil,
164172
Error: &JSONRPCError{
165173
Code: code,
166174
Message: msg,
167-
Data: nil,
175+
Data: dataPtr,
168176
},
169177
}
170178
h.writeJSONRPCResponse(w, res)
@@ -351,7 +359,7 @@ func (h *JSONRPCHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
351359
result, err := method.call(ctx, req.Params)
352360
if err != nil {
353361
if jsonRPCErr, ok := err.(*JSONRPCError); ok {
354-
h.writeJSONRPCError(w, req.ID, jsonRPCErr.Code, jsonRPCErr.Message)
362+
h.writeJSONRPCErrorWithData(w, req.ID, jsonRPCErr.Code, jsonRPCErr.Message, jsonRPCErr.Data)
355363
} else {
356364
h.writeJSONRPCError(w, req.ID, CodeCustomError, err.Error())
357365
}

rpcserver/jsonrpc_server_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,33 @@ func TestJSONRPCServerDefaultLiveAndReady(t *testing.T) {
143143
require.Equal(t, http.StatusNotFound, rr.Code)
144144
}
145145

146+
func TestJSONRPCErrorDataIsPreserved(t *testing.T) {
147+
handlerMethod := func(ctx context.Context, arg int) (int, error) {
148+
errorData := any("some error data")
149+
return 0, &JSONRPCError{
150+
Code: 1234,
151+
Message: "test error",
152+
Data: &errorData,
153+
}
154+
}
155+
156+
handler, err := NewJSONRPCHandler(map[string]interface{}{
157+
"testError": handlerMethod,
158+
}, JSONRPCHandlerOpts{})
159+
require.NoError(t, err)
160+
161+
httpServer := httptest.NewServer(handler)
162+
defer httpServer.Close()
163+
164+
client := rpcclient.NewClient(httpServer.URL)
165+
resp, err := client.Call(context.Background(), "testError", 1)
166+
require.NoError(t, err)
167+
require.NotNil(t, resp.Error)
168+
require.Equal(t, 1234, resp.Error.Code)
169+
require.Equal(t, "test error", resp.Error.Message)
170+
require.Equal(t, "some error data", resp.Error.Data)
171+
}
172+
146173
func TestJSONRPCServerReadyzOK(t *testing.T) {
147174
handler := testHandler(JSONRPCHandlerOpts{
148175
ReadyHandler: func(w http.ResponseWriter, r *http.Request) error {

0 commit comments

Comments
 (0)