Skip to content

Commit

Permalink
Omit data field from error when empty (#66)
Browse files Browse the repository at this point in the history
The JSON-RPC 2.0 specification allows the data member of an error object
to be omitted. Before this commit, if Error.Data was nil then the JSON
encoding was "null". That means that the data member was included in
every JSON-RPC error object, even when the data member was not
explicitly set.

This commit adds the omitempty struct tag to the Error.Data field,
meaning that the data member is omitted from the JSON encoding unless
explicitly set with the Error.SetError() method. Beware that this is a
breaking change for clients that may have strict null checks on the data
member.
  • Loading branch information
samherrmann authored Feb 12, 2023
1 parent 846c29e commit 6864d8c
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 2 deletions.
4 changes: 2 additions & 2 deletions jsonrpc2.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ type JSONRPC2 interface {
type Error struct {
Code int64 `json:"code"`
Message string `json:"message"`
Data *json.RawMessage `json:"data"`
Data *json.RawMessage `json:"data,omitempty"`
}

// SetError sets e.Error to the JSON representation of v. If JSON
// SetError sets e.Data to the JSON representation of v. If JSON
// marshaling fails, it panics.
func (e *Error) SetError(v interface{}) {
b, err := json.Marshal(v)
Expand Down
59 changes: 59 additions & 0 deletions jsonrpc2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,65 @@ import (
websocketjsonrpc2 "github.com/sourcegraph/jsonrpc2/websocket"
)

func TestError_MarshalJSON(t *testing.T) {
tests := []struct {
name string
setError func(err *jsonrpc2.Error)
want string
}{
{
name: "Data == nil",
want: `{"code":-32603,"message":"Internal error"}`,
},
{
name: "Error.SetError(nil)",
setError: func(err *jsonrpc2.Error) {
err.SetError(nil)
},
want: `{"code":-32603,"message":"Internal error","data":null}`,
},
{
name: "Error.SetError(0)",
setError: func(err *jsonrpc2.Error) {
err.SetError(0)
},
want: `{"code":-32603,"message":"Internal error","data":0}`,
},
{
name: `Error.SetError("")`,
setError: func(err *jsonrpc2.Error) {
err.SetError("")
},
want: `{"code":-32603,"message":"Internal error","data":""}`,
},
{
name: `Error.SetError(false)`,
setError: func(err *jsonrpc2.Error) {
err.SetError(false)
},
want: `{"code":-32603,"message":"Internal error","data":false}`,
},
}

for _, test := range tests {
e := &jsonrpc2.Error{
Code: jsonrpc2.CodeInternalError,
Message: "Internal error",
}
if test.setError != nil {
test.setError(e)
}
b, err := json.Marshal(e)
if err != nil {
t.Error(err)
}
got := string(b)
if got != test.want {
t.Fatalf("%s: got %q, want %q", test.name, got, test.want)
}
}
}

// testHandlerA is the "server" handler.
type testHandlerA struct{ t *testing.T }

Expand Down

0 comments on commit 6864d8c

Please sign in to comment.