【问题标题】:How to ignore unknown enum values?如何忽略未知的枚举值?
【发布时间】:2019-09-16 10:35:00
【问题描述】:

我想知道在 GraphQL/Apollo 服务器中忽略/丢弃未知枚举值的最佳方法是什么。

假设我的 GraphQL 架构定义了枚举数组“enum Service { Supermarket, TicketSales }”,现在它工作正常,但后来我使用的其他服务正在添加一些新值(例如 Playground),而我的客户只是没有'不支持它,我只想忽略它并返回支持的值而不会出错。

在 GraphQL 中执行此操作的最佳方法是什么。我的第一个想法是制定指令,从模式中读取支持的值并忽略其他所有内容,但是在谷歌搜索之后,我没有找到任何好的例子。你能给我一个方向吗?

【问题讨论】:

    标签: graphql apollo-server


    【解决方案1】:

    如果您的解析器函数将接受任意字符串,那么您可以使用自定义标量类型,或者只是 String

    """
    The type of a service.  `Supermarket` means..., and
    `TicketSales` means...; any other value is ignored.
    """
    scalar Service
    

    GraphQL 通常将责任放在客户端以符合服务器的期望,而不是让服务器尝试支持任何请求。有几个地方可以合理地预期会出现这样的枚举值:

    enum Service { Supermarket, TicketSales }
    type Query {
      inAReturnValue: Service!
      asAQueryParam(service: Service!): Node
    }
    type Mutation {
      asAMutationInput(service: Service!): Node
    }
    

    特别是如果服务器不理解,告诉服务器“让这个对象的类型成为游乐场”可能没有意义。相反,如果服务器知道“playground”,它可以在客户端可能不期望的情况下返回它。在这里有一个枚举可以明确服务器所知道的内容。服务器已经说明了它支持的内容,客户有责任合作。

    请注意,客户端可以查明服务器是否支持 Playground,是否为枚举值,这可能有助于告知其行为。

    query GetServiceTypes {
      __type(name: "Service") {
        enumValues { name }
      }
    }
    

    【讨论】:

    • 感谢您的回复,我需要考虑一些好主意。在我的情况下,我们有很多不同的“支持的服务”类型,它们实际上是字符串数组,我想将它们映射到枚举的原因是它会让客户清楚哪些值可以预期而不是随机的字符串,当然我也会为它们输入打字稿。随着时间的推移,我们可能会引入一些我们还不支持的新服务,当然我的服务器需要以某种方式过滤掉这些服务,直到我们为它们建立支持。
    • 而我正在处理的数据来自另一个服务,所以基本上我可能会突然开始获得一些我不知道的新值。由于我的 graphql 模式已经定义了允许的值,我想知道是否有一些简单的方法可以只允许这些值而忽略其他所有内容?也许以某种方式使用自定义解析器和信息参数?
    【解决方案2】:

    在玩了之后,我发现了一些可以用来解决我原来的问题的东西,所以我会把它贴在这里,以防其他人有同样的疑问。

    所以我最初的问题是简而言之,我从另一个服务接收了几种不同的“可用服务”类型的字符串数组,我正在考虑将它们映射到枚举以获得更好的打字稿支持等。但问题是,如果我从另一个服务获取一些未知值,我的 graphql 将失败。

    所以我最初的想法是用我终于开始工作的指令来修复它:

    # In schema
    directive @mapUnknownTo(value: String) on ENUM
    
    enum SomeAttribute @mapUnknownTo(value: "__UNKNOWN__") {
      SomeAttribute1
      AnotherAttribute
      SomethingElse
      __UNKNOWN__
    }
    

    指令的实现是:

    import { SchemaDirectiveVisitor } from 'graphql-tools';
    import { GraphQLEnumType } from 'graphql';
    
    export class MapUnknownToDirective extends SchemaDirectiveVisitor {
      visitEnum(type: GraphQLEnumType) {
        const { value = '__UNKNOWN__' } = this.args;
        const valueMap = type.getValues().reduce((map, v) => map.set(v.value, v.name), new Map<string, string>());
        type.serialize = (v: string): string => valueMap.get(v) || value;
      }
    }
    

    因此,这会将架构中未定义的所有值映射到某个自定义值,这并不是我最初想要的,但至少它没有给出错误,所以没关系。

    我仍然不能 100% 确定指令是否可以处理这种情况,但至少这是一种可能的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多