首页 > 解决方案 > GraphQL 操作名称

问题描述

当我在后端(即 Apollo)上设置我的 GraphQL 定义时,定义操作名称有什么方法或好处吗?

例如,我有一个可以将枚举作为参数的更新操作:

mutation {
  updateOrder(status: StatusEnum): Order
}

但我在想我可以为每个状态做特定的命名操作,后端解析器连接到每个状态(随后知道“好的,我是取消解析器,我不需要关心一些枚举” )。

mutation {
  makeOrderCanceled(): Order
  makeOrderPending(): Order
  makeOrderComplete(): Order
}

resolvers = {
  makeOrderCanceled: () => {
    // don't need to infer the status from a param, in essence could 
    // just hardcode the enum here and prevent the API consumers from 
    // having to know about it.
  }
}

这很好,可能我会这样做。但这省略了操作名称。我读过它对日志记录很有用,并且作为实际 HTTP 请求的一个字段出现。我明白了。但是,如果我将我的类型、查询和突变定义为后端开发人员,我能做些什么来帮助改进我的架构的意图和建议使用吗?例如,我能看到的最后一种方法是这样的:

mutation CancelOrder {
  updateOrder(status: "cancel"): Order   # this
  updateOrder(): Order                   # or this like the examples above
}

mutation CompleteOrder {
  updateOrder(status: "complete"): Order  # this
  updateOrder(): Order                    # or this like the examples above
}

问题

标签: graphqlapollo-servergraphql-js

解决方案


不,您不能在后端定义操作名称,因为操作是动态的并且由 API 的使用者创建。我相信你在这里混合概念。无论您决定构建架构(updateOrdermakeOrder****),您最终要说的是:

这是该服务器可以处理的突变,玩得开心!

您的消费者可以决定发出任意数量的不同查询,例如,我可以很好地决定在一个操作中执行:

mutation TryToBreakAPI {
   makeOrderCanceled {
     id
   }
   makeOrderPending {
     id
   }
}

根据 graphql 规范,突变按顺序执行(与并行执行的查询相比),因此它将首先调用makeOrderCanceled解析器(及其子代),然后是makeOrderPending解析器(及其子代)。

记录操作名称仍然是一个好主意,可以更轻松地调试私有 API,因为您可以要求前端工程师编写一个,以便在查询失败时更容易调试它的来源。但这不是灵丹妙药,因此您通常也应该记录完整的查询(如果只是为了捕捉一些可能以意想不到的方式尝试使用您的 API 的潜在恶意行为者)。

有一些方法可以限制您的服务器可以接受的查询,这通常被称为query whitelisting,它的实现将取决于您使用的服务器(老实说,您甚至可以自己构建)。它通常包括对前端使用的每个查询进行 SHA256,并告诉后端只接受散列到“已批准”散列之一的查询。


推荐阅读