@@ -409,6 +409,72 @@ func (post Post) JSONAPIRelationshipMeta(relation string) *Meta {
409
409
}
410
410
```
411
411
412
+ ### Nullable attributes
413
+
414
+ Certain APIs may interpret the meaning of ` null ` attribute values as significantly
415
+ different from unspecified values (those that do not show up in the request).
416
+ The default use of the ` omitempty ` struct tag does not allow for sending
417
+ significant ` null ` s.
418
+
419
+ A type is provided for this purpose if needed: ` NullableAttr[T] ` . This type
420
+ provides an API for sending and receiving significant ` null ` values for
421
+ attribute values of any type.
422
+
423
+ In the example below, a payload is presented for a fictitious API that makes use
424
+ of significant ` null ` values. Once enabled, the ` UnsettableTime ` setting can
425
+ only be disabled by updating it to a ` null ` value.
426
+
427
+ The payload struct below makes use of a ` NullableAttr ` with an inner ` time.Time `
428
+ to allow this behavior:
429
+
430
+ ``` go
431
+ type Settings struct {
432
+ ID int ` jsonapi:"primary,videos"`
433
+ UnsettableTime jsonapi.NullableAttr [time.Time ] ` jsonapi:"attr,unsettable_time,rfc3339,omitempty"`
434
+ }
435
+ ```
436
+
437
+ To enable the setting as described above, an non-null ` time.Time ` value is
438
+ sent to the API. This is done by using the exported
439
+ ` NewNullableAttrWithValue[T]() ` method:
440
+
441
+ ``` go
442
+ s := Settings {
443
+ ID : 1 ,
444
+ UnsettableTime : jsonapi.NewNullableAttrWithValue [time.Time ](time.Now ()),
445
+ }
446
+ ```
447
+
448
+ To disable the setting, a ` null ` value needs to be sent to the API. This is done
449
+ by using the exported ` NewNullNullableAttr[T]() ` method:
450
+
451
+ ``` go
452
+ s := Settings {
453
+ ID : 1 ,
454
+ UnsettableTime : jsonapi.NewNullNullableAttr [time.Time ](),
455
+ }
456
+ ```
457
+
458
+ Once a payload has been marshaled, the attribute value is flattened to a
459
+ primitive value:
460
+ ```
461
+ "unsettable_time": "2021-01-01T02:07:14Z",
462
+ ```
463
+
464
+ Significant nulls are also included and flattened, even when specifying ` omitempty ` :
465
+ ```
466
+ "unsettable_time": null,
467
+ ```
468
+
469
+ Once a payload is unmarshaled, the target attribute field is hydrated with
470
+ the value in the payload and can be retrieved with the ` Get() ` method:
471
+ ``` go
472
+ t , err := s.UnsettableTime .Get ()
473
+ ```
474
+
475
+ All other struct tags used in the attribute definition will be honored when
476
+ marshaling and unmarshaling non-null values for the inner type.
477
+
412
478
### Custom types
413
479
414
480
Custom types are supported for primitive types, only, as attributes. Examples,
0 commit comments