Validation and User Errors in GraphQL Mutations

Konstantin Tarkus
Mar 8, 2016 · 3 min read

In this blog post I would like to propose the pattern which you can use to handle user input validation and user errors in your GraphQL API server. It’s based on the assumption that there is a clear distinction between system and user errors. For example, if you send a query to a GraphQL mutation endpoint with some required input arguments omitted, you would get a response similar to this one:

{
errors: [
{ message: 'Filed "createUser" argument "email" of type
"String!" is required but not provided' }
]
}

This type of errors is not supposed to be displayed to end users. It helps with debugging, error tracking etc. But it’s considered to be exceptional, only happening if there is a bug or some critical run-time issue in your program.

It is often required to perform additional validation of the input parameters passed to GraphQL mutations, and provide user-friendly localized error messages in case validation fails or mutation cannot be completed successfully.

Each of these error messages should contain the name of the input argument that didn’t pass validation and the reason why it failed. It would also be helpful to support multiple error messages per input field, as well as error messages that are not associated with any particular field.

So, here is how the schema of a GraphQL mutation may look like:

type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload
}
type CreateUserInput {
email: String!
password: String!
}

type CreateUserPayload {
user: User
}

And here is an example GraphQL query for it:

mutation M {
createUser(input: {
email: "hello@tarkus.me",
password: "Passw0rd"
}) {
user { id email }
}
}

If the mutation fails, the GraphQL response to this query may look as follows:

{
errors: [{
message: 'Request is invalid.',
path: ['createUser'],
state: {
'': ['Failed to create a new user.'],
email: ['A user with this email already exists.']
},
...
}]
}

The state field is just an object with keys representing the names of input parameters that didn’t pass server-side validation and an array of error messages for each of these keys. There is also a special case '' field that may contain one more errors that are not related to any particular input field.

In your client app, you can now grab this info, highlight the form fields that caused these errors and ask the user to fix errors and submit the form again.

Here is how a JavaScript implementation of this GraphQL mutation with form validation may look like:

The mutation code above validates the input by using validator.js library, builds an array of error messages and throws a custom error before saving data into the database. Let’s see how this ValidationError class looks like:

Note: This syntax only works if don’t compile classes into ES5 code.

The purpose of this class is to reshape the list of error messages into format that can be easily consumed on the client.

And at last, you would need to tweak express-graphql middleware to include this custom errors into a response.

app.use('/graphql', expressGraphQL(req => ({
...
formatError: error => ({
message: error.message,
state: error.originalError && error.originalError.state,
locations: error.locations,
path: error.path,
}),
})));

I hope this helps. Happy coding!

For a complete example visit Node.js API Starter Kit on GitHub.

Konstantin Tarkus

Written by

Bringing the technical edge to early-stage companies with advice on software architecture, best practices, database design, web infrastructure, and DevOps.

Konstantin Tarkus

Written by

Bringing the technical edge to early-stage companies with advice on software architecture, best practices, database design, web infrastructure, and DevOps.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store