GraphQL SDL 枚举类型

GraphQL SDL enum types

我们在 SDL 中定义了一堆枚举类型,它们非常适合查询和变更。 在解析器部分,这些被映射到代表后端枚举的字符串。

例如在 SDL 中我们有:

enum WRRole {
    USER
    PROVIDER
    SUPPORT
    ADMIN
    SUPER_ADMIN
    GUEST
}

在解析器部分我们有:

WRRole: {
   USER: 'user',
   PROVIDER: 'provider',
   SUPPORT: 'support',
   ADMIN: 'admin',
   SUPER_ADMIN: 'super admin',
   GUEST: 'guest'
},

解析器使用 Mongoose 匹配 nodejs 后端中定义的枚举值,其中字段定义为:

...
roles: {
  type: [
    {
      type: String,
      enum: ['user', 'provider', 'support', 'admin', 'super admin', 'guest']
    }
  ],
  default: ['user']
},
...

GraphQL 枚举的问题是我们无法自省枚举并使用 GraphQL 自省取回映射....

这会导致构建 UI 时出现问题,我们希望在其中向用户显示这些选项的下拉列表。 SUPER_USER 等 SDL 枚举值非常适合键,但我们希望显示实际的后端映射值以供 select 使用。

这只是我们拥有的众多枚举中的一个示例。许多映射值由多个单词组成,这些单词之间有空格或包含 SDL 枚举值中不允许的字符的单词,例如本例中的 "super admin"。

所以我的问题是......你们是如何处理这样的事情的,而不必重复自己或向前端添加更多代码以将这些映射到更有用的有意义的名称以进行展示????

无法保证顺序与后端枚举的定义顺序相匹配,因此添加到后端模型枚举会严重破坏 SUPER_USER 实际上映射到 "super user" 的任何假设,即使解析器知道这一点。

此致

史蒂夫

虽然没有针对此恕我直言的完美解决方案 有几种方法可以解决这个问题

  1. 优雅的方式
    您可以向 graphql 模式添加一个接收 Enum 名称的查询 像这样(在 SDL 中):

    type Query {
         getEnumValues(enumName: String!): [EnumKeyValue!]!
    }
    
    type EnumKeyValue {
         key: String!
         value: String
    }
    

    这需要您稍微更改后端代码,例如我会更改 Enum 解析器以从对象中获取数据,如下所示:

    const enums = {
        WRRole: {
            USER: 'user',
            PROVIDER: 'provider',
            ...
        }
    };
    
    const enumResolver = {
        WRRole: {
           USER: enums.WRRole.USER,
           PROVIDER: enums.WRRole.PROVIDER,
           ...
        }
    };
    

    然后 getEnumValues 的解析器看起来像:

    const queryResolvers = {
          getEnumValues(source, args) {
               const enumKey = args.enumName;
    
               // enums is the same enums object from the previous example
               return Object.keys(enums[enumKey]).map(key => ({ 
                    key,
                    value: enums[enumKey][key] 
               }))
    
          }
    };
    


  2. 肮脏、辱骂但很快
    另一种可能的方式,有点滥用是在 Enum 值上添加描述 所以你的 Enum SDL 想要:

        enum WRRole {
          # user
          USER
          # provider
          PROVIDER
          # support
          SUPPORT
          # admin
          ADMIN
          # super admin
          SUPER_ADMIN
          # guest
          GUEST
        }
    

    然后您可以通过以下查询获取键和描述之间的映射:

        {
          __type(name: "WRRole") {
            enumValues {
              description
              name
            }
          }
        }