GraphQL: Learn by Doing (Part 1 of 3)

Armand Aquino
EdgeCoders

--

This will be Part 1 out of 3 of the GraphQLLearn by Doing” series. I’m putting this together because I think “learning by doing” it is a great way to learn something. Remember the quote from my last post. Well here it is to refresh your memory:

I hear and I forget, I see and I remember, I do and I understand.

My last GraphQL post gave some legit reasons to use GraphQL. You may have read about it, hopefully got excited, and saw the code to declare what data you want, but you may have left without knowing how to implement a GraphQL server on your own. Here is how this series will be broken down:

Sound good? All aboard? Ready to see how cool beans this is? Let’s go.

I won’t make this a super step-by-step but close. I will assume you have knowledge of javascript, express, node, npm, and you have node and npm installed on your system. FYI, there will be a link to the repo at the end of this article but I suggest you follow along as much as you can.

Let’s start by making a directory, setting up npm, and downloading the modules you will need to install and configure a GraphQL server.

mkdir github-graphql-server
cd github-graphql-server
npm init

When running npm init, type “server.js” for the “entry point” and accept the default values for the rest of the prompted questions.

We’ll be creating a GraphQL server using express. We will also be writing all the code in ES6/2015 because you should get used to it and start making it a habit because it is the future, IMHO.

npm install --save graphql express express-graphql
npm install --save babel-cli babel-core babel-loader babel-preset-es2015

Create a directory named “data” and file named “schema.js” inside it.

This will be the schema that describes the data so that your GraphQL server will understand how to retrieve data and transfer information to the GraphiQL tool. Oh yeah, we’re making that too.

In the data/schema.js file, start by importing some objects from the graphql module. It‘s more than what we need for now but we’ll definitely use it later. Not including all of it now will be the cause of a lot of your errors in the future.

import {
GraphQLSchema,
GraphQLObjectType,
GraphQLInt,
GraphQLString,
GraphQLList,
GraphQLNonNull,
GraphQLID,
GraphQLBoolean,
GraphQLFloat
} from ‘graphql’;

We then make a query object so GraphQL can use it to make a schema that understands how to query/fetch and return the data. We’ll be making two fields that we can query for. A “hello” field that takes one argument “name” that cannot be blank/null and returns a hello message, and “luckyNumber” field that returns a fixed number. Here is the code and I’ll explain after.

const query = new GraphQLObjectType({
name: “Query”,
description: “First GraphQL Server Config — Yay!”,
fields: () => ({
hello: {
type: GraphQLString,
description: "Accepts a name so you can be nice and say hi",
args: {
name: {
type: new GraphQLNonNull(GraphQLString),
description: “Name you want to say hi to :)”,
}
},
resolve: (_,args) => {
return `Hello, ${args.name}!!!`;
}
},
luckyNumber: {
type: GraphQLInt,
description: "A lucky number",
resolve: () => {
return 888;
}
}
})
});

Each Query object requires a “name” property but you can also include an optional “description” property. I recommend including a “description” because it will automatically show up in the GraphiQL tool and can help your developers or you can create and maintain documentation because you like doing it =/

Next is thefields” property which is required. It is a function that returns an object of the different field objects a developer can query for. Each field object requires a “type” which can be one of the GraphQL types that we imported or a custom GraphQL type object we create that returns multiple fields (We’ll see that in part 2.). GraphQL fields are strongly typed and you must declare what type it expects to receive. The next property each fields object requires is the “resolve” property which is a function. That will be used to return the data for the field or fields. In this simple example case, each field is resolved with static data. Usually this is a query from another data source.

If you need to pass arguments in order to resolve your fields, then you can include the “args” property. This is usually the case when you are making a call to the data source that requires arguments or user supplied information. The “args” property is an object that can return one or more objects in case you need to pass multiple arguments to your resolve function. You can also include a “description” property for each field. The “description” is very useful for GraphiQL and creates an excellent introspection system.

If you saw the code above and wondered what the first argument in the “resolve” function was or thought it was a typo, it is not. It is an underscore that denotes the first argument is not provided but the args object is. The order of the parameters in the resolve function matter. You can pass the object returned from the datasource to each resolve function. This way you can modify the data before it is returned or use mutliple data values from the object to determine the return value. If you need to do that, then it must be the first argument in the resolve function. Hard to explain — easy to demonstrate; we’ll see that in Part 2.

resolve: (_,args) ...

This schema has some really boring stuff, I know. We just want to test the server to make sure it works. We’ll be calling cooler stuff later, promise. Fun fact, the resolve function can handle promises.

Lastly for this file, create a GraphQL schema object, include the query object we just made in it, and then export the schema.

const schema = new GraphQLSchema({
query
});
export default schema;

Now let’s make a really simple express server that uses the express-graphql middleware. In the root directory, create a file called “server.js” and enter this code. I assume you are familiar with express and I’ll just explain the GraphQL specific parts.

import express from ‘express’;
import GraphQLHTTP from ‘express-graphql’;
import schema from ‘./data/schema’;
const app = express();
const PORT = 8888;
app.use(“/GraphQL”, GraphQLHTTP({
schema,
graphiql: true
})
);
app.listen(PORT, () => {
console.log(“Node/Express server for Flux/GraphQL app. listening on port”, PORT);
});

We import and create variables for the schema and the express-graphql middleware module. Then use the middleware and make an endpoint called “/GraphQL”. You can call the endpoint whatever you want but this is the convention. The middleware is an object that expects a GraphQL schema object. Let’s also include the optional, but highly recommended, “graphiql” property set to true “graphiql:true” . That is how you setup the GraphiQL server; yes, that easy!

I added a following start command in the scripts section of the package.json file. This will allow you to use ES6/2015 code to start a node server that understands ES6/2015.

“start”: “./node_modules/.bin/babel-node --presets es2015 ./server.js”

From your terminal, go to the root directory of this app and type the following command:

npm start

Now, on your browser, go to http://localhost:8888/graphql

You should see this.

As you start typing, it will autocomplete your available valid options with a descriptions if you provided them.

Here is a view of GraphiQL with the documentation explorer on the right where you can navigate and see what queries the GraphQL server supports, information on the fields, and more. Go play around and see what information is available on your own. You can get all these cool features just by adding “graphiql: true”, boo-yah. In the screenshot below the complete query appears on the left and results in middle … mission accomplished.

Congrats on setting up your GraphQL server.

Code from this blog can be found here. I will have different branches for each part of the series.

Hope you enjoyed the first installment of GraphQL: Learn by Doing.

Next up in part 2 is configuring the GraphQL server to make calls to the GitHub API and return only the data you need and sometimes in a format more useful for the developer.

If you thought this article was helpful, then consider recommending ❤ the story so more people will find it.

Thanks for reading and stay tuned for more.

--

--

Armand Aquino
EdgeCoders

Quantitative Analyst/Developer at Optimal Asset Management, Inc. ✌♠️