Skip to content

Commit 2bfcfaf

Browse files
author
Derek Dowling
committed
Merge pull request #19 from picmonkey/handle-empty-list
Serialize data as an empty array in the response when it is a non-nil empty array
2 parents a56d001 + 25be454 commit 2bfcfaf

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

document.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Refer to the JSON API Specification for a full descriptor
1212
of each attribute: http://jsonapi.org/format/#document-structure
1313
*/
1414
type Document struct {
15-
Data List `json:"data,omitempty"`
15+
Data List `json:"data"`
1616
Errors ErrorList `json:"errors,omitempty"`
1717
Links *Link `json:"links,omitempty"`
1818
Included []*Object `json:"included,omitempty"`
@@ -89,10 +89,10 @@ func (d *Document) Validate(r *http.Request, response bool) *Error {
8989
return nil
9090
}
9191

92-
if !d.HasErrors() && !d.HasData() {
92+
if !d.HasErrors() && d.Data == nil {
9393
return ISE("Both `errors` and `data` cannot be blank for a JSON response")
9494
}
95-
if d.HasErrors() && d.HasData() {
95+
if d.HasErrors() && d.Data != nil {
9696
return ISE("Both `errors` and `data` cannot be set for a JSON response")
9797
}
9898
if !d.HasData() && d.Included != nil {

list.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,23 @@ func (list *List) UnmarshalJSON(rawData []byte) error {
5353

5454
/*
5555
MarshalJSON returns a top level object for the "data" attribute if a single object. In
56-
all other cases returns a JSON encoded list for "data".
56+
all other cases returns a JSON encoded list for "data". We use a pointer receiver here
57+
so we are able to distinguish between nil (don't serialize) and empty (serialize as []).
5758
*/
58-
func (list List) MarshalJSON() ([]byte, error) {
59+
func (list *List) MarshalJSON() ([]byte, error) {
5960
// avoid stack overflow by using this subtype for marshaling
6061
type MarshalList List
61-
marshalList := MarshalList(list)
62+
63+
if list == nil {
64+
return nil, nil
65+
}
66+
67+
marshalList := MarshalList(*list)
6268
count := len(marshalList)
6369

6470
switch {
71+
case count == 0:
72+
return []byte("[]"), nil
6573
case count == 1:
6674
return json.Marshal(marshalList[0])
6775
default:

list_test.go

+35
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,41 @@ func TestList(t *testing.T) {
5151
})
5252
})
5353

54+
Convey("->Send(empty list)", func() {
55+
56+
Convey("should send a properly formatted empty List response", func() {
57+
58+
writer := httptest.NewRecorder()
59+
err := Send(writer, req, List([]*Object{}))
60+
So(err, ShouldBeNil)
61+
So(writer.Code, ShouldEqual, http.StatusOK)
62+
63+
contentLength, convErr := strconv.Atoi(writer.HeaderMap.Get("Content-Length"))
64+
So(convErr, ShouldBeNil)
65+
So(contentLength, ShouldBeGreaterThan, 0)
66+
So(writer.HeaderMap.Get("Content-Type"), ShouldEqual, ContentType)
67+
68+
req, reqErr := testRequest(writer.Body.Bytes())
69+
So(reqErr, ShouldBeNil)
70+
71+
responseList, parseErr := ParseList(req)
72+
So(parseErr, ShouldBeNil)
73+
So(len(responseList), ShouldEqual, 0)
74+
})
75+
})
76+
77+
Convey("->Send(nil list)", func() {
78+
79+
Convey("should fail with a 500 ISE", func() {
80+
81+
writer := httptest.NewRecorder()
82+
var list []*Object
83+
err := Send(writer, req, List(list))
84+
So(err, ShouldNotBeNil)
85+
So(writer.Code, ShouldEqual, http.StatusInternalServerError)
86+
})
87+
})
88+
5489
Convey("->UnmarshalJSON()", func() {
5590

5691
Convey("should handle a data object", func() {

0 commit comments

Comments
 (0)