Add your arguments to the field
Add your arguments to field (instead of root/info).
(Client Side)
change from Root field argument
Car(type: $type, materialType: $materialType){
material
id
name
...etc
}
To Nested field argument:
Car(type: $type){
material(materialType: $materialType) // moved from root
id
name
...etc
}
Then, access your argument in your server field resolver (material
field in this case).
Longer version
Try not to pass your argument through root/info
, except IDs
and arguments that is not from client
, anything else use field level argument (unless you have a very good reason not to)
Why?
@Bruno Ribeiro from the comment section summarised it very well:
it leads to coupling and it's very hard to scale up schemas
There are a few reasons:
when there is multiple object accessing the same object resolver
It is easy to miss providing arguments, where the needed argument is actually few level deep.
eg: student requires bestPal id, it is nest field of school, if you provide argument through root, then you will pass the bestPal argument to school and pass it to student. Which is clearly wrong, because school can have multiple students. Each student should have their own bestPal so the field should be on student.
Additionally, adding your arguments to root is not only pass to your only child, It will be pass to other children field.
Eg: an offset. if two of your child need a different offset. The Naive way is to pass a different named offset, eg: offset_1 and offset_2 for each of it. Why not define it in client side? The argument will only be meant for that field and only that field.
How?
Let's make it really simple:
There are only two level of argument:
- Root field argument
- Field level argument
Let's say you want to query a customizable car (let's limit to only the seat is customizable for now)
[Root] Car(color:white, type:sedan, seat:leather)
Soon you find yourself, you need to customize the color of seat
[Root] Car(color:white, type:sedan, seat:leather, seatColor:black)
then, business grows, now we can customize the rim as well:
[Root] Car(color:white, type:sedan, seat:leather, seatColor:black, rimShape:star,rimColor:makeitshine)
Coming next dashboard, exhaust, windows. You can already see that it is never ending:
To solve this let's make it to field level:
[Root] Car(color:white, type:sedan)
[Field] seat(color: black, texture:fabric)
[Field] rim(shape:star, color: makeitshine)
[Field] window(feature:bulletproof, tint:cantseeme)
......any other thing you want to add
instead of clumping all arguments into one root, now each field is responsible of its own argument and own its resolver.
When to apply?
Whenever you find yourself creating a dedicated resolver for that field, pass the argument to the field instead of passing it through root (even worse: info).
Example (For host question)
This section is to answer host question.
(Server side)
type RootQuery {
getTotalVehicles(color: String): TotalVehicleResponse
}
type TotalVehicleResponse {
totalCars(color: String): Int // <-- added arguments
totalTrucks(offset: Int, limit: Int): Int // <-- added arguments
}
schema {
query: RootQuery
}
then, you can access this args in your resolver argument fields:
// In your child resolver
TotalVehicleResponse{
totalCars(parent, args, ctx){
const {color} = args // <-- access your client args here
return ....
}
totalTrucks(parent, args, ctx){
const {offset, limit} = args // <-- your args from client query
...do db query
return ....
}
}
In your client query
(Client Side)
Don't forget to add your variables in your nested query field as well.
getTotalVehicles(color: $color){
totalCars(color: $color) <-- add your variable here
totalTrucks(offset: $offset, limit: $limit) <-- add your variable here
}