子解析器中的Graphql-Access参数

Man*_*iya 7 apollo graphql graphql-js apollo-server

我正在使用apollo-server和apollo-graphql-tools,我有以下架构

type TotalVehicleResponse {
  totalCars: Int
  totalTrucks: Int
}

type RootQuery {
  getTotalVehicals(color: String): TotalVehicleResponse
}

schema {
  query: RootQuery
}
Run Code Online (Sandbox Code Playgroud)

和解析器功能是这样的

{
  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
        .........
        .........
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是如何在任何子args解析器中访问root解析器(getTotalVehicals)中可用的?

cYe*_*Yee 12

将您的参数添加到字段

(客户端)从:

Car(type: $type, materialType: $materialType){
  id
  material
  name
  ...
}
Run Code Online (Sandbox Code Playgroud)

(客户端)至:

Car(type: $type){
  id
  material(materialType: $materialType) // moved here
  name
  ...
}
Run Code Online (Sandbox Code Playgroud)

然后,在您的服务器中访问您的参数fieldResolvermaterial在本例中为字段)。

更长的版本

尽量不要传递您的参数root,除了IDs, arguments that is not from clienta parent object任何其他使用字段级参数的内容 (除非您有充分的理由不这样做

为什么?

有几个原因:

  1. 紧耦合

    来自评论部分的@Bruno Ribeiro:它导致耦合并且很难扩展模式

  2. 难以排除故障

    一个级别仍然可以,但是当坏习惯失控时,您公司中的某个人找到了一种方法将争论深入到几个级别的根源中,并且消失了,很难找出它消失的地方。不好玩。

  3. 向儿童泄露不必要的信息

    通过 root 传递参数也意味着传递给其他每个孩子,无论是否需要。

如何?

让我们让它变得非常简单:只有两个级别的论证:

  1. 根字段参数
  2. 字段级参数

假设您想要query一辆可定制的汽车(让我们现在仅限于座椅可定制)

[Root] Car(color:white, type:sedan, seat:leather)
Run Code Online (Sandbox Code Playgroud)

很快你发现自己,需要自定义座椅颜色

[Root] Car(color:white, type:sedan, seat:leather, seatColor:black)
Run Code Online (Sandbox Code Playgroud)

然后,业务增长,现在我们也需要定制轮辋:

[Root] Car(color:white, type:sedan, seat:leather, seatColor:black, rimShape:star,rimColor:makeitshine)
Run Code Online (Sandbox Code Playgroud)

下一个仪表板,排气管,窗户,它永远不会结束。要解决此问题:将其设置为字段级别:

[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
Run Code Online (Sandbox Code Playgroud)

现在每个字段都负责自己的参数并拥有自己的解析器,而不是将所有参数集中到一个根中。

什么时候申请?

每当您发现自己为该字段创建专用解析器时,请将参数传递给该字段(不是 root,更糟糕的是:info)

结束了漫长的呜呜声。

######################

本节回答主持人提问。

我的问题是如何访问任何子解析器中的根解析器(getTotalVehicals)中可用的参数?

(服务器端)

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
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在解析器参数字段中访问此参数:

// 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 ....
   }
}
Run Code Online (Sandbox Code Playgroud)

在您的客户查询中

(客户端)

不要忘记在嵌套查询字段中添加变量。

getTotalVehicles(color: $color){
  totalCars(color: $color) <-- add your variable here
  totalTrucks(offset: $offset, limit: $limit) <-- add your variable here
}
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的答案。参数不应在解析器之间共享;这会导致耦合,并且很难以这种方式扩展模式 (4认同)
  • 最好且唯一正确的答案!谢谢!很难找到关于如何处理这个问题的克莱尔文档! (2认同)

imr*_*las 10

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
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 请不要这样做。它导致解析器之间的紧密耦合并且不能很好地扩展。每个解析器应该直接从查询接收自己的参数。请查看 cYee 的答案以获取更多信息:/sf/answers/4431009481/ (3认同)
  • 这看起来像是一个解决方法,而不是一个正确的解决方案。 (2认同)

Tal*_*l Z 8

如果你知道你正在使用变量,那么除了接受的答案之外,还有另一种方法,使用解析器函数的第四个参数:info.

info参数包含variableValues其他字段中的字段.此字段不严格包含父级args,但如果使用传递给父级解析程序的变量执行操作,则可以通过所有相关解析程序函数的info.variableValues访问它们.

因此,如果您的操作被调用,例如:

query GetTotalVehicalsOperation($color: String) {
  getTotalVehicals(color: $color) {
    totalCars
    totalTrucks   
  }
}
Run Code Online (Sandbox Code Playgroud)

...带变量:{color:'something'}

您可以访问其他解析器中的变量:

{
  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'}
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 仅供参考,这仅在使用变量时有效.所以依靠信息可能不是一个好主意. (4认同)