I am using apollo-server and apollo-graphql-tools and I have following schema
type TotalVehicleResponse {
totalCars: Int
totalTrucks: Int
}
type RootQuery {
getTotalVehicals(color: String): TotalVehicleResponse
}
schema {
query: RootQuery
}
and Resolver functions are like this
{
RootQuery: {
getTotalVehicals: async (root, args, context) => {
// args = {color: 'something'}
return {};
},
TotalVehicleResponse: {
totalCars: async (root, args, conext) => {
// args is empty({}) here
.........
.........
},
totalTrucks: async (root, args, conext) => {
// args is empty({}) here
.........
.........
}
}
}
}
My question is that how can I access args
which is available in root resolver(getTotalVehicals
) in any of the child resolvers?
To access this id , we can use the second parameter in the resolver: args . args is an object that contains all GraphQL arguments that were provided for the field. We can destructure this object to access the id property, then pass that id into our getTrack method. Then, we can return the results of that method.
The Context can be accessed directly in resolve function or within Dependency Injection using CONTEXT token.
To start testing GraphQL queries, use the easygraphql-tester library. The library can be used to test all kinds of resolvers, queries, mutations, and subscriptions, but start by testing the getBooks query. First, create a tester object from your schema.
args
refer strictly to the arguments provided in the query to that field. If you want values to be made available to child resolvers, you can simply return them from the parent resolver.
{
RootQuery: {
getTotalVehicles: async (root, args, context) => {
return { color: args.color };
},
TotalVehicleResponse: {
totalCars: async (root, args, context) => {
// root contains color here
},
totalTrucks: async (root, args, context) => {
// root contains color here
}
}
}
}
If you know you are using variables there is another way, other than the accepted answer, using the fourth argument of the resolver function: info
.
This info
argument contains a field variableValues
amongst other fields.
This field doesn't strictly contain the parent's args
, but if your operation is executed with variables that are passed to the parent resolver, then you'll have access to them via the info.variableValues from all the relevant resolver functions.
So if your operation is called like this for example:
query GetTotalVehicalsOperation($color: String) {
getTotalVehicals(color: $color) {
totalCars
totalTrucks
}
}
... with variables: {color: 'something'}
you'll have access to the variables from the other resolvers:
{
RootQuery: {
getTotalVehicles: async (root, args, context, info) => {
//info.variableValues contains {color: 'something'}
return {};
},
TotalVehicleResponse: {
totalCars: async (root, args, context, info) => {
//same here: info.variableValues contains {color: 'something'}
},
totalTrucks: async (root, args, context, info) => {
//and also here: info.variableValues contains {color: 'something'}
}
}
}
}
(Client Side) change from:
Car(type: $type, materialType: $materialType){
id
material
name
...
}
(Client Side) To:
Car(type: $type){
id,
material(materialType: $materialType) // moved here
name
...
}
Then, access your argument in your server fieldResolver
(material
field in this case).
Try not to pass your argument through root
, except IDs
, arguments that is not from client
or a parent object
, anything else use field level argument (unless you have a very good reason not to)
There are a few reasons:
Tight Coupling
it leads to coupling and it's very hard to scale up schemas -From @Bruno Ribeiro in the comment section:
Difficult to troubleshoot
One level is still fine, but when someone in your company found a way to pass the argument down deep through the roots, it is difficult to debug how it is missing.
Leaking unnecessary information to children
Passing arguments through root also means passing to every other child, desired one or not.
Mixing up parent object and argument
Your parent object might have the same property key as argument, eg: offset
, by supplying another offset, you will likely got an undesirable result.
A simple query can grow from this:
[Root] Car(
color:white,
type:sedan,
seat:leather
) {
id,
seat,
numberOfPassengers,
...
}
To this:
[Root] Car(
color:white,
type:sedan,
seat:leather,
seatColor:black,
rimColor: blue,
rimShape: OutOfTheWorld,
...
) {
id,
seat,
numberOfPassengers,
...
}
Instead of passing the argument around, you can do this
[Root] Car(
color:white,
type:sedan
...
) {
id
seat(type:leather, color:black),
rim(color: blue, shape: OutOfTheWorld){
// nested query
material(hardness: high), // solved `Why no.2`: deep argument.
// More nested
brand(trustWorthy: high) {
priceRange(range: mid),
area,
...
},
id
}
numberOfPassengers,
...
}
instead of clumping all arguments into one root, now each field is responsible for its argument and resolver.
Whenever you find yourself creating a dedicated resolver for that field, pass the argument to the field (not root, and worse: info)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With