Your First GraphQL Server

So, today we’re going to write a small GraphQL server. I’m not going to try to persuade you to drop everything and adopt GraphQL — but if you’re curious about what this stuff looks like today and how it works, read on.

Setup an HTTP Server

We need a server to receive our GraphQL queries. There’s nothing in the GraphQL spec that demands we do this over HTTP, but since the GraphQL reference implementation is in JavaScript, it’s expedient to roll a quick HTTP server with Express.

$ mkdir graphql-intro && cd ./graphql-intro
$ npm install express --save
$ npm install babel --save
$ touch ./server.js
$ touch ./index.js

This creates a folder for our project (graphql-intro), and installs Express and Babel as dependencies. Babel isn’t required for GraphQL either, but it will let us write our JavaScript using ES2015 features that make life easier.

Finally, let’s write some code:

To run our server, execute:

$ node index.js
GraphQL listening at http://0.0.0.0:3000

To test that things are working:

$ curl -XPOST http://localhost:3000/graphql
Hello!

We’ve chosen to use an endpoint at /graphql, accessible via HTTP POST, but there are no hard rules — the GraphQL spec doesn’t dictate how you communicate to a GraphQL server.

Create a GraphQL Schema

Now that we have a server we can talk to, it’s time to “add some GraphQL”. What does that actually mean?

Let’s remind ourselves what a GraphQL request looks like:

query getHighScore { score }

In this case, our GraphQL client is requesting the `score` sub-field of the top-level `getHighScore` field. Fields are the things we ask a GraphQL server to return. Fields can also have arguments, like:

query getHighScores(limit: 10) { score }

They can do a few more things, but lets move on.

Our GraphQL server needs to be configured to respond to requests like these — it does this using a schema.

Constructing a schema is analogous to constructing a RESTful route tree. Our schema will describe what fields the server can respond to and what types of objects the responses will contain. Type information is very important to GraphQL, and the client can safely assume that the server will return consistent types of objects for the same field (or an error if that invariant is broken).

As you can imagine, schema definitions can grow pretty meaty. For our simple GraphQL server, we’ll have one simple field: `count`.

Back to running commands:

$ npm install graphql --save
$ npm install body-parser --save
$ touch ./schema.js

This looks promising, right? The GraphQL module contains the GraphQL technical preview, which allows us to compose our server schema and process GraphQL requests against it. Body-parser is a simple Express middleware that we use to grab the GraphQL request being sent.

Time to write our schema:

What we’re doing here is creating an instance of `GraphQLSchema`, which takes a big configuration blob. Eventually another part of the GraphQL library will consume this schema object, but it’s a reasonable practice to isolate its construction in a separate file.

In plain english, we’re configuring the schema to say:

My top-level query object returns a `RootQueryType` object, which has a `count` field, which is an integer.

You can imagine there are more scalar types besides integers (strings, lists, etc.), and that you can nest custom non-scalar types quite deeply.

Connect the Schema

Our fancy schema wouldn’t be any good unless we could execute queries against it. Let’s hook up the schema to our HTTP server:

Any POST requests to `/graphql` will now be executed against our GraphQL schema. We enforce a new content type for these requests — this isn’t part of the GraphQL spec, but may be a good pattern for servers that mix GraphQL with existing code.

Restart your server and give it a go:

$ node ./index.js // restart your server
// in another shell
$ curl -XPOST -H "Content-Type:application/graphql" -d 'query RootQueryType { count }' http://localhost:3000/graphql
{
"data": {
"count": 0
}
}

Neat! GraphQL also allows us to omit the `query RootQueryType` prefix, but I wanted to show as little ‘magic’ as possible. Thus, this will also work:

$ curl -XPOST -H 'Content-Type:application/graphql'  -d '{ count }' http://localhost:3000/graphql
{
"data": {
"count": 0
}
}

Now that we’ve got non-zero GraphQL “stuff” working, let’s take a minute to talk about introspection.

Introspect the server

Fun fact: you can write a GraphQL query to ask a GraphQL server about its fields. Very meta.

Sound crazy? Check this out:

$ curl -XPOST -H 'Content-Type:application/graphql'  -d '{__schema { queryType { name, fields { name, description} }}}' http://localhost:3000/graphql
{
"data": {
"__schema": {
"queryType": {
"name": "RootQueryType",
"fields": [
{
"name": "count",
"description": null
}
]
}
}
}
}

Here’s the query we issued, but more readable:

{
__schema {
queryType {
name,
fields {
name,
description
}
}
}
}

Basically, each GraphQL root field automatically has a `__schema` field, which has its own fields that we can query against — in particular, the `queryType` field. Every field can be queried for meta-information, such as the name.

More interestingly, you can attach useful human-level metadata like `description`, `isDeprecated`, and `deprecationReason` to fields. Facebook says their tooling uses this metadata to build better developer experiences (i.e. when you use a deprecated field, you see a red squiggly).

To make this perfectly clear, here’s how we add a `description` to our current schema:

Restart the server and see the new metadata appear:

$ curl -XPOST -H 'Content-Type:application/graphql'  -d '{__schema { queryType { name, fields { name, description} }}}' http://localhost:3000/graphql
{
"data": {
"__schema": {
"queryType": {
"name": "RootQueryType",
"fields": [
{
"name": "count",
"description": "The count!"
}
]
}
}
}
}

We’re almost done with our whirlwind tour of GraphQL — for my last trick, I’ll show off mutations.

Add a Mutation

If you want read-only access to a bunch of data, then you probably don’t need to read any further. But for most applications, we’re going to have to change our data. GraphQL calls these operations mutations.

Mutations are just fields that are intended to have side-effects, so most of the syntax is identical. Like normal query fields, mutation fields must also return a typed value — the intent is that if you mutate something, you should also return whatever it mutated.

How do we add mutations to our schema? Much like we define a top-level `query` key on our schema, we will also define a top-level `mutation` key:

let schema = new GraphQLSchema({
query: ...
mutation: // todo
)}

Besides going in a different location, how are mutations different? We could have made our `count` field function update our counter or do some other mutative action and GraphQL would have no way of knowing.

The meaningful difference between a mutation and a query is that mutations are processed serially, but queries make no such guarantee (in fact, GraphQL encourages servers to exploit the inherent parallelism of independent queries). The GraphQL spec gives this example of a set of mutation queries that must be processed by the server in order:

{
first: changeTheNumber(newNumber: 1) {
theNumber
},
second: changeTheNumber(newNumber: 3) {
theNumber
},
third: changeTheNumber(newNumber: 2) {
theNumber
}
}

Thus, by the end of the request, `theNumber` field should have the value of `2`.

Let’s add a simple mutation that updates our counter and returns the value:

Restart your server and give it a try:

$ curl -XPOST -H 'Content-Type:application/graphql' -d 'mutation RootMutationType { updateCount }' http://localhost:3000/graphql
{
"data": {
"updateCount": 1
}
}

Boom — the data has been updated. You can confirm this with a new query:

$ curl -XPOST -H 'Content-Type:application/graphql' -d '{ count }' http://localhost:3000/graphql
{
"data": {
"count": 1
}
}

You can do it as many times as you like — mutable state is entertaining.

In a proper GraphQL implementation, we would probably wrap our counter in a semantic value (like `CountValue`), which would be more meaningfully returned from both the query and the mutation.

Wrapping Up

That’s a whirlwind tour of how you can use GraphQL today using Facebook’s JavaScript implementation. I didn’t cover some more powerful topics — fields with arguments, resolving promises, fragments, directives…there’s lots of cool things in the GraphQL spec. There’s also room for new implementations and schema APIs on the server side. You can imagine a GraphQL server written in a typed language like Java might look quite different than how it looks in JavaScript.

This is also based on my 48-hour experience with GraphQL — if there’s anything missing or wrong, don’t hesitate to let me know. You can view the source (each commit is a new step) here: https://github.com/clayallsopp/graphql-intro

Thanks to the RisingStack folks for their excellent post and example on GraphQL.