Skip to content

fix(response caching): respect interface objects as entities#8582

Merged
aaronArinder merged 6 commits intodevfrom
aaron/response_caching_interface_object_resolution
Nov 25, 2025
Merged

fix(response caching): respect interface objects as entities#8582
aaronArinder merged 6 commits intodevfrom
aaron/response_caching_interface_object_resolution

Conversation

@aaronArinder
Copy link
Copy Markdown
Contributor

@aaronArinder aaronArinder commented Nov 10, 2025


for cache invalidation keys, we only supported objects and not interface entities

Checklist

Complete the checklist (and note appropriate exceptions) before the PR is marked ready-for-review.

  • PR description explains the motivation for the change and relevant context for reviewing
  • PR description links appropriate GitHub/Jira tickets (creating when necessary)
  • Changeset is included for user-facing changes
  • Changes are compatible1
  • Documentation2 completed
  • Performance impact assessed and acceptable
  • Metrics and logs are added3 and documented
  • Tests added and passing4
    • Unit tests
    • Integration tests
    • Manual tests, as necessary

Exceptions

Note any exceptions here

Notes

Footnotes

  1. It may be appropriate to bring upcoming changes to the attention of other (impacted) groups. Please endeavour to do this before seeking PR approval. The mechanism for doing this will vary considerably, so use your judgement as to how and when to do this.

  2. Configuration is an important part of many changes. Where applicable please try to document configuration examples.

  3. A lot of (if not most) features benefit from built-in observability and debug-level logs. Please read this guidance on metrics best-practices.

  4. Tick whichever testing boxes are applicable. If you are adding Manual Tests, please document the manual testing (extensively) in the Exceptions.

@aaronArinder aaronArinder requested a review from a team November 10, 2025 20:48
@github-actions

This comment has been minimized.

@apollo-librarian
Copy link
Copy Markdown
Contributor

apollo-librarian bot commented Nov 10, 2025

✅ Docs preview ready

The preview is ready to be viewed. View the preview

File Changes

0 new, 10 changed, 0 removed
* graphos/routing/(latest)/customization/custom-binary.mdx
* graphos/routing/(latest)/observability/graphos/graphos-reporting.mdx
* graphos/routing/(latest)/observability/router-telemetry-otel/telemetry-pipelines/metrics-exporters/otlp.mdx
* graphos/routing/(latest)/observability/router-telemetry-otel/telemetry-pipelines/trace-exporters/otlp.mdx
* graphos/routing/(latest)/observability/router-telemetry-otel/telemetry-pipelines/trace-exporters/overview.mdx
* graphos/routing/(latest)/operations/apq.mdx
* graphos/routing/(latest)/performance/caching/response-caching/faq.mdx
* graphos/routing/(latest)/performance/caching/response-caching/observability.mdx
* graphos/routing/(latest)/performance/caching/response-caching/quickstart.mdx
* graphos/routing/(latest)/security/authorization.mdx

Build ID: 4ea92bf93ba65e6e189352a9
Build Logs: View logs

URL: https://www.apollographql.com/docs/deploy-preview/4ea92bf93ba65e6e189352a9

Comment thread apollo-router/src/plugins/response_cache/plugin.rs Outdated
}
})
});
// supports both Object types and Interface types (for interface objects with isInterfaceObject: true)
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.

Where do you check that isInterfaceObject is set to true ? Do you assume it's checked at composition ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm assuming in composition; the second test below, where we have a concrete object and a normal interface (ie, not an interface object) shows that (I think, at least insofar as I understand how parsing/validating works, which is very little), where the first test (with just an interface object and no concrete object) gets us back the __typename we'd expect (in that case, Item)

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.

Cc @duckki I don't have enough knowledge on this maybe you could help me

Copy link
Copy Markdown
Contributor

@duckki duckki Nov 12, 2025

Choose a reason for hiding this comment

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

Let me double check the status of validation rules.

Update: We allow @cacheTag on interface objects in composition. But, I need to check how it's represented in supergraph schemas. Unfortunately, I'm away from office today. I'll think more about this when I have a chance.

Copy link
Copy Markdown
Contributor

@duckki duckki Nov 14, 2025

Choose a reason for hiding this comment

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

I reviewed the supergraph composition of cache-tag directives applied on interface object entity types.

  • In supergraph, those directives are translated using @directive directive applied on the interface type, instead of its implementation types.
  • Since we don't normally allow @cacheTag on interface, such directive applications only happen with interface object in specified subgraphs.

Thus, in order to check if a type has @cacheTag, we must

  • Check the type (interface or object) has one or more @cacheTag directives applied on it.
  • (For object types) check all of its interface types if one or more @cacheTag directives applied on them.

Copy link
Copy Markdown
Member

@dariuszkuc dariuszkuc Nov 14, 2025

Choose a reason for hiding this comment

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

I thought @cacheTag is per graph? so in a graph that there is an @interfaceObject we won't have any of its implementations - hence why do we need to look up the interface types?

edit: nvm, found it -> filtering per graph is done afterwards

Co-authored-by: Renée <renee.kooi@apollographql.com>
@aaronArinder aaronArinder requested a review from bnjjj November 12, 2025 14:23
Copy link
Copy Markdown
Contributor

@duckki duckki left a comment

Choose a reason for hiding this comment

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

It looked good.
I pushed a commit handling another case.

Cache tags can be on an interface object or regular objects. Also, we should consider the combinations of the source subgraph and the target subgraph when we jump from one to another.

  • From non-interface object to non-interface object: Originally handled
  • From interface object to interface object: Handled in the previous commit of this PR
  • From non-interface object to interface object:Handled in my new commit pushed to this PR
  • From interface object to non-interface object: Not handled (= No cache keys since it can't be determined)

I also added two more tests demonstrating those cases.

}
})
});
// supports both Object types and Interface types (for interface objects with isInterfaceObject: true)
Copy link
Copy Markdown
Contributor

@duckki duckki Nov 14, 2025

Choose a reason for hiding this comment

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

I reviewed the supergraph composition of cache-tag directives applied on interface object entity types.

  • In supergraph, those directives are translated using @directive directive applied on the interface type, instead of its implementation types.
  • Since we don't normally allow @cacheTag on interface, such directive applications only happen with interface object in specified subgraphs.

Thus, in order to check if a type has @cacheTag, we must

  • Check the type (interface or object) has one or more @cacheTag directives applied on it.
  • (For object types) check all of its interface types if one or more @cacheTag directives applied on them.

@duckki duckki force-pushed the aaron/response_caching_interface_object_resolution branch from ea07517 to a7b0d4a Compare November 14, 2025 06:39
@duckki duckki force-pushed the aaron/response_caching_interface_object_resolution branch from a7b0d4a to fa9d801 Compare November 14, 2025 06:44
@duckki
Copy link
Copy Markdown
Contributor

duckki commented Nov 17, 2025

Over the weekend, I realized it could be improved:

  • From non-interface object to interface object:Handled in my new commit pushed to this PR
    • We don't need to enumerate what interfaces the given object type implements, since we should already know the interface-object type from the query plan. I'll fix this.
  • From interface object to non-interface object: Not handled (= No cache keys since it can't be determined)
    • Since we validated all implementation types have the same set of cache tags, we can retrieve that from any object type implements the interface. Thus, we can handle this case. I'll fix this, too.

@duckki
Copy link
Copy Markdown
Contributor

duckki commented Nov 19, 2025

My attempt to improve it didn't really work. Let me explain:

  • From non-interface object to interface object:Handled in my new commit pushed to this PR

    • We don't need to enumerate what interfaces the given object type implements, since we should already know the interface-object type from the query plan. I'll fix this.

I wanted to derive the interface type name from the query plan, but it's not readily available (we would have to parse the fetch query to get that). However, I think the situation is not too bad. Even if we enumerate all interfaces, the result will be at most one anyways. That's because we can't really have multiple interface objects covering the same object type.

Instead, I just moved the directive filtering before collecting them for efficiency.

  • From interface object to non-interface object: Not handled (= No cache keys since it can't be determined)

    • Since we validated all implementation types have the same set of cache tags, we can retrieve that from any object type implements the interface. Thus, we can handle this case. I'll fix this, too.

I misspoke. Actually, object types CAN have different sets of cache tags. So, in this case, we can't determine cache tag after all. 😢 This is a fundamental issue with interface objects.

I just added some more comments in the code explaining it.

I'll leave end-to-end testing to you. Otherwise, this PR looks good.

@aaronArinder
Copy link
Copy Markdown
Contributor Author

ack on e2e testing, @duckki; I'll probably not get to it until next week, but have it on my list of todos

thank you so much for running with this pr and fleshing it out into something useable!

@aaronArinder aaronArinder requested a review from a team as a code owner November 25, 2025 19:21
@aaronArinder aaronArinder merged commit 5957c84 into dev Nov 25, 2025
14 of 15 checks passed
@aaronArinder aaronArinder deleted the aaron/response_caching_interface_object_resolution branch November 25, 2025 20:11
@abernix abernix mentioned this pull request Dec 12, 2025
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.

5 participants