Question
Hello team,
I'm using Apollo iOS 1.18.0 with normalized caching and encountered a frustrating issue:
- User loads a paginated list (e.g., business reviews)
- Review objects get cached correctly with normalized keys (Review:)
- User taps a review to see details
- Cache miss occurs, triggering an unnecessary network request (even though the data already exists in the cache!)
Example Scenario
Query 1 - Paginated List:
query GetBusinessReviews($encid: String!, $first: Int, $after: String) { business(encid: $encid) { reviews(first: $first, after: $after) { edges { node { encid rating text { full } business { encid, alias } } } pageInfo { hasNextPage, endCursor } } } }
Query 2 - Detail Screen:
query GetReview($encid: String!) { review(encid: $encid) { encid rating text { full } business { encid, alias } } }
Root Cause
Apollo's cache stores data in two layers:
- QUERY_ROOT entries (entry points for queries)
- Normalized objects (the actual data, keyed by ID)
What Query 1 creates:
QUERY_ROOT.business(encid:X) → Business:X
Review:ABC (normalized) ✅
What Query 2 looks for:
QUERY_ROOT.review(encid:ABC) ❌ (doesn't exist!)
Even though Review:ABC exists as a normalized object, Apollo can't use it because the query root entry doesn't exist. Apollo always starts resolution from QUERY_ROOT.
I’m aware of withinReadTransaction, but relying on manual record reads feels like a workaround: it bypasses GraphQL selection-set decoding and increases the risk of drift/bugs as the schema evolves.
Questions:
- Is there a better way to create QUERY_ROOT entries programmatically without manual cache writes?
- Has anyone else solved this differently?
- Will Apollo iOS 2.x have improvements for cross-query cache resolution?
I didn't know if this fit as a feature request or a bug so decided to tag it as a question.
Question
Hello team,
I'm using Apollo iOS 1.18.0 with normalized caching and encountered a frustrating issue:
Example Scenario
Query 1 - Paginated List:
query GetBusinessReviews($encid: String!, $first: Int, $after: String) { business(encid: $encid) { reviews(first: $first, after: $after) { edges { node { encid rating text { full } business { encid, alias } } } pageInfo { hasNextPage, endCursor } } } }Query 2 - Detail Screen:
query GetReview($encid: String!) { review(encid: $encid) { encid rating text { full } business { encid, alias } } }Root Cause
Apollo's cache stores data in two layers:
What Query 1 creates:
QUERY_ROOT.business(encid:X) → Business:X
Review:ABC (normalized) ✅
What Query 2 looks for:
QUERY_ROOT.review(encid:ABC) ❌ (doesn't exist!)
Even though Review:ABC exists as a normalized object, Apollo can't use it because the query root entry doesn't exist. Apollo always starts resolution from QUERY_ROOT.
I’m aware of withinReadTransaction, but relying on manual record reads feels like a workaround: it bypasses GraphQL selection-set decoding and increases the risk of drift/bugs as the schema evolves.
Questions:
I didn't know if this fit as a feature request or a bug so decided to tag it as a question.