【问题标题】:Graphql-Access arguments in child resolvers子解析器中的 Graphql-Access 参数
【发布时间】:2018-07-01 03:53:03
【问题描述】:

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

type TotalVehicleResponse {
  totalCars: Int
  totalTrucks: Int
}

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

schema {
  query: RootQuery
}

和Resolver函数是这样的

{
  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
        .........
        .........
      }
    }
  }
}

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

【问题讨论】:

    标签: graphql apollo graphql-js apollo-server


    【解决方案1】:

    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
          }
        }
      }
    }
    

    【讨论】:

    • 请查看此综合链接prisma.io/blog/…
    • 请不要这样做。它导致解析器之间的紧密耦合并且不能很好地扩展。每个解析器都应该直接从查询中接收自己的参数。请查看 cYee 的答案以获取更多信息:stackoverflow.com/a/63300135/7948938
    • 这看起来像是一种解决方法,但它不是一个合适的解决方案。
    【解决方案2】:

    如果您知道自己使用的是变量,除了接受的答案之外,还有另一种方法,使用解析器函数的第四个参数:info

    这个info 参数包含一个字段variableValues 以及其他字段。 此字段不严格包含父级的args,但如果您的操作是使用传递给父级解析器的变量执行的,那么您将可以通过所有相关解析器函数的 info.variableValues 访问它们。

    所以如果你的操作是这样调用的,例如:

    query GetTotalVehicalsOperation($color: String) {
      getTotalVehicals(color: $color) {
        totalCars
        totalTrucks   
      }
    }
    

    ... 带有变量:{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'}
          }
        }
      }
    }
    

    【讨论】:

    • 仅供参考,这仅在使用变量时有效。因此,依赖信息可能不是一个好主意。
    • 谢谢@Trevor。我已经更新了我的答案以澄清这一点。
    • 请查看此综合链接prisma.io/blog/…
    【解决方案3】:

    将您的参数添加到字段

    (客户端)更改自:

    Car(type: $type, materialType: $materialType){
      id
      material
      name
      ...
    }
    

    (客户端)收件人:

    Car(type: $type){
      id,
      material(materialType: $materialType) // moved here
      name
      ...
    }
    

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

    加长版

    尽量不要通过root 传递你的参数,除了IDsarguments that is not from clienta parent object,其他任何东西都使用字段级参数 (除非你有一个非常好的理由不

    为什么?

    有几个原因:

    1. 紧耦合

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

    2. 难以排除故障

      一个级别仍然可以,但是当您公司中的某个人找到一种方法将参数深入到根源时,很难调试它是如何丢失的。

    3. 向孩子泄露不必要的信息

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

    4. 混合父对象和参数

      您的父对象可能具有与参数相同的属性键,例如: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)

    长啸结束。

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

    这部分是回答主持人的问题。

    我的问题是如何访问根目录中可用的 args 任何子解析器中的解析器(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
    }
    

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

    // 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 ....
       }
    }
    

    在您的客户查询中

    (客户端)

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

    getTotalVehicles(color: $color){
      totalCars(color: $color) <-- add your variable here
      totalTrucks(offset: $offset, limit: $limit) <-- add your variable here
    }
    

    【讨论】:

    • 这是正确答案。解析器之间不应共享参数;这会导致耦合,并且很难以这种方式扩展模式
    • 最好的也是唯一正确的答案!谢谢!很难找到有关如何处理此问题的 clair 文档!
    【解决方案4】:

    了解更多关于变量在 GraphQL 中的使用

    请参考这些链接(您可以在不到 5 分钟的时间内浏览这些链接)

    https://graphql.org/learn/queries/#operation-name

    https://graphql.org/learn/queries/#variables

    https://graphql.org/learn/queries/#fragments

    https://graphql.org/learn/queries/#using-variables-inside-fragments

    您将更多地掌握操作名称、变量、片段以及片段内变量的使用。

    看看这个链接:https://www.prisma.io/blog/graphql-server-basics-demystifying-the-info-argument-in-graphql-resolvers-6f26249f613a

    它将帮助您了解更多关于解析器函数的info参数。

    【讨论】:

    • 这些链接没有解释如何像 OP 要求的那样在解析器之间共享参数。如果您的意图是表明 OP 不应首先尝试在解析器之间共享 args,则应在您的回答中予以澄清
    猜你喜欢
    • 2018-10-21
    • 2017-02-05
    • 2022-01-12
    • 2021-08-22
    • 2019-07-14
    • 2019-03-28
    • 2019-08-07
    • 2018-11-28
    • 2018-07-15
    相关资源
    最近更新 更多