Introducing graphErr: solving GraphQL’s questionable query response quirks.
GraphQL has rapidly increased in popularity in large part due to its out-of-the-box solution to one of the main drawbacks of a RESTful API — under and over fetching data. GraphQL was created by Facebook as a new API standard that provides a more efficient, powerful, and flexible alternative to REST. It has seen widespread adoption in the industry, including big tech companies such as Twitter, Expedia, and Shopify. The many benefits of GraphQL, however, do not come without their own set of challenges. We set out to fix some of them.
By way of comparison, the standard RESTful API architecture works on top of HTTP transport, and as such takes advantage of HTTP’s native GET, PUT, POST, and DELETE methods. Requests sent to a RESTful API adhere to the constraints of the API architecture, are often sent to an endpoint specified in the URL, and typically get a standard JSON, XML, or HTML response back, along with a HTTP status code. These status codes make handling client-server requests and responses fairly straightforward, with a 2xx code indicating success, and a 4xx or 5xx code indicating an issue on the client or server respectively. A request sent to a RESTful API either works or it doesn’t; there is almost never an in-between. Unfortunately, this is not the case with GraphQL, as non-2xx response codes indicate that some issue occurred at the HTTP transport layer, not the GraphQL layer.
GraphQL doesn’t replace the HTTP transport; GraphQL is protocol agnostic, and is in fact typically served over HTTP via a POST request to a single endpoint. This is one area where an additional layer of conceptual complexity is needed as developers can no longer rely on the server response codes to base their logic around. For example, let’s say that you need to query a database of users. Typically, you can provide the user ID number as an argument to the query to get back the specific users you needed from the database. If, however, your query does not include an argument and your schema does not require said argument, then you will receive a null response.
Additionally, if you supply a user ID argument that doesn’t exist in the data source, you’ll also get back a null value. Both of these scenarios will generate a server-side response code of 200 — meaning as far as the HTTP protocol (and GraphQL) is concerned, both were successful queries. As you can see, by separating the requests from the HTTP protocol response and providing null responses in certain situations, it is now a requirement for the developer to decipher what can be an ambiguous response from GraphQL.
Many of the major GraphQL middlewares and platforms have implemented some form of additional error handling for GraphQL queries to address issues such as the ones described above. However, when our team needed a lightweight solution for our GraphQL implementation, we couldn’t find one — both because we wanted to avoid opting into an entire platform like Apollo and because we were using Deno rather than Node.js.
Deno was created by Ryan Dahl, the creator of Node.js, as a sort of redo, a way to take the lessons learned from Node.js and create an even better runtime, one designed to avoid many of Node.js’s inherent problems. That isn’t to say that Node.js isn’t great, but a large part of its popularity stems from its first-to-market advantage and the huge ecosystem that has developed. While Deno doesn’t have the benefits of a huge ecosystem (yet!), it does surpass Node.js in several key areas, such as security, module handling, and dependencies. Faced with no lightweight Deno module to add extended error handling, our team set out to build our own.
Enter graphErr, an open-source error handling library for GraphQL implementations in Deno. In addition to expanded and illustrative error responses pulled directly from the formal GraphQL spec sheet, graphErr programmatically analyzes your GraphQL queries, adding a post-processing layer of error handling that reduces the conceptual burden on the developer by providing many of the benefits of RESTful API architecture. Our first step in creating graphErr was to determine which query formulations result in ambiguous responses, or responses that could be better aligned with the traditional RESTful architecture that most developers are used to. To that end, we built a fairly exhaustive table of query formulations and their ideal error response. We then set out to add error handling one by one.
We also saw an opportunity to add additional information to existing graphQL errors by displaying the GraphQL specifications covering the errors you receive. We even included a link to the specification to reference the documentation directly.
GraphErr aims to be lightweight and simple to use. It lowers the barrier to entry for developers looking to use GraphQL with Deno while also adding helpful information for seasoned GraphQL developers. It is currently built on top of the excellent oak_graphql middleware, and future plans include extracting functionality outside the middleware itself to better support a range of GraphQL options. We built graphErr to improve the development experience with our own GraphQL APIs, and to both new and seasoned GraphQL developers, we hope graphErr is helpful to you on your next project.
See more at www.grapherr.land or follow us on GitHub.
Meet the team:
Clay Sawyer: LinkedIn | GitHub
Loralyn Milcarek: LinkedIn | GitHub