Introducing Elucid, A GraphQL Error Detector For the Rest of Us

Giovanni Iacobucci
CodeX
Published in
6 min readAug 18, 2021

GraphQL does a lot of wonderful things, but it doesn’t make error detection for requests sent over HTTP particularly painless. Elucid would like to change that.

The Problem

Since GraphQL’s public release in 2015, an ever-growing number of software developers have turned to Facebook’s open-source query language to bolster their API game. GraphQL’s flexibility and potential for delivering precise responses with only the data a developer wants means less over- and under-fetching. That’s especially important in an age of increasing expectations for complex, rich, and dynamic mobile computing where every byte transmitted is weighed against time and usage.

Yet, with all that potential comes added complications. By way of comparison, consider the existing RESTful API architecture a GraphQL API is replacing. Under this configuration, a client makes an HTTP request (‘GET’, ‘POST’, ‘PUT’, or ‘DELETE’) to a specific URL, one that might look something like ‘https://www.example.com/users/{username}’. That final piece of the web address is the backend endpoint, a place where the client can ask for information about a given user. If the client mistakenly asks for information about a user that doesn’t exist and who can’t be found in the server’s database, it’s easy enough and standard RESTful practice for the server to return a 4xx error code in its response, indicating to the client side that it made a bad request.

By its very nature, GraphQL tends to throw a wrench into this process: your formulated GraphQL queries are (most likely) sent along as part of a standard HTTP protocol ‘POST’ request, but they’re all going to the same place: a single GraphQL endpoint. The server will respond to any request sent to this location with a JSON response object. I say “most likely” sent over HTTP, because GraphQL is transfer layer-agnostic. While it’s often found in the wild served over HTTP, there’s nothing in the GraphQL specifications that opines on how GraphQL ought to handle, for instance, setting status codes in an HTTP response, because GraphQL itself is not a replacement for HTTP, and can just as easily be served over, say, WebSockets.

Source: https://www.cosmicjs.com/blog/graphql-vs-rest-a-quick-guide

Put it this way: if you ask it a question, and GraphQL responds with, “I can’t find what you’re looking for,” or even, “The question you’re asking me doesn’t make any sense,” as far as GraphQL is concerned, that was a successful interaction and a perfectly valid response. For client-side developers used to the traditional RESTful paradigm, that’s something of a bummer, because it’s common to rely on server-set response status codes to inform what a client-side application ought to do with the response it receives. By replacing the static, explicit architecture of a RESTful API, GraphQL increases the conceptual complexity for a developer looking to interact with it, because now the burden is on them to make sense of the response in ways they didn’t have to worry about previously.

In addition to lacking out-of-the-box status code manipulation, error messaging can also become vague and ambiguous, because it’s not always clear when a “null” response field is the result of a queried-for data point simply not existing in the server, versus being the result of a malformed query or even an internal server error on the part of the GraphQL installation.

A smug Jedi librarian handling Obi-Wan’s search request as opaquely as GraphQL.

Now, this aspect of working with GraphQL has been known for a long time, and there are plenty of existing products on the market that include some version of error handling for GraphQL implementations over HTTP. There’s Apollo, a robust and full-featured platform that’s positioning itself as an entire data management solution; Relay, Facebook’s early offering, built for React applications; and Hasura, a “realtime GraphQL API engine” for databases, to name a few prominent names. These are all market-tested, robust, and very useful utilities. So why did we decide to make our own?

We wanted to build something that wouldn’t require opting into an entire network layer ecosystem between client and server, like Apollo, nor something that would be as opinionated about how you can handle your server’s responses as Relay. We just wanted something lightweight, direct, and easy to get off the ground. Something that felt less like an entire framework you’d have to adopt, and more like a plugin to make developer’s lives just a little bit easier and more illustrative when it comes to communicating with a GraphQL server. We knew we’d be building code that extended the functionality of graphql.js, the simple, “vanilla” client for Javascript developers looking to work within the GraphQL universe.

From that, we began to tackle the matter by setting up a testing environment and exploring as many possible error scenarios as we could think of, guided by a wealth of writing on GraphQL and error behavior already available. We created a “taxonomy of errors” to keep track of how to reproduce our errors, and how they manifested in responses sent back from the server. From this, we discussed how to reverse-engineer useful error handling language and when to alter the default 200 OK status codes sent back with responses to bring them more in line with RESTful status coding.

A couple of our working docs as we tried to comprehensively understand the potential emergence points for errors in talking to a GraphQL server.

At this stage, we had to decide whether to build directly atop graphql.js, or whether to bootstrap express-graphql, a popular package recommended in the official GraphQL documentation as a way to easily get a GraphQL server up and running. An obvious downside of building on top of express-graphql would be locking our potential users into using Express to handle their server setup. The upshot would be that express-graphql already came with built-in logic to identify many common bad requests that could result in a 4xx response, so we could focus our efforts on what it didn’t already take care of. Later, we could expand Elucid’s power to encompass what express-graphql was handling, making our tool more agnostic. Given how popular Express is, this felt like a fair trade-off for the time being.

Express-graphql has a default manner for handling errors it detects, although it provides for optional custom error handling configuration. Furthermore, it offers room for extensions, meaning we could define some additional post-processing behavior for the responses that passed express-graphql’s error checking. There, we could develop a secondary layer of error discovery and handling via our bespoke euclid() function.

This is where the magic happens: right in your own GraphQL server setup.
A closer look under the hood at Elucid’s logic.

We believe Elucid is the most straightforward error detection library for Javascript implementations of GraphQL available today. In the future, we would like to remove Elucid’s dependency on express-graphql, to make it a truly standalone solution. We hope you’ll give it a try and find that it helps illuminate the path forward in your own projects.

Visit Elucid online at www.elucid.dev

Interested in contributing or viewing Elucid’s code? Visit the Github project page.

Team Elucid is:

Khayal Alasgarov: LinkedIn | Github

Vivian Wu LinkedIn | Github

Spencer Szu LinkedIn | Github

Giovanni Iacobucci LinkedIn | Github

--

--

Giovanni Iacobucci
CodeX
Writer for

Software engineer, director of the movie "West Coast Gothic," and author of the Bridgetown series. Sans-serif fonts have ruined my last name.