Hi Apollo community!
I’m working on a federated supergraph (30 subgraphs) - it’s gotten pretty messy and is not working well. It’s more like a collection of unrelated rest endpoints. There are two problems with the graph I’m trying to solve…
- The standard for a subgraph resolver to get data from another service is through the supergraph gateway. I’d rather rely heavily on schema design + federation directives where it makes sense.
- The schema is not designed in a demand-oriented way wherein clients can easily query for the data they need. (lots of water-falling request chains)
So I’m trying to start to untangle this and make a proof of concept of a high-leverage place where we implement a pattern which can be used as a blueprint moving forward. A “context entity” pattern for handling relationships between entities across multiple subgraphs. I’d love to get feedback on whether this is a recommended approach.
The Pattern
I have a UserCatalogItemContext entity that represents the relationship between a User and a CatalogItem. Multiple services extend this entity to contribute their domain-specific data. In this specific relationship, there are at least 3 subgraphs who want to contribute to the entity in the context of a specific User/CatalogItem combo. (For example - transcripts, rewards, assignments, reviews, etc.) This structure allows almost a “resolution hub” where these subgraphs can grab any field from both user entity and CatalogItem entity via @requires to resolve their fields they are contributing…
# Users Subgraph
type UserCatalogItemContext @key(fields: "userId catalogItemId") {
userId: ID!
catalogItemId: ID!
user: User!
}
# Catalog Subgraph
extend type UserCatalogItemContext @key(fields: "userId catalogItemId") {
userId: ID! @external
catalogItemId: ID! @external
catalogItem: CatalogItem!
}
# License Subgraph
extend type UserCatalogItemContext @key(fields: "userId catalogItemId") {
userId: ID! @external
catalogItemId: ID! @external
user: User! @external
canAccess: Boolean! @requires(fields: "user { organizations { name } } catalogItem { tier }")
}
# Transcripts Subgraph
extend type UserCatalogItemContext @key(fields: "userId catalogItemId") {
userId: ID! @external
catalogItemId: ID! @external
transcript: DigitalTranscript @requires(fields: "blablabla")
}
Query Example
This enables queries like:
query {
currentUser {
catalogItem(catalogItemId: "cat-001") {
user { name } # from users
catalogItem { name price } # from catalog
canAccess # from license (using @requires)
transcripts { status progress } # from transcripts
}
}
}
Note that in the current schema, the frontend has to make queries like the below after calling currentUser and querying for into about the CatalogItem….
getPdpTranscriptByUserIdAndCatalogItemId,
reviewByUserIdAndReferent,
getTrainingAssignmentByUserIdAndCatalogRootItemId,
rewardsByUserIdAndCatalogRootItemId
Question: Is this a commonly used pattern in federation architectures? Or is there another way?
Thanks for any insights!