An Enum is a special kind of scalar that is restricted to a particular set of allowed values. It can be used as both an input and an output type.
enum UserRole { GUEST, DEFAULT, ADMINISTRATOR}
type Query { role: UserRole usersByRole(role: UserRole): [User]}
Usage
Given is the schema from above.
When querying a field returning an enum type, the enum value will be serialized as a string.
Request
{ role}
Response
{ "data": { "role": "STANDARD" }}
When using an enum value as an argument, it is represented as a literal and not a string.
Request
{ usersByRole(role: ADMINISTRATOR) { id }}
When used as a type for a variable, it is represented as a string in the variables object, since JSON does not offer support for literals.
Request
Operation:
query ($role: UserRole) { usersByRole(role: $role) { id }}
Variables:
{ "role": "ADMINISTRATOR"}
Definition
We can define enums like the following.
public enum UserRole{ Guest, Standard, Administrator}
public class Query{ public User[] GetUsers(UserRole role) { // Omitted code for brevity }}
Non-enum values
In Code-first we can also bind the enum type to any other .NET type, for example a string
.
public class UserRoleType : EnumType<string>{ protected override void Configure(IEnumTypeDescriptor<string> descriptor) { // we need to specify a name or otherwise we will get a conflict // with the built-in StringType descriptor.Name("UserRole");
descriptor .Value("Default") .Name("STANDARD"); }}
public class QueryType : ObjectType{ protected override void Configure(IObjectTypeDescriptor descriptor) { descriptor.Name(OperationTypeNames.Query);
descriptor .Field("users") .Argument("role", a => a.Type<UserRoleType>()) .Resolve(context => { var role = context.ArgumentValue<string>("role");
// Omitted code for brevity }); }}
Binding behavior
In the Annotation-based approach all enum values are implicitly included on the schema enum type. The same is true for T
of EnumType<T>
when using the Code-first approach.
In the Code-first approach we can also enable explicit binding, where we have to opt-in enum values we want to include instead of them being implicitly included.
We can configure our preferred binding behavior globally like the following.
services .AddGraphQLServer() .ModifyOptions(options => { options.DefaultBindingBehavior = BindingBehavior.Explicit; });
This changes the binding behavior for all types, not only enum types.
We can also override it on a per type basis:
public class UserRoleType : EnumType<UserRole>{ protected override void Configure(IEnumTypeDescriptor<UserRole> descriptor) { descriptor.BindValues(BindingBehavior.Implicit);
// We could also use the following methods respectively // descriptor.BindValuesExplicitly(); // descriptor.BindValuesImplicitly(); }}
Ignoring values
In the Annotation-based approach we can ignore values using the [GraphQLIgnore]
attribute.
public enum UserRole{ [GraphQLIgnore] Guest, Standard, Administrator}
Including values
In the Code-first approach we can explicitly include values using the Value
method on the IEnumTypeDescriptor
. This is only necessary, if the binding behavior of the enum type is explicit.
public class UserRoleType : EnumType<UserRole>{ protected override void Configure(IEnumTypeDescriptor<UserRole> descriptor) { descriptor.BindValuesExplicitly();
descriptor.Value(UserRole.Guest); }}
Naming
Unless specified explicitly, Hot Chocolate automatically infers the names of enums and their values. Per default the name of the enum becomes the name of the enum type. When using EnumType<T>
in Code-first, the name of T
is chosen as the name for the enum type.
Enum values are automatically formatted to the UPPER_SNAIL_CASE according to the GraphQL specification:
Guest
becomesGUEST
HeadOfDepartment
becomesHEAD_OF_DEPARTMENT
If we need to we can override these inferred names.
The [GraphQLName]
attribute allows us to specify an explicit name.
[GraphQLName("Role")]public enum UserRole{ [GraphQLName("VISITOR")] Guest, Standard, Administrator}
This would produce the following Role
schema enum type:
enum Role { VISITOR, STANDARD, ADMINISTRATOR}