问题描述
我正在使用Apollo-Server和Apollo-Graphql-Tools,并且我有schema
type TotalVehicleResponse { totalCars: Int totalTrucks: Int } type RootQuery { getTotalVehicals(color: String): TotalVehicleResponse } schema { query: RootQuery }
和解析器函数就像这个
{ 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 ......... ......... } } } }
我的问题是,如何在任何子解析器中访问root Resolver(getTotalVehicals)中的哪个?
推荐答案
args严格指查询该字段中提供的参数.如果您希望为子解析器提供值,则只需将其从父级解析器返回.
{ 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 } } } }
其他推荐答案
如果您知道自己正在使用变量除了接受解析器函数的第四个参数外,还有其他方法:info.
此info参数在其他字段中包含字段variableValues. 该字段并不严格包含父的args,但是如果您的操作执行了传递给父解冻器的变量,则您可以通过Info访问它们.从所有相关的解析器函数中的VaribleValues.<<<<<<<<<<<
因此,如果您的操作被称为这样:
query GetTotalVehicalsOperation($color: String) { getTotalVehicals(color: $color) { totalCars totalTrucks } }
...带变量:{颜色:'sosings'}
您可以访问其他解析器的变量:
{ 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'} } } } }
其他推荐答案
tldr:将您的参数添加到 field
(客户端)从:
更改Car(type: $type, materialType: $materialType){ id material name ... }
(客户端)至:
Car(type: $type){ id, material(materialType: $materialType) // moved here name ... }
然后,在服务器中访问您的参数fieldResolver(在这种情况下为material字段).
更长版本
尽量不要通过root将您的论点传递给,除了arguments that is not from client,arguments that is not from client或a parent object,其他任何东西都使用字段级别参数 (除非您有非常好的理由不)
为什么?
有几个原因:
-
紧密耦合
它导致耦合,很难扩展模式 -bruno ribeiro在评论部分中:
-
难以故障排除
一个级别仍然可以,但是当您公司中的某人找到一种将论点深入根深蒂固的方法时,很难调试如何丢失.
-
向儿童泄漏不必要的信息
通过root通过参数也意味着传递给其他每个孩子,不需要一个.
-
混合父对象和参数
您的父对象可能具有与参数相同的属性密钥,例如:offset,通过提供另一个偏移,您可能会得到不良结果.
如何?
一个简单的查询可以从中增长:
[Root] Car( color:white, type:sedan, seat:leather ) { id, seat, numberOfPassengers, ... }
:
[Root] Car( color:white, type:sedan, seat:leather, seatColor:black, rimColor: blue, rimShape: OutOfTheWorld, ... ) { id, seat, numberOfPassengers, ... }
您可以做这个
,而不是传递论点[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, ... }
,而不是将所有参数汇总到一个根中,而是每个字段的参数负责.
.什么时候应用?
每当您发现自己为该字段创建专用解析器时,请将参数传递到该字段(不是root,更糟糕的是:info)
问题描述
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?
推荐答案
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'} } } } }
其他推荐答案
TLDR: Add your arguments to the field
(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).
Longer version
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)
Why?
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.
How?
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.
When to apply?
Whenever you find yourself creating a dedicated resolver for that field, pass the argument to the field (not root, and worse: info)