user1790230
user1790230

Reputation: 123

GraphQL SDL enum types

We have a bunch of enum types defined in an SDL and they work great for queries and mutations. In the resolvers section these are mapped to the strings which represent those enums in the back end.

For example in the SDL we have :

enum WRRole {
    USER
    PROVIDER
    SUPPORT
    ADMIN
    SUPER_ADMIN
    GUEST
}

And in the resolvers section we have :

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

The resolvers match the enum values defined in the nodejs backend using Mongoose where the field is defined as :

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

The issue we have with GraphQL enums is that we cannot introspect the enums and get back the mappings using GraphQL introspection....

This causes issues with constructing UI's where we want to present the user with a dropdown list of these as options. The SDL enum values such as SUPER_USER are great for the keys but we want to display the actual backend mapped value to the use to select from.

This is just one example of many enums we have. Many of the mapped values consist of multiple words that have spaces between or words containing characters not allowed in the SDL enum value such as "super admin" in this case.

So my question is... How are you all handling stuff like this without having to repeat yourself or add more code to the front end to map these to more useful meaningful names for presentation ????

The order cannot be guaranteed to match the defined order of the enums in the backend so adding to the backend model enums would seriously mess up any assumptions that SUPER_USER actually maps to "super user" even though the resolver knows this.

Regards

Steve

Upvotes: 6

Views: 3357

Answers (1)

Daniel Jakobsen Hallel
Daniel Jakobsen Hallel

Reputation: 584

While there isn't a perfect solution for this IMHO there are a couple of ways I would approach this problem

  1. Elegant way
    You can add to your graphql schema a query that receives the Enum name like so (in SDL ) :

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

    this requires you to change your backend code a bit, for instance I would change the Enum resolver to get it's data from an object like so:

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

    and then the resolver for getEnumValues would look like:

    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. Dirty, Abusive but quick
    Another possible way, that is a bit abusive is to add a description on the Enum value so your Enum SDL would like:

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

    And then you can get the mapping between the key and the description with the following query:

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

Upvotes: 3

Related Questions