Reputation: 123
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
Reputation: 584
While there isn't a perfect solution for this IMHO
there are a couple of ways I would approach this problem
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]
}))
}
};
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