Skip to content

Support absent attributes/relationships in resource decoding#20

Open
alanf wants to merge 1 commit into
mainfrom
alanf/MOB-6727-support-absent-attributes-relationships
Open

Support absent attributes/relationships in resource decoding#20
alanf wants to merge 1 commit into
mainfrom
alanf/MOB-6727-support-absent-attributes-relationships

Conversation

@alanf

@alanf alanf commented Jul 22, 2026

Copy link
Copy Markdown

Support absent attributes/relationships in resource decoding

Per the JSON:API spec, a resource
object's attributes and relationships members are optional — only type/id are required.
Resource previously threw keyNotFound if either was missing. This adds opt-in support for
decoding through that gap.

Changes

  • New EmptyRepresentable protocol: conform Attributes/Relationships to it, and Resource
    falls back to .empty when the corresponding key is absent, instead of throwing. (Malformed-but-present
    data still throws as before.)
  • @ResourceWrapper auto-synthesizes this conformance whenever every attribute/relationship
    property is Optional — the common case needs no extra annotation. Applied independently to
    attributes vs. relationships; BodyDefinition is excluded.
  • Tests (unit, macro-expansion snapshots, integration) and README/doc updates.

Tradeoffs

  • Non-optional array attributes are intentionally excluded from auto-synthesis (no
    "defaults-to-[]" semantics added here).
  • Eligibility detection doesn't recognize the module-qualified spelling Swift.Optional<T>
    (only T?/Optional<T>) — a pre-existing limitation in a shared macro helper, not a
    regression, and not worth touching for this rare spelling.
  • Fully additive/non-breaking; no existing resource definition changes behavior unless it opts in.

The JSON:API spec allows a resource object's attributes and relationships
members to be entirely absent, but Resource.init(from:) previously threw
keyNotFound whenever either key was missing. Add an opt-in
EmptyRepresentable protocol so a ResourceDefinition can declare tolerance
for a missing key, and teach @ResourceWrapper to auto-synthesize that
conformance when every attribute/relationship property is Optional.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@alanf
alanf marked this pull request as ready for review July 23, 2026 17:21
@alanf
alanf requested a review from NicoMulet July 23, 2026 17:21

@NicoMulet NicoMulet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for adding this important behavior to the library

self.attributes = attributes
} else if !container.contains(.attributes), let emptyType = Attributes.self as? any EmptyRepresentable.Type
{
self.attributes = emptyType.empty as! Attributes

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add this cast to the if condition, so that we avoid of making of force cast

} else if !container.contains(.relationships),
let emptyType = Relationships.self as? any EmptyRepresentable.Type
{
self.relationships = emptyType.empty as! Relationships

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment for this cast

Comment on lines +346 to +348
} catch DecodingError.keyNotFound {
// then
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need an extra catch block in order to also fail the test if the error is not the one we were expecting

Comment on lines +158 to +160
} catch DecodingError.keyNotFound {
// then
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this do-catch block

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants