Skip to content

Commit 4ebf344

Browse files
committed
Fixes panic when a has-many relation contains nil
1 parent 43b65c2 commit 4ebf344

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

response.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ var (
2626
// ErrUnexpectedType is returned when marshalling an interface; the interface
2727
// had to be a pointer or a slice; otherwise this error is returned.
2828
ErrUnexpectedType = errors.New("models should be a struct pointer or slice of struct pointers")
29+
// ErrUnexpectedNil is returned when a slice of relation structs contains nil values
30+
ErrUnexpectedNil = errors.New("slice of struct pointers cannot contain nil")
2931
)
3032

3133
// MarshalPayload writes a jsonapi response for one or many records. The
@@ -498,7 +500,12 @@ func visitModelNodeRelationships(models reflect.Value, included *map[string]*Nod
498500
nodes := []*Node{}
499501

500502
for i := 0; i < models.Len(); i++ {
501-
n := models.Index(i).Interface()
503+
model := models.Index(i)
504+
if !model.IsValid() || model.IsNil() {
505+
return nil, ErrUnexpectedNil
506+
}
507+
508+
n := model.Interface()
502509

503510
node, err := visitModelNode(n, included, sideload)
504511
if err != nil {

response_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package jsonapi
33
import (
44
"bytes"
55
"encoding/json"
6+
"errors"
67
"fmt"
78
"reflect"
89
"sort"
@@ -40,6 +41,26 @@ func TestMarshalPayload(t *testing.T) {
4041

4142
func TestMarshalPayloadWithNulls(t *testing.T) {
4243

44+
func TestMarshalPayloadWithManyRelationWithNils(t *testing.T) {
45+
blog := &Blog{
46+
ID: 1,
47+
Title: "Hello, World",
48+
Posts: []*Post{
49+
nil,
50+
{
51+
ID: 2,
52+
},
53+
nil,
54+
},
55+
}
56+
57+
out := bytes.NewBuffer(nil)
58+
if err := MarshalPayload(out, blog); !errors.Is(err, ErrUnexpectedNil) {
59+
t.Fatal("expected error but got none")
60+
}
61+
}
62+
63+
func TestMarshalPayloadWithNulls(t *testing.T) {
4364
books := []*Book{nil, {ID: 101}, nil}
4465
var jsonData map[string]interface{}
4566

0 commit comments

Comments
 (0)