GraphQL 操作名称
GraphQL Operation Name
当我在后端(即 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
}
问题
- 能否在后端定义中定义操作名称?
- 如果对上一个问题是肯定的,这样做有什么好处,特别是比较示例 2 和 3?
不,您不能在后端定义操作名称,因为操作是动态的,由 API 的消费者创建。我相信您在这里混合了概念。无论您决定构建您的架构(updateOrder
或 makeOrder****
),您最终要说的是:
Here are the mutations that this server can handle, have fun!
您的消费者可以决定发出任意数量的不同查询,例如我可以很好地决定在一个操作中执行:
mutation TryToBreakAPI {
makeOrderCanceled {
id
}
makeOrderPending {
id
}
}
根据 graphql 规范,突变按顺序执行(与并行执行的查询相比),因此它将首先调用 makeOrderCanceled
解析器(及其子级),然后 makeOrderPending
解析器(及其子项)。
记录操作名称仍然是一个好主意,可以更轻松地调试私有 APIs,因为您可以要求您的前端工程师编写一个,这样如果查询失败,可以更容易地调试它的到来从。但这不是灵丹妙药,因此您通常也应该记录完整的查询(如果只是为了捕获一些可能试图以意想不到的方式使用您的 API 的潜在恶意行为者)。
有一些方法可以限制您的服务器可以接受的查询,这通常称为 query whitelisting
并且它的实现将取决于您使用的服务器(老实说,您甚至可以自己构建)。它通常包括对前端使用的每个查询执行 SHA256,并告诉后端仅接受散列为“已批准”散列之一的查询。
当我在后端(即 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
}
问题
- 能否在后端定义中定义操作名称?
- 如果对上一个问题是肯定的,这样做有什么好处,特别是比较示例 2 和 3?
不,您不能在后端定义操作名称,因为操作是动态的,由 API 的消费者创建。我相信您在这里混合了概念。无论您决定构建您的架构(updateOrder
或 makeOrder****
),您最终要说的是:
Here are the mutations that this server can handle, have fun!
您的消费者可以决定发出任意数量的不同查询,例如我可以很好地决定在一个操作中执行:
mutation TryToBreakAPI {
makeOrderCanceled {
id
}
makeOrderPending {
id
}
}
根据 graphql 规范,突变按顺序执行(与并行执行的查询相比),因此它将首先调用 makeOrderCanceled
解析器(及其子级),然后 makeOrderPending
解析器(及其子项)。
记录操作名称仍然是一个好主意,可以更轻松地调试私有 APIs,因为您可以要求您的前端工程师编写一个,这样如果查询失败,可以更容易地调试它的到来从。但这不是灵丹妙药,因此您通常也应该记录完整的查询(如果只是为了捕获一些可能试图以意想不到的方式使用您的 API 的潜在恶意行为者)。
有一些方法可以限制您的服务器可以接受的查询,这通常称为 query whitelisting
并且它的实现将取决于您使用的服务器(老实说,您甚至可以自己构建)。它通常包括对前端使用的每个查询执行 SHA256,并告诉后端仅接受散列为“已批准”散列之一的查询。