Should I expect enum types to resolve automatically or do the types only exist to limit options?
Given a GraphQL Schema of the following:
type Job {
description: String!
status: Status!
}
enum Status {
PENDING_REVIEW
PENDING_APPROVAL
APPROVED
}
and a query that looks like:
query job {
description
status
}
If my database returned the following:
{ "description": "Some irrelevant job description", "status": 1 }
I would expect GraphQL to return:
{ "description": "Some irrelevant job description", "status": "PENDING_APPROVAL" }
Have I set something up incorrectly, or is this expected behaviour that will require me to write a resolver for status
const getQuestionStatus = ({ status }) => ['PENDING_REVIEW', 'PENDING_APPROVAL', 'APPROVED'][status];
In GraphQL.js, each enum value in an Enum Type may have an associated value with it. Setting this value is optional; it defaults to the string representation of the value's name. That is, for an enum like:
enum ExampleEnum {
FOO
BAR
}
by default, the value for FOO
will be "FOO"
. If you're using graphql-tools
to build your schema (or using apollo-server
, which uses graphql-tools
under the hood`) we can pass in the values for an Enum type right in our resolvers:
const resolvers = {
Query: {
example: () => 11, // field with ExampleEnum type
},
ExampleEnum: {
FOO: 11,
BAR: 23,
},
}
Once we've done that, we can return the defined value in our resolver and it will be serialized into the appropriate Enum value. Note: the same is true of enums that are used as arguments -- if FOO
is passed in as an argument, the resolver will actually receive a value of 11
.
Not providing any values is equivalent to doing:
ExampleEnum: {
FOO: 'FOO',
BAR: 'BAR',
}
It's also worthwhile to note that providing values has no impact on how the enum values are shown in the response. When the execution result is serialized into JSON, enum values are always shown as string values that match the names of the enum values (i.e. "FOO"
and "BAR"
in our example).
What about vanilla GraphQL.js?
Values for enum values can also be provided if you define your schema programatically. Here's an equivalent of the above example:
const ExampleEnumType = new GraphQLEnumType({
name: 'ExampleEnum',
values: {
FOO: {
value: 11,
},
BAR: {
value: 23,
},
},
})
Yes, you need to write a resolver from the enum values to whatever you need, e.g. numbers, per the apollo-server docs for Internal values. Here's how to do this in TypeScript:
export enum Status {
DRAFT,
PENDING,
APPROVED
}
const typeDefs = gql`
enum Status {
DRAFT
PENDING
APPROVED
}
type Query {
echo(status: Status!): Int!
}
`;
const resolvers = {
Status: {
DRAFT: Status.DRAFT,
PENDING: Status.PENDING,
APPROVED: Status.APPROVED
},
Query: {
echo(_, { status }): String {
console.log(status);
return status;
}
}
};
Here's a Code Sandbox showing automatic enum parsing and return.
Note though that for default enum values that are query parameters, the behavior is dubious - the resolver may receive the enum value as a string, or undefined
.
I think you need to implement resolver for it.
However, if you are using Apollo Server
, it has a feature called Internal Values where you can use 1
as an internal value in the resolver, Apollo Server
will automatically map it to PENDING_APPROVAL
when returning the response.
This depends on the language you are implementing GraphQL in. Enum types in GraphQL are just enum types and nothing more. This means, for example, your APPROVED
enum type doesn't evaluate to anything. This allows the developer more room to do what they want with them. If you want an enum to map to integers, you'll need a resolver as you described.
From the GraphQL article on schemas and types:
Note that GraphQL service implementations in various languages will have their own language-specific way to deal with enums. In languages that support enums as a first-class citizen, the implementation might take advantage of that; in a language like JavaScript with no enum support, these values might be internally mapped to a set of integers.