I have an Order subgraph and a Menu subgraph. The order subgraph returns customers orders and the Menu subgraph return information about menu's and the menu items.
When I fetch an order, I want the order data returned from the Order subgraph but then any correlated item information such as price and name etc needs to be resolved from the Menu subgraph.
My schema's are as follows:
// Order subgraph
type Order @key(fields: "id") {
id: ID!
item: MenuItem! // MenuItem type exists in the Menu subgraph
}
// Menu subgraph
type MenuItem @key(fields: "id") {
id: ID!
name: String!
price Float!
}
When I start my Order subgraph, I get the error: Error: Unknown type: "MenuItem".
.
Sounds like I might be able to use @external
or @provides
directives in order to tell my subgraph that the types exist in another subgraph but I can't seem to get it to work.
How can I share types across subgraphs and how does the data resolve from one to another?
I have recently learned about Federated Subgraphs and I think I can help you. All of my information comes from the courses they have here (https://www.apollographql.com/tutorials/). If you take a look at the Voyage 1 course, you can learn about entities in detail.
Since you want MenuItems
to be resolved by the Menu
subgraph through the Orders
subgraph, I'm assuming that data-wise an Order
would have an ID for a MenuItem
. You wouldn't need the @provides
or @external
directives in this case. What you could do, is this:
MenuItem
entity in your Order
subgraph.type Order @key(fields: "id") {
id: ID!
item: MenuItem! // MenuItem type exists in the Menu subgraph
}
type MenuItem @key(fields: "id", resolvable: false) {
id: ID!
}
Order
resolver. For this example, since you didnt outline, I'll just say you have an orderById
function you use to fetch an order. In that function, you want to ensure that an order returns the ID of a menu item somewhere. For example:function orderById(orderId) {
// ...content...
returns {
// ...order information...
menuItem: {
id: menuItemID
}
}
}
Menu
subgraph when we call for an Order
. To do this we create a resolve for our menuItem
field in our ResolversMap (or where you outline how things resolve with what functions). You can do that like so:// Order resolvers
const resolvers = {
Query: {
orderById: ...
}
Order: {
menuItem: ({menuItem}: Order) => {
return {id: menuItem.id}
}
}
}
Menu
a sharable entity.type MenuItem @key(fields: "id") @shareable {
id: ID!
name: String!
price Float!
}
Order
resolver to pass that ID down it has to be received by the Menu
subgraph. To do this, we create a __resolveReference
. Here I am also assuming that you have setup some sort of API for retrieving a menu item from you database. Under the Menu
subgraph resolvers, go ahead and add this:// Menu resolvers
const resolvers = {
Query: {
menuItemByID: ...
}
MenuItem: {
__resolveReference: ({id}: MenuItem,{dataSources}: ServerContext) => {
return dataSources.menuItemAPI.menuItemByID(id)
}
}
}
What happens now, is that whenever the Router sees a request for an Order
, you ask to return a menuItem
within that Order
, it will know to call the Menu
subgraph to resolve menuItem
. Hope this helps, let me know if you have any questions