Remember the good old SOAP protocol? Maybe you forgot it ’cause REST replaced it, and it’s way better!
But what if I tell you that we’ll soon wish to forget REST in favor of GraphQL?

The need for querying data

GraphQL is a query language created by Facebook in 2012 and open sourced in 2015.
It allows requests and manipulations for specific data, so clients have more control over what information the server will send.
A common REST problem is Data Overfetching: imagine you only want to know the first name and the email of a given user, but the API will return the entire profile… why do we get so many useless informations?
Now imagine that you only need a list of user IDs, but the API will return a huge array of objects containing every user’s informations. What a waste of time and resources!
GraphQL provides a declarative data fetching API, which allows you to require only what you need.

Type Safety

GraphQL queries are written in the Schema Definition Language (SDL), which requires strong typing. GraphQL schemas are validated during compile time, which means that the compilation will fail if any type error is found in your schema.

Deprecation and Versioning

Coming from REST, you may remember that after some time, some APIs can be deprecated.
You may need to switch from https://someapi.dev/v1/myendpoint to https://someapi.dev/v2/myNewEndpoint ’cause the structure of our resources has changed over time.
GraphQL avoids that ’cause the client is querying the API, just like he would do on a database.
The structure may change on the server, but the client still will be able to get it contents in the desired format.

Creating the Server

GraphQL

So let’s build a GraphQL server! First of all, create a new project and install the following packages:

$ yarn add graphql express express-graphql

Great. Now let’s create a ./src/main.js file and build a new Express Server:

const express = require("express");
const app     = express();
const port    = process.env.PORT || 3000;

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`Server ready on port http://localhost:${port}`);
});

Let’s try to run our webserver and see if it works: node ./src/main.js:

GraphQL

Not the best looking web page, but it works! Now we may want to add a GraphQL endpoint, maybe using the awesome GraphiQL tool.

const express         = require("express");
const expressGraphQL  = require("express-graphql");
const { buildSchema } = require("graphql");
const app     = express();
const port    = process.env.PORT || 3000;

const schema = buildSchema(`
  type Query {
    message: String
  }
`);

const rootValue = {
  message() {
    return "Hello World!"
  }
}

app.use("/graphql", expressGraphQL({
  schema,
  rootValue,
  graphiql: true
}));

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`Server ready on port http://localhost:${port}`);
});

Let’s analyze what we did:

  • We imported the Express GraphQL middleware (express-graphql).

  • We imported buildSchema function, which allow us to build a GraphQL Schema which describes our source data.

  • On line 7, we build our Schema using the Schema Definition Language (SDL). We’ll have to define a type for each value (in that case, we just have message, which is String).

  • On line 13, we define a Resolver: it contains the mapping of actions to functions. When you’ll require the message data, our resolver will just send back the hello world string. Pretty easy, isn’t it?

  • On line 19 we finally create the /graphql endpoint, which also uses express-graphql middleware to create a GraphiQL interface.

Let’s start again our server and go to http://localhost:3000/graphql:

GraphiQL

Awesome! With just few lines of code, we created a GraphQL endpoint! Let’s test it requiring our message:

GraphiQL

And here you are! We just made our first GraphQL server!
Now let’s do something more complex. Let’s create a new file ./src/data.js:

module.exports = [
  {
    id:         1,
    name:       "Java",
    createdBy:  "James Gosling",
    year:       1995,
    paradigm:   "Object Oriented",
    complexity: 7
  },
  {
    id:         2,
    name:       "PHP",
    createdBy:  "Rasmus Lerdorf",
    year:       1995,
    paradigm:   "Object Oriented",
    complexity: 3
  },
  {
    id:         3,
    name:       "C",
    createdBy:  "Dennis Ritchie",
    year:       1972,
    paradigm:   "Imperative",
    complexity: 10
  },
  {
    id:         4,
    name:       "Erlang",
    createdBy:  "Joe Armstrong",
    year:       1986,
    paradigm:   "Functional",
    complexity: 8
  },
  {
    id:         5,
    name:       "OCaml",
    createdBy:  "INRIA",
    year:       1996,
    paradigm:   "Functional",
    complexity: 8
  },
  {
    id:         6,
    name:       "LISP",
    createdBy:  "John McCarthy",
    year:       1958,
    paradigm:   "Functional",
    complexity: 6
  }
]

Ok, now we have our little dataset! We’ll expose a GraphQL endpoint which will allow us to query against a list of programming languages.

In order to make the code more maintainable, let’s create a third file: ./src/graphqlData.js

const { buildSchema } = require("graphql");
const data            = require("./data");

const schema = buildSchema(`
  type Query {
    language(id: Int!):          Language
    languages(paradigm: String): [Language]
  }

  type Language {
    id:         Int
    name:       String
    createdBy:  String
    year:       Int
    paradigm:   String
    complexity: Int
  }
`);

First of all: let’s importo both our data and buildSchema.
We need to define a schema for our GraphQL endpoint. As you can see, we first define the Query type, which allows us to:

  1. Get a specific language, given an ID (which is an Integer). It will return a Language, which is a type that we’re gonna create in the lines below.

  2. Get a list (array in JavaScript) of languages, given a specific paradigm. Again, a paradigm needs to be of type String, and will return a list (again, array in JavaScript) of Language.

Last but not least, we define the **Language **type. Coming from other programming languages, it feels like writing down a struct or a record.
When we define a new GraphQL type, we need to write a description of the data that will be queried. In our case, we have an id which is an Int, a name which is a String and so on.

Let’s move on and create two functions which will allow us to get our data:

function getLanguage(args) {
  return data.filter((language) => {
    return language.id = args.id;
  })[0]
}

function getLanguages(args) {
  return args.paradigm
         ? data.filter((language) => language.paradigm === args.paradigm)
         : data
}

const rootValue = {
  language:  getLanguage,
  languages: getLanguages,
}

We just created two functions and a constant value, let’s see how they works:

  • getLanguage accepts an Object as argument, and will filter our data returning us just the language with a given ID.

  • getLanguages accepts an Object as argument, and will return an array of languages given a specific paradigm.

  • rootValue just composes our rootValue to be used in express-graphql.

Please note that both getLanguage and getLanguages **returns the same type **we defined in our schema.

Now put everything together:

const { buildSchema } = require("graphql");
const data            = require("./data");

const schema = buildSchema(`
  type Query {
    language(id: Int!):          Language
    languages(paradigm: String): [Language]
  }

  type Language {
    id:         Int
    name:       String
    createdBy:  String
    year:       Int
    paradigm:   String
    complexity: Int
  }
`);

function getLanguage(args) {
  return data.filter((language) => {
    return language.id = args.id;
  })[0]
}

function getLanguages(args) {
  return args.paradigm
         ? data.filter((language) => language.paradigm === args.paradigm)
         : data
}

const rootValue = {
  language:  getLanguage,
  languages: getLanguages,
}

module.exports = {
  schema,
  getLanguage,
  getLanguages,
  rootValue
}

Awesome! Let’s modify a bit our ./src/main.js file:

const express         = require("express");
const expressGraphQL  = require("express-graphql");
const graphQLData     = require("./graphQLData");
const app             = express();
const port            = process.env.PORT || 3000;

app.use("/graphql", expressGraphQL({
  schema:    graphQLData.schema,
  rootValue: graphQLData.rootValue,
  graphiql: true
}));

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`Server ready on port http://localhost:${port}`);
});

And now it’s time to test it out! Let’s restart our webserver and test our GraphQL endpoint:

GraphQL

Awesome! And what if we want to remove some values from our query?

GraphQL

Sooooo easy!
What if we want to get a specific language?

GraphQL

We did it! We created a simple GraphQL endpoint in just a few lines of code.
Greatest thing is that our data could come from a database, a file, wherever we wish!
This is just a simple implementation… but imagine how far we can go from here!

You can see the complete code here:
jsmonday/graphql-server
Simple GraphQL server built for the 12 JSMonday article - jsmonday/graphql-servergithub.com

Did you like this article? Consider becoming a Patron!

This article is CC0 1.0 (Public Domain) licensed.