I have a deeply nested type in graphql which i resolve with content at different parts of the graph (without a direct parent->child)
Some of the child property in the resolver, needs a property from a parent (but sometimes not the parent directly above), so i am passing around this object into resolver context so that leaf nodes can access it.
example:
my db has a bunch of product items
{
"products": [
{
"id": "1",
"name": "product-1",
"options": [
{
"id": "colour-gray",
"items": [
{
"id": "not-selected",
"name": "not selected",
"price": 0
},
{
"id": "selected",
"name": "selected",
"price": 10
}
]
},
{
"id": "colour-red",
"items": [
{
"id": "not-selected",
"name": "not selected",
"price": 0
},
{
"id": "selected",
"name": "selected",
"price": 10
}
]
}
]
},
{
"id": "2",
"name": "product-1",
"options": [
{
"id": "colour-gray",
"items": [
{
"id": "not-selected",
"name": "not selected",
"price": 0
},
{
"id": "selected",
"name": "selected",
"price": 30
}
]
},
{
"id": "colour-red",
"items": [
{
"id": "not-selected",
"name": "not selected",
"price": 0
},
{
"id": "selected",
"name": "selected",
"price": 25
}
]
}
]
}
]
}
I have a resolver for products, but i need to add content regarding options dynamically and present things like prices but these options are dependent on a product Id,
the final result is something like this:
{
"id": "colour-gray",
"items": [
{
"id": "not-selected",
"name": "not selected",
"price": 0,
"content": "No cost added"
},
{
"id": "selected",
"name": "selected",
"price": 10,
"content": "only today it will cost 10, at discounted price for product-1"
}
]
}
I have a service thats fills up products, and something seperately that serves content, Both are not connected, its all done through the graph.
To go around the fact the whatever populates content is not aware of the productId, we put this in the context object.
However i am aware that the context object is shared to all resolvers for the lifetime of the request.
Now my questions are:
I cant find anywhere in the docs how gql resolves the graph. if it populates one at time from top of the graph all the way in, or it can attempt to do things concurrently.
Any help would be appreciated.
TLDR: yes.
However often it is just simpler to add values to the child object so that they can be passed down to the grandchildren.
Your model appears to look like:
type Product {
id: ID!
name: String
options: [Option]
}
type Option {
id: ID!
items: [Item]
}
type Item {
id: ID!
name: String
price: Number
content: String
}
The challenge is that to properly resolve an Item
you need to know the id
of the grandparent Product
.
What I recommend is that you include the product's id
when you resolve options
- this will cause it to pass down to the Item
resolver.
The options
resolver for the Product
type will naturally get the id
of the parent product.
options: ({ id:productId },args,context) => database('options').where({ productId })
I'm using a knexjs style ORM syntax here but it will be based on whatever db and ORM you use.
Here we're just returning all the columns from the options
table that belong to the product in question regardless of whether or not they are included in the GraphQL type definition for Option
. This means the productId
column is going to get included.
Now when GraphQL resolves the items
field under the Option
type, the parent
field will include that productId
field even though it will eventually get stripped out of the final result!
items: ( { id:optionId, productId }, args, context ) => database('items').where({ optionId, productId })