by Luis Aguilar

A Guide to GraphQL in Plain English

All you need to know about the latest buzzword that’s taking the API development scene by storm.

TL;DR

GraphQL is a query language and runtime that we can use to build and expose APIs as a strongly-typed schema instead of hundreds of REST endpoints. Your clients see the schema. They write a query for what they want. They send it over and get back exactly the data they asked for and nothing more.

A schema looks like:

So, if a client wants a user with an ID of 2, instead of doing a GET /api/v1/users/2, they would rather send a query like this:

… and get a response like this:

Why should REST watch its back, and why should you care?

  1. The schema is strongly-typed. The schema dictates that the id parameter must be an integer. If a client sends user(id: “2”) instead, the GraphQL engine will reject the whole query.
  2. Clients pick what they need. See those braces after the query parameters? That’s how our clients tell which fields they want. Fewer fields = leaner and faster responses.
  3. It’s fast. Fields not picked won’t be processed, meaning less stress on the server.
  4. And most importantly, it’s flexible. If a client needs fewer fields from an endpoint, we don’t create a new endpoint or version our whole API exclusively for that need. They can pick whichever fields they need, and that’s free for us.

And that’s all there is to it, really. No magic is going on. Just a more convenient, flexible, and natural way of building your API.

But what is life without those juicy core concepts and sweet, sweet code examples?

The Big Five

Before moving onto the actual fun, there are some concepts we need to have in mind, otherwise everything else won’t make any sense.

Don’t worry—I’ll keep it short.

Query

A member of the schema that reads data.

Mutation

A member of the schema that modifies data (as in create, edit, or delete.)

Schema

A single-rooted tree with two primary nodes: one for queries, and another for mutations.

Type

The shape of everything composing the schema. The data returned by a query, the fields of that data, the parameters taken by a mutation, queries, and mutations themselves—everything has a type.

Types are composed of fields which also have a type.

Both the query and mutation initial nodes are of type Query and Mutation respectively. These have more fields, users and user, and their type can also have more fields! That’s how you structure your API data into a queryable tree.

Resolver

The actual piece that connects your code to your schema. Resolvers are actual functions that resolve the value of a single field in a type. The following is a very, very barebones pseudo example of how it works—don’t mind it too much.

Easy, right? Well, that’s it for theory, time for some code!

A Totally Original and Not Overused Code Example

Tired of the classic user model code example? Me neither! Okay, it might be dull and uninteresting, but it serves well to illustrate the previous concepts, so let’s stick to it. By the end, we’ll have an API clients will be able to query for users, roles, and create new users.

1. Create a Server

As already mentioned, GraphQL is a language, and a runtime—we still have to put it somewhere. For this example, it will live in an Express server.

So let’s get started:

  • Create a new folder.
  • Open a terminal and cd to your folder.
  • Run npm init && touch server.js
  • Run npm i express --save to, well, install ExpressJS.
  • Throw this into server.js:
  • Run the server with node server.js

And so we have a home for our GraphQL API.

2. Add a Pinch of GraphQL

As simple as:

  • Run npm i graphql graphql-express --save
  • Edit server.js like this:

And this is why it was essential to review the concepts before moving onto the code. This simple Hello World app already has a lot going on, but we can at least get an idea.

Don’t worry, here’s the annotated version:

Wait, are we hardcoding our schema using a huge magic string? Don’t panic— we’ll get to that later.

Okay, time to fire up Postman and send some queries to our GraphQL API!

Heh, just kidding…

At line 46 we enabled GraphiQL (pronounced “graphical,”) a built-in fully-featured IDE for writing queries. Now, close Postman and go to localhost:4000/graphql in your browser of preference.

GraphiQL: the best thing since the IE7 tax.

What can you do with this? Well, here are some things you can try:

  • View schema. To the right, select the Query root type to see its fields, return types, documentation, etc.
  • Write queries. To the left, type the following query, and notice how the editor shows autocompletion and documentation as you go:
  • Test queries. If your query is valid, hit that play button at the top and see the results in the middle pane.
GraphiQL: Everybody’s New Best Friend

But what about clients? They can use GraphiQL (or a similar tool—there are tons) to build and test their queries. Then send them over using a GraphQL client like Apollo Boost—as easy as copying and pasting!

3. Add a Query to List Users

All right, Hello World is fine and all, but we want to do more than greeting people. Let’s add a new User type, and replace hello with users which will return all users from a dummy repository.

  • Edit server.js like this:
  • Grab the user-repository.js file from here and put it in your local directory.
  • Restart your server and refresh the GraphiQL editor.
  • In your query, replace hello for users { id, login } and hit play.
  • Profit.
Building a Query: As Easy as 1–2–3.

Annotated:

4. Add a Query to Get a Single User By ID

By now, you might be asking: if queries are also fields of a type, why not call them fields? What makes them different?

Queries can take parameters and use a resolver.

The easiest way to see it is to compare it to OOP classes. While classes have fields and functions, GraphQL types have fields and queries.

  • Edit server.js with:

Again, no magic.

We’re saying the user query takes an id parameter, and that’s what its resolver function will take. Oh, also notice the ! sign meaning the parameter is required—GraphQL will make sure it is provided.

5. Replace Schema Builder with Manual Definitions

Remember how we called out that huge magic string we used to define our schema? Well, it’s time to fix that.

Okay, in a real-world app, you would put your schema in separate *.graphql files. Then you can add syntax highlighting and code completion plugins to your code editor. However, manual definitions offers a better integration with the rest of our code. Check out this article for more info.

For this step, we’ll use the specialized classes and helpers provided by GraphQL:

Done? Okay, now annotated:

This way we can put our type definitions in separate files to better organize our server code!

As pointed out in the example, in this notation, the resolver function takes the following parameters:

  • rootthe resolved parent object, in this case the user.
  • argsarguments passed by the query.
  • context, infoout of the scope of this guide.

6. Add a Sub-query for Fetching User Roles

So far, we’ve learned to define basic queries. Time to turn it up a notch! Let’s add a new field to the User type for its assigned roles. In a traditional architecture, we’d be tempted to create a new query like userRoles(userId: Int!): Role and call it a day. But that’s not how things work in GraphQL!

We have to think in graphs.

In the language of graphs, to get the roles of a user we’d send a query like this:

… and get a JSON result like this:

Makes sense, right? Let’s go ahead and modify the schema.

  • Edit server.js with:

There—we can fetch user roles now. Notice how we used the User instance passed as the first parameter to the resolver to get the ID from the parent resolved user.

Schema Documentation: It’s Got Your Back.

The advantage of subqueries? GraphQL won’t resolve the roles field unless it’s selected in the query.

Did you spot the pitfall with the last bit of code?

If we query 100 users and their roles, the roles resolver function will execute a hundred times. Then, let’s say each user has 10 roles and each role has a sub-query field. That query will execute 100 * 10 times.

This is called The N + 1 Problem.

Finding out how to fix that is your homework! But it’s dangerous to go alone, so take this:

Avoiding n+1 requests in GraphQL, including within subscriptions
Note: this article will not make much sense unless you know the basics of GraphQL, an awesome technology we use at…medium.com

7. Add a Mutation to Create a New User

As mentioned before, mutations are how we change data in our schema. If we want to create, edit, or delete a user account, we’ll need a mutation for that.

Mutations are defined almost exactly the same as a query, and often return the affected data. So the only difference between them is merely logical?

Exactly.

As mentioned before, queries can also take parameters. They only return data.

  • Edit server.js with:
  • Send the following query from GraphiQL:
  • Profit.
Typos: Screwing Up GIF Recordings Since 1927

Conclusion

So, hopefully, the basics of GraphQL are clear: setting up a server, creating a schema (in plain and complex notation) with types, queries, and mutations. I used quite a basic example. Hopefully it served well for illustrating every concept unobtrusively.

From this point onwards, it’s up to you to expand the example with more stuff. Or you can create a completely new codebase for another use case.

To get you going, here are a few things you can try out:

  • Solving the N+1 problem by implementing data loaders.
  • Create mutations for validating user credentials, managing user roles, and more.
  • Add an actual database to feed your resolvers (MySQL, SQLite, etc.)
  • Use an authentication backend like OAuth to validate users.
  • Create a simple client app that uses the Apollo Boost client to connect to your server.
  • Rebuild the example with TypeScript.

Possibilities are endless!

Get the Source Code

The entire example is hosted in GitHub. Browse through the tags to see a gradual progression of the code.

ldiego08/workshops-graphql
GitHub is where people build software. More than 28 million people use GitHub to discover, fork, and contribute to over…github.com

Got questions, comments, or anything you’d like to share? Find me on Twitter as @ldiego08. Also, don’t forget to 👏, share, and follow if this post was helpful!

Luis Aguilar (@ldiego08) | Twitter
San José, Costa Rica — Writer of sci-fi, software dev @skillshare. twitter.com