How to design GraphQL queries and mutations: enum type

In the first part of this series we discussed the different built-in scalars available in the GraphQL specification. In this part we will concentrate on enums. The enum type is the second type in the GraphQL specification that can be used as a primitive value. In this part we will extend the task definition from the previous part and we will add a new field called “state” classified as an enum.

We will continue with the same repository. You can clone the GitHub repository using this command

git clone https://github.com/a7v8x/express-graphql-demo.git -b feature/3-graphql-scalars

In this part, we will extend the fields of Task type defined in the previous part of this series. If you are new to GraphQL, it might also be helpful to check out our previous articles in GraphQL mastery publication, especially the one on input object type and setting up basic GraphQL server. We use them as prerequisites for this article in terms of understanding GraphQL, and we will also use parts of the code that we built in previous articles. In the following image we illustrate the hierarchical tree graph of the response for our queries and mutations

the hierarchical tree graph of the response for our queries and mutations

Enum Types

Enums are basically a special type we can use to enumerate all possible values in the field. By using Enums we are adding another kind of validation to existing GraphQL schema. The specified values of the Enum type are the only possible options that are accepted. Now let’s go right into the implementation.

Let’s consider that in our Task type we also define Enum for the task state. We design this enum type with the consideration that a given task can have one of three states:

  • assigned;
  • unassigned;
  • inProgress.

In the GraphQL query language we can write it in the following form

In GraphQL language, these values are automatically mapped to the name of the value. However, when we rewrite the TaskStateEnum with graphql-js, we can also write the enum type in the following form:

taskStateEnumType.js

The enum class allows us to map enum values to internal values represented by integers (or different strings etc.). However, why we map the string values onto integer values in this example? By defining enumerated values to an integer leads you to design your schema in the most efficient way in terms of performance. In our case, we did not use any real database and did not send it to some more complex backend infrastructure. However, in production you will often use some monolithic or microservice architecture. It is much more efficient to send these enum values using integers, as the size is much smaller and can be transferred over the network more quickly. Also, it is more efficient to manipulate integer values in the database.

Now we can implement our defined state in our Task definition:

extended taskType.js for state field

All possible values for the state field are now available through introspection in GraphiQL

All possible values for the TaskStateEnumType

Now let’s move on to result and input coercion. If you do not know what that means, it might be usefull to go through the article on scalars and its input and result coercion.

Result coercion for enums

If we receive a different value from the database, that is not defined in enum type, an error is raised. For example, let’s change the value of the model Task state in the “in-memory” db (taskDb.js file) to badstate. And then execute the following query for retrieving tasks from the server

query for retrieving tasks from the memory db

The GraphQL server will raise the following error:

Expected a value of type \”TaskStateEnumType\” but received: badstate

The important thing to recognize is also the fact that if we change the state from integer value 1 (unassigned) to the string value "unassigned" the GraphQL will also raises the same type of error:

Expected a value of type \”TaskStateEnumType\” but received: unassigned

GraphQL server cares about internal value mapping when dealing with result coercion, therefore will raise the error when no internal enum values matches the received data. If the data are matched to enumerated values, these data values are then mapped according to enum specification, e.g. 2 will be mapped to inProgress. However, when we use float 1.0 as a value for the state field of the task in the “in-memory” db. The value is then transformed to the integer 1and GraphQL does not raise an error as the data are available in the TaskStateEnum specification.

Input coercion for enums

When we deal with input coercion for enums, we have to take into account additional validation for enumerated values. The GraphQL server will check if the values for the enum field matches defined values in the schema. Therefore if we execute the following mutation for adding task with state argument badstate

the GraphQL server would raise the following error.

Argument \"input\" has invalid value {name: \"task with bad state\", state: badState}.\nIn field \"state\": Expected type \"TaskStateEnumType\", found badState.

The offen error in graphiql is the execution of this addTask mutation

It is not allways predictable that it will raise the following error

Argument \"input\" has invalid value {name: \"Next task\", state: \"assigned\"}.\nIn field \"state\": Expected type \"TaskStateEnumType\", found \"assigned\".

The correct way to pass enum inline arguments in GraphiQL is just to specify enumerated values without the quotation

This is different, of course, when we specify mutations using variables, as the variable has to be written according to JSON syntax specification. In that case, we have to use strings. You can check out the GraphQL specification for more information on this topic.

Did you like this post? Then clap for this article as it is easier for others to find it. The repository with the examples and project setup can be cloned from this GitHub branch. You can get early access to upcoming free GraphQL course by subscribing at graphqlmastery.com.