Skip to content

fix(serializer): honour nested includes in lazy_load_data - #203

Draft
tvdeyen wants to merge 2 commits into
mainfrom
fix-jsonapi-lazy-load-nested
Draft

fix(serializer): honour nested includes in lazy_load_data#203
tvdeyen wants to merge 2 commits into
mainfrom
fix-jsonapi-lazy-load-nested

Conversation

@tvdeyen

@tvdeyen tvdeyen commented Aug 24, 2026

Copy link
Copy Markdown
Member

jsonapi-serializer's lazy_load_data is meant to omit a relationship's data linkage unless that relationship was requested via include. It works for top-level relationships but is broken for nested ones: a relationship emits linkage unless lazy_load_data && !included, where included = includes_list.include?(key) — but the top-level includes are a flat list of dotted symbols (primary_taxon.ancestors), and get_included_records hands each sideloaded record its parent's includes_list rather than the scoped remainder. So enabling lazy_load_data suppresses linkage for every relationship of a nested resource, including the ones that were requested — making it unusable beyond the top level.

This prepends a patch onto FastJsonapi::SerializationCore that:

  • matches included against the base key of each requested include path (so primary_taxon.ancestors marks :primary_taxon, and the taxon's own :ancestors), and
  • threads the correctly-scoped remainder into each sideloaded record.

With it, lazy_load_data: true emits linkage only for relationships actually requested at that resource's position in the include tree — which lets a serializer stop emitting the unrequested back-references (a taxon's children when only ancestors was asked for, an option value's option_type, …) that otherwise bloat responses and create cycles for consumers.

Scope / safety

  • It does not enable lazy_load_data anywhere. It's a pure bug fix and is completely inert for relationships that don't set lazy_load_data: true (their linkage is emitted regardless).
  • It patches a gem constant, so it's loaded at boot from the engine via require (flickwerk/Zeitwerk on_load only fires for app-autoloaded constants, not gem code).

Testing
Spec added under spec/serializers/… reproducing the nested case (requested relationship keeps data, unrequested nested relationship drops it, and non-lazy relationships are untouched). The fix was also validated directly against jsonapi-serializer 2.2.0 in isolation.

@tvdeyen
tvdeyen force-pushed the fix-jsonapi-lazy-load-nested branch from 62a1897 to befdc82 Compare August 24, 2026 13:30
@mamhoff

mamhoff commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Amazing.

@tvdeyen
tvdeyen force-pushed the fix-jsonapi-lazy-load-nested branch 2 times, most recently from 566b21e to 0100d28 Compare August 26, 2026 16:50
jsonapi-serializer decides whether to emit a relationship's linkage from
`includes_list.include?(key)`, but the top-level includes are a flat list
of dotted symbols and each sideloaded record is handed its parent's
includes_list rather than the scoped remainder. So enabling
`lazy_load_data` suppresses linkage for every relationship of a nested
resource -- including the ones that were requested -- which makes it
unusable beyond top-level relationships.

Prepend a patch onto FastJsonapi::SerializationCore that matches the base
key of each requested include path and threads the scoped remainder into
each sideloaded record, so lazy_load_data only suppresses relationships
that were genuinely not requested at that resource's position in the
include tree. It is loaded at boot from the engine (the target is a gem
constant, not autoloadable) and is inert for relationships that do not
set lazy_load_data.
@tvdeyen
tvdeyen force-pushed the fix-jsonapi-lazy-load-nested branch from 0100d28 to 9bae754 Compare August 26, 2026 17:39
Emitting linkage for relationships that were not requested via `include`
is surprising and triggers N+1 queries on the server, so relationships
now set `lazy_load_data: true` and emit their `data` only when requested.

The element tree is the exception and stays eager: `all_elements`,
`elements`, `fixed_elements` and the recursive `nested_elements`. A tree
of arbitrary depth cannot be expressed as an `include` path, and clients
rely on the top-level `elements`/`fixed_elements` linkage as the entry
points from which to walk `nested_elements` down and reconstruct the
page's content.
@tvdeyen
tvdeyen force-pushed the fix-jsonapi-lazy-load-nested branch from 9bae754 to 79ddb46 Compare August 26, 2026 18:01
@tvdeyen
tvdeyen marked this pull request as draft August 27, 2026 21:31
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