Skip to content

Commit 1bf031b

Browse files
committed
add custom handling of NullFields to marshaling
1 parent 4b7b22a commit 1bf031b

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed

response.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,12 @@ func visitModelNode(model interface{}, included *map[string]*Node,
233233

234234
modelValue := value.Elem()
235235
modelType := value.Type().Elem()
236+
nullFields := []string{}
237+
if _, ok := modelType.FieldByName("NullFields"); ok {
238+
if modelValue.FieldByName("NullFields").Kind() == reflect.Slice {
239+
nullFields = modelValue.FieldByName("NullFields").Interface().([]string)
240+
}
241+
}
236242

237243
for i := 0; i < modelValue.NumField(); i++ {
238244
fieldValue := modelValue.Field(i)
@@ -348,7 +354,7 @@ func visitModelNode(model interface{}, included *map[string]*Node,
348354
} else if fieldValue.Type() == reflect.TypeOf(new(time.Time)) {
349355
// A time pointer may be nil
350356
if fieldValue.IsNil() {
351-
if omitEmpty {
357+
if omitEmpty && !stringInSlice(nullFields, structField.Name) {
352358
continue
353359
}
354360

@@ -373,7 +379,7 @@ func visitModelNode(model interface{}, included *map[string]*Node,
373379
emptyValue := reflect.Zero(fieldValue.Type())
374380

375381
// See if we need to omit this field
376-
if omitEmpty && reflect.DeepEqual(fieldValue.Interface(), emptyValue.Interface()) {
382+
if omitEmpty && reflect.DeepEqual(fieldValue.Interface(), emptyValue.Interface()) && !stringInSlice(nullFields, structField.Name) {
377383
continue
378384
}
379385

@@ -648,3 +654,12 @@ func convertToSliceInterface(i *interface{}) ([]interface{}, error) {
648654
}
649655
return response, nil
650656
}
657+
658+
func stringInSlice(s []string, v string) bool {
659+
for _, field := range s {
660+
if field == v {
661+
return true
662+
}
663+
}
664+
return false
665+
}

response_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,47 @@ func TestWithOmitsEmptyAnnotationOnAttribute(t *testing.T) {
518518
}
519519
}
520520

521+
func TestOmitsEmptyAnnotationAndNullFieldOnAttribute(t *testing.T) {
522+
type Author struct{}
523+
524+
type Book struct {
525+
ID int `jsonapi:"primary,books"`
526+
Name string `jsonapi:"attr,name"`
527+
Author *Author `jsonapi:"attr,author,omitempty"`
528+
PublishedAt *time.Time `jsonapi:"attr,published_at,omitempty"`
529+
530+
NullFields []string
531+
}
532+
533+
book := &Book{
534+
ID: 123,
535+
Name: "The Confidence Man",
536+
PublishedAt: nil,
537+
538+
NullFields: []string{"PublishedAt"},
539+
}
540+
541+
out := bytes.NewBuffer(nil)
542+
if err := MarshalPayload(out, book); err != nil {
543+
t.Fatal(err)
544+
}
545+
546+
var jsonData map[string]interface{}
547+
if err := json.Unmarshal(out.Bytes(), &jsonData); err != nil {
548+
t.Fatal(err)
549+
}
550+
551+
payload := jsonData["data"].(map[string]interface{})
552+
attributes := payload["attributes"].(map[string]interface{})
553+
if _, ok := attributes["published_at"]; !ok {
554+
t.Fatal("Was expecting the data.attributes.published_at to have NOT been omitted")
555+
}
556+
557+
if _, ok := attributes["author"]; ok {
558+
t.Fatal("Was expecting the data.attributes.author to have been omitted")
559+
}
560+
}
561+
521562
func TestMarshalIDPtr(t *testing.T) {
522563
id, make, model := "123e4567-e89b-12d3-a456-426655440000", "Ford", "Mustang"
523564
car := &Car{

0 commit comments

Comments
 (0)