Introducing MediQL

A Developer Tool to Enhance GraphQL Responses and Error Handling

NoahT
6 min readMay 12, 2023

Co-Authors: James Huang, Lily Hoong, Jake Ruiz

GraphQL Errors are Incomplete

GraphQL is a very useful tool for specific circumstances — it was designed to return select data from large queries consisting of many bundled single requests handled by resolvers. Using HTTP methods for transferring data (GET, POST, PUT, etc.), developers receive a request response status. Even non-developers are surely familiar with the “404 Not Found” error. But web developers know there are many more nuanced codes that are useful for understanding what is happening on the other side of a request. A “200 OK” is ideal, but errors happen. If they occur, GraphQL does not inform developers of these HTTP errors. Unless something goes awry in the GraphQL request itself, it will return the entire response as “200 OK” even when one or more of the resolver responses are, in fact, not OK.

If there are errors in a GraphQL response, they are sent back as an array in its response object. Insofar as the individual resolver queries are concerned, there may be an entry in the errors array that highlights errors in data, that is, in a resolver’s request or response. This will point to which resolver the error occurred in but it won’t always be clear what the problem is and it definitely won’t give us an HTTP code. If developers are using RESTful APIs and/or are sending HTTP requests in their GraphQL resolvers, they are missing information when handling GraphQL query responses.

How Can GraphQL Error Handling be Improved?

There are a number of methods available for a developer to better handle GraphQL errors. There are GraphQL libraries, such as Apollo, that have their own tools for dealing with errors. There are also techniques described nicely by other developers that show us how to write custom error handling into a GraphQL schema. While these approaches have their place and are not lacking in ingenuity, we found that there is a need for a lightweight tool requiring little setup that will give the developer more detailed information from resolver responses, errors or otherwise. We set out to make GraphQL responses more complete and error handling less opaque.

Introducing MediQL

Our solution to getting the HTTP status codes and messages into a GraphQL response is to capture that information when the resolver gets a response from its call. We designed MediQL to work with GraphiQL, an open-source web-based integrated development environment (IDE) built into the express-graphql package. MediQL enhances GraphiQL by delivering query response visualization, HTTP error indication, and the ability to observe API response statuses and objects that GraphQL does not provide. Once all the resolver responses come through, MediQL combines them with the GraphQL response, and then visualizes it into an interactive tree model with branches representing each resolver. The MediQL response object and its visualization includes all the data you would receive from a traditional HTTP request. Ultimately, MediQL combines GraphQL responses with REST/HTTP responses into one easy to read visual interface.

How to Use MediQL

Since MediQL leverages express-graphql and its GraphiQL utility, your GraphQL server needs to incorporate these technologies. Additionally, you will need a MongoDB collection to handle the GraphQL data from your project.

To use MediQL, you will need two pieces of software: the MediQL application repository and the mediql npm package to use in you GraphQL project. First, fork and clone this repository from GitHub. We will set this up in a moment.

Next, in your GraphQL project, install the mediql npm package.

npm i mediql

The mediql package contains two functions: postOriginResp and postQueryResp which will be explained as they are invoked in the following instructions.

The GraphQL server needs to be set up with Express.js with graphqlHTTP from the express-graphql package handling the GraphQL queries through the /graphql path. Additionally, GraphiQL needs to be enabled. In the server.js/ts file of your GraphQL project, you will need to import express-graphql, mediql, and set up the /graphql path as follows:

server.js/ts in your GraphQL project

...
...
const { graphqlHTTP } = require("express-graphql");
const { postQueryResp} = require("mediql");
...
...
app.use(
"/graphql",
graphqlHTTP({
schema,
graphiql: true,
context: ({ req }) => ({ req }),
extensions: async (
{ document, variables, operationName, result }) => {
//invoke postQueryResp function with the argument of result.
postQueryResp(result);
},
})
);
...
...

Once the server is set up, the GraphQL resolvers need to be addressed. The second function from the mediql package, postOriginResp, needs to be placed into every resolver to capture the resolver response. postOriginResp takes three arguments as described below:

postOriginResp function explanation

//inside the resolver, declare & assign the response
//variable as the result of your fetch request
const response = await fetch("url");

//declare & assign the parsedResponse variable as the
//parsed JSON response of your response variable
const parsedResponse = await response.json();

//invoke postOriginResp with the arguments
//response, parsedResponse, and info
//the info parameter comes from the resolver function
postOriginResp(response, parsedResponse, info);

//return parsedResponse as this is the typical GraphQL resolver set up
return parsedResponse;

Your resolvers don’t need any special setup except that the resolve function must include the “info” argument in order to pass it into postOriginResp. The code below shows how a resolver may look:

resolvers in your GraphQL project

...
...
const RootQuery = new GraphQLObjectType({
name: "RootQueryType",
fields: {
YOUR_FIELDNAME: {
type: YOUR_TYPE,
async resolve(parent, args, context, info) {
try {
const response = await fetch(
"YOUR_REST_API_URL",
{
headers: {"content-type": "application/json"},
}
);
const parsedResponse = await response.json();
postOriginResp(response, parsedResponse, info);
return response;
}
...
...
}

This needs to be done with every resolver in the RootQuery. Once you have completed this, your nearly set to use MediQL.

The final step is to establish a connection to MongoDB in your local MediQL repository. All data is deleted from the MongoDB documents as soon as the query is complete. You will also never reach the storage limit if you’re using the free tier of MongoDB and any sensitive data will never persist. The server.ts file in MediQL shows you where you need to put your credentials. It uses the Mongoose ORM to work with MongoDB.

server.ts in MediQL repository

...
...
const db = YOUR_MONGODB_URI;

mongoose
.connect(`${db}`)
...
...

Now you are ready to use the MediQL application. First, run your GraphQL project on any port except for 3003 which is the server port for MediQL. In the root folder of MediQL, open up a terminal and run:

npm run dev

Visit localhost:8080 in your browser. There is a form element for you to enter the port of your GraphQL project into. Put it in and begin using MediQL.

When and Why to Use MediQL

MediQL is designed as a developer tool, so it’s best suited for developing GraphQL schemas. MediQL’s query response visualization allows developers to view the response data in a structured and intuitive manner. This makes it easier to understand and analyze complex GraphQL responses, especially when dealing with deeply nested data. Integrating with GraphiQL, MediQL enhances an already familiar and helpful IDE.

MediQL’s ability to show the complete API HTTP response can highlight problems with specific parts of a GraphQL schema. This allows developers to monitor and debug any issues that may arise from individual resolvers. This can improve a developer’s efficiency in schema troubleshooting and development. In addition to receiving errors, the entire API response is available to view at the click of a button. While the point of GraphQL is to target specific parts of the resolver’s response and not over fetch, it can be a helpful reminder during development to see what is entirely available from any given API.

In certain scenarios, GraphQL is a beneficial tool to utilize. When choosing to use any piece of technology, there are benefits and disadvantages to each choice. We hope that MediQL minimizes some of the disadvantages developers may experience when using GraphQL in their project.

Meet the Team

Lily Hoong — LinkedInGitHub
James Huang — LinkedInGitHub
Jake Ruiz — LinkedInGitHub
Noah Tofte — LinkedInGitHub

--

--