Skip to content

Commit

Permalink
Merge pull request #19 from picmonkey/handle-empty-list
Browse files Browse the repository at this point in the history
Serialize data as an empty array in the response when it is a non-nil empty array
  • Loading branch information
Derek Dowling committed Feb 22, 2016
2 parents a56d001 + 25be454 commit 2bfcfaf
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 6 deletions.
6 changes: 3 additions & 3 deletions document.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Refer to the JSON API Specification for a full descriptor
of each attribute: http://jsonapi.org/format/#document-structure
*/
type Document struct {
Data List `json:"data,omitempty"`
Data List `json:"data"`
Errors ErrorList `json:"errors,omitempty"`
Links *Link `json:"links,omitempty"`
Included []*Object `json:"included,omitempty"`
Expand Down Expand Up @@ -89,10 +89,10 @@ func (d *Document) Validate(r *http.Request, response bool) *Error {
return nil
}

if !d.HasErrors() && !d.HasData() {
if !d.HasErrors() && d.Data == nil {
return ISE("Both `errors` and `data` cannot be blank for a JSON response")
}
if d.HasErrors() && d.HasData() {
if d.HasErrors() && d.Data != nil {
return ISE("Both `errors` and `data` cannot be set for a JSON response")
}
if !d.HasData() && d.Included != nil {
Expand Down
14 changes: 11 additions & 3 deletions list.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,23 @@ func (list *List) UnmarshalJSON(rawData []byte) error {

/*
MarshalJSON returns a top level object for the "data" attribute if a single object. In
all other cases returns a JSON encoded list for "data".
all other cases returns a JSON encoded list for "data". We use a pointer receiver here
so we are able to distinguish between nil (don't serialize) and empty (serialize as []).
*/
func (list List) MarshalJSON() ([]byte, error) {
func (list *List) MarshalJSON() ([]byte, error) {
// avoid stack overflow by using this subtype for marshaling
type MarshalList List
marshalList := MarshalList(list)

if list == nil {
return nil, nil
}

marshalList := MarshalList(*list)
count := len(marshalList)

switch {
case count == 0:
return []byte("[]"), nil
case count == 1:
return json.Marshal(marshalList[0])
default:
Expand Down
35 changes: 35 additions & 0 deletions list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,41 @@ func TestList(t *testing.T) {
})
})

Convey("->Send(empty list)", func() {

Convey("should send a properly formatted empty List response", func() {

writer := httptest.NewRecorder()
err := Send(writer, req, List([]*Object{}))
So(err, ShouldBeNil)
So(writer.Code, ShouldEqual, http.StatusOK)

contentLength, convErr := strconv.Atoi(writer.HeaderMap.Get("Content-Length"))
So(convErr, ShouldBeNil)
So(contentLength, ShouldBeGreaterThan, 0)
So(writer.HeaderMap.Get("Content-Type"), ShouldEqual, ContentType)

req, reqErr := testRequest(writer.Body.Bytes())
So(reqErr, ShouldBeNil)

responseList, parseErr := ParseList(req)
So(parseErr, ShouldBeNil)
So(len(responseList), ShouldEqual, 0)
})
})

Convey("->Send(nil list)", func() {

Convey("should fail with a 500 ISE", func() {

writer := httptest.NewRecorder()
var list []*Object
err := Send(writer, req, List(list))
So(err, ShouldNotBeNil)
So(writer.Code, ShouldEqual, http.StatusInternalServerError)
})
})

Convey("->UnmarshalJSON()", func() {

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

0 comments on commit 2bfcfaf

Please sign in to comment.