Skip to main content

GraphQL Fundamentals

GraphQL is a powerful and flexible way to fetch data from the D&D 5e SRD API. In this tutorial, we will learn how to build and try out a range of GraphQL queries using the Apollo Sandbox Explorer.

✅ Learning Objectives

  1. Understand the limitations of the RESTful API
  2. Understand how the GraphQL API solves these limitations
  3. Build and test GraphQL queries with Apollo Sandbox Explorer

From REST to GraphQL

In the Getting Started tutorial, we used curl to make an HTTP GET request to a specific URL that returned the data we wanted. Using that approach, the URL we made a request to corresponded directly to the resource we wanted to fetch; /api/ability-scores/cha refers to the resource within the ability-scores collection which has the index cha.

This is one of the defining features of a RESTful API: a URL corresponds to a resource. The RESTful endpoints of the D&D 5e SRD API follow this uniform interface to make it easy for us to fetch the resources we need, but they don't allow us much control over what data is returned by the API.

For example, if we make a GET request to https://www.dnd5eapi.co/api/monsters, we will receive only the index, name and url of all the monsters in the SRD database. This is a sensible default, as it gives us the information we need to discover all the monsters, while keeping the response relatively lightweight by excluding unnecessary details. But what if I want to know more about a specific monster?

Making a request to one of the urls provided, such as /api/monsters/aboleth, we will receive all of the data about the Aboleth, including its stats, actions, proficiencies, etc. But what if we just wanted to know the Aboleth's armor class? We've just wasted time and bandwidth transporting all that extra information.

And what if we want to fetch the armor classes of all of the monsters? Using the REST API, we would have to make a separate request for every single monster in the API - that's 334 HTTP requests! Not only would this be slow, it would be a pain to implement.

This is where GraphQL saves the day. GraphQL stands for "Graph Query Language". It is a computer language that allows us to query an API much more flexibly than is allowed by the REST API. GraphQL allows us to specify exactly which parts of a resource we want to receive, and to request that data for many resources all in one request. In this tutorial, we will look at how we can build and execute powerful queries against the D&D 5e SRD API using GraphQL.

Sandbox Explorer

As well as data, GraphQL servers are able to serve their own schemas and documentation. This allows us to use tools such as the Apollo Sandbox Explorer to discover the API's capabilities and to build and test our queries.

Open the explorer in a new tab now so that you can follow along with the tutorial. You should see a page like this:

A screenshot of the Apollo Sandbox Explorer

On the left we can see the documentation - a list of all the resources we can query. In the middle are the text boxes where we can write our GraphQL query, as well as any variables that we might want to pass with the request. Finally on the right is the "Response" panel, where any results of queries we execute will be displayed.

Our First Query

Let's start by getting a list of all the monsters in the database. To do this, we can build a query using the panel on the left-hand side of the explorer. Scroll down to "monsters" and click the ("plus") icon to the left. You should then be presented with a list of attributes that we can request. You should also see the following code appear in the editor:

query Monsters {
monsters {

}
}

From the list on the left-hand side, scroll down to the "Fields" section and select name and index, and then click the blue "Monsters" button in the top-right corner of the "Operation" box to execute the query. The result should look like this:

A screenshot of the Sandbox Explorer with the query and its results

In the results pane, we can see the list of all the monsters in the database, and each entry only has the attributes we requested.

Nested Attributes

Now let's try getting the armor class of each monster. If we select the armor_class attribute from the list of fields, it appears in our query with a set of curly braces, like so:

query Monsters {
monsters {
name
index
armor_class {

}
}
}

We are also presented with a list of fields that exist inside the armor_class object. Let's select value and type, and execute the query again. Here's what we should see now:

A screenshot of the Sandbox Explorer with the nested query and its results

Here we can see that each monster now has an array of possible armor classes, and we can see the value and type of each one, but we haven't fetched any unwanted data, like the conditions or descriptions of the armor classes.

Take a moment now to try building some queries of your own. Use the documentation on the left of the screen to build your queries, or for an extra challenge, try writing a query by hand.

Fetching a Single Resource

You may have noticed that each top-level field in the documentation comes in a singular and a plural form. For example, abilityScore and abilityScores, monster and monsters. The plural forms denote fields that allow us to query a collection of resources, as we have seen with the monsters field, but the singular forms (e.g. monster) allow us to query a single resource. All we need is the resource's index, which is its unique identifier.

Let's try this out now.

Enter the following query into the Explorer:

query Monster {
monster(index: "aboleth") {
name
challenge_rating
hit_points
}
}

You will notice that we are making use of the index argument to specify that we want information about the Aboleth. When we execute the query, this is exactly what we get.

But what if we don't always want to fetch information about the same monster? To facilitate this, we can use variables. The query below declares a variable called $index, which must be passed a String value when we make our request.

query Monster($index: String) {
monster(index: $index) {
name
challenge_rating
hit_points
}
}

To pass variables, we can provide a JSON object along with our request, where each field corresponds to a variable. Add the following JSON code to the "Variables" box in the explorer:

{
"index": "aboleth"
}

Execute the query and we should see the same results as before, except this time we can request a different monster just by changing the value of our index variable. Take this opportunity to pass in different indices and observe how this affects the response.

Next Steps

Now that we can build and test a range of GraphQL queries, we are ready to apply these skills to a real project. In future tutorials, we will bring together GraphQL and other languages and technologies to build fun and interesting tools.