1
0
Fork 0
mirror of https://github.com/sourcegraph/jsonrpc2.git synced 2026-06-16 04:04:56 +02:00

Omit data field from error when empty

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.
This commit is contained in:
Sam Herrmann 2023-02-09 12:30:36 -05:00
parent 846c29e96d
commit 243eedf323
2 changed files with 61 additions and 2 deletions

View file

@ -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)

View file

@ -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 }