cft

Decoding the Why and How of GraphQL

Learn the various aspects of GraphQL, its core concepts, comparisons with REST APIs and finally, implement a GraphQL API Server from scratch.


user

Saurabh Dashora

2 years ago | 6 min read

As software applications increase in complexity, their interfaces also increase in complexity. This leads to an ever-growing API footprint and an explosion of integrations between clients and servers. Eventually, this results in a maintenance nightmare. Seemingly minor changes start taking more and more time to implement. More often than not, refactoring your interfaces seems the only solution to handle the situation. However, refactoring is a costly business and usually, does not get approved unless there is an overwhelming reason to do so.

So what's the solution?

GraphQL is a tool that brings a paradigm shift in the way clients and servers interact. While it is not a silver bullet, it can definitely act as a sweet spot between complete overhaul of the application and doing nothing at all.

1 - What is GraphQL?

GraphQL stands for Graph Query Language.

But don't let those words mislead you. While it is a query language, we don't query database tables using GraphQL.

So what do we query using GraphQL?

Nothing, really! GraphQL is more of a format or structure to define the contract between the client and the API server. Basically, you can also think of GraphQL as a specification. Maybe, a new API standard similar to REST. However, it is considered more efficient and flexible when compared to REST.

Also, we can practically use GraphQL wherever we were using REST. In a way, GraphQL aims to do what REST was doing all these years. Only it claims to do it better!

GraphQL is a standard specification. There is no official implementation of GraphQL. You could create a GraphQL implementation using any programming language as long as it follows the specifications of GraphQL.

2 - Features of GraphQL

There are some key features of GraphQL.

2.1 - Declarative

In GraphQL, clients ask queries to the server. These queries are declarative in nature. See below example:

{

book(id: "1") {

title

publishYear

}

}

The query here is pretty self-explanatory. Basically, the client is asking for the book with id of 1. Also, the client is specifying that it is only interested in the fields title and publishYear.

It is the job of the server to make sure that only specified fields are returned as part of the response. Below is how the response could look like:

{

"data": {

"book": {

"title": "The Way of Kings",

"publishYear": 2010

}

}

}

This is totally different from REST where a client has no control over what gets returned by the server.

2.2 - Hierarchical

Queries in GraphQL are also hierarchical. See below example:

{

book(id: "1") {

title

publishYear

authors {

name

}

}

}

Here, the client is asking for the book. But along with the book, it is also interested in the author of the book (specifically the name of the author). The query can describe this relation quite easily.

2.3 - Type Safety

In GraphQL, we have to declare schemas to specify our data models. A GraphQL schema helps the server determine whether the client's query is valid or not.

These schemas are strongly-typed.

type Book {

title: String!

publishYear: Int

price: Float

}

Basically, the type-system can use primitive types such as numeric integers, booleans and strings. However, it can also use complex types such as objects.

3 - GraphQL Core Concepts

There are a few core concepts of GraphQL that form the basis of its query language.

Let us look at them one by one.

3.1 - Schema Definition Language (SDL)

As we saw in previous section, GraphQL has a type system. It is used to define the schema.

Basically, the syntax for writing the schema is also known as Schema Definition Language or SDL. Below is a simple schema.

type Author {

name: String!

}

This schema describes an Author. It contains only one field and that is the name of the author. The ! mark denotes the fact that name is a mandatory field.

3.2 - Queries

Queries are the backbone of GraphQL. Clients make queries to the GraphQL server. These queries specify the requirements of the client. If the query is found to be valid, the server sends a response.

Below is an example of a typical GraphQL query.

{

book(id: "1") {

title

publishYear

}

}

3.3 - Mutations

APIs are used not only to query information but also update information. In GraphQL, updates are supported using the concept of mutations.

mutation {

createAuthor(name: 'Robert Jordan', country: "USA") {

name

country

}

}

As you can see, the mutation keywords differentiates it from a query.

4 - GraphQL vs REST

There is no denying the fact that REST has been an industry-standard for the past several years. However, REST APIs are often inflexible and don't adapt well to changing requirements of the client.

  • The major problem with REST is that you end up over-fetching or under-fetching data. Each endpoint has a specific layout. Even if the client needs only one field from that layout, the API will return all the fields whether you like it or not. This is known as over-fetching. An even bigger problem is under-fetching. It is quite common that a single endpoint does not provide all the needed information. We make an API call, get some response and use that response to make another API call to get the rest of the information. Depending on the design, there can be multiple calls to accumulate required data. This is also known as the n+1 problem. In GraphQL, this problem does not occur. This is because the clients control the query.
  • REST APIs can lead to un-necessary network traffic due to multiple calls. Also, more data goes over the wire. In the case of GraphQL, the same amount of data can go through in a single call using proper hierarchical queries.
  • With REST APIs, it is hardly possible for the server to determine what the client is doing with the data and what fields it is actually interested in. The server simply sends everything and forgets about it. In GraphQL, clients send queries. Imagine the use of this information from an analytics point of view. Monitoring of these GraphQL queries can result in improvement to the API offerings.

5 - Creating a GraphQL Server

We have now talked enough about the virtues of GraphQL.

Let's see it in action by creating a simple GraphQL Server. As I mentioned earlier, GraphQL is just a specification. There are various implementations of this specification.

In a nutshell, there are 3 things a GraphQL API server needs to work properly:

  • A webserver
  • A GraphQL schema with a resolver.
  • A request handler to receive incoming requests.

The simplest way to achieve the above is as follows:

  • For the webserver, we will use Express. It is a popular NodeJS framework for building APIs.
  • The schema and resolver are handled by the graphql package. This is a standard GraphQL implementation and forms the basis for all other sophisticated implementations.
  • Next, for the request handler, we will use the express-graphql package. This package is basically a middleware for Express.

And that's it! This is all we need to setup a GraphQL API Server.

In the first step, we will create a project directory and install the required packages.

$ mkdir graphql-express-demo

$ cd graphql-express-demo

$ npm init -y

$ npm install express express-graphql graphql --save

As discussed earlier, we install the express, express-graphql and graphql packages.

Next, we have to create a file named server.js and place the below code in that file.

var express = require('express');

var { graphqlHTTP } = require('express-graphql');

var { buildSchema } = require('graphql')

var schema = buildSchema(`

type Query {

hello: String

} `)

var root = {

hello: () => {

return "Hello, World"

},

}

var app = express();

app.use("/graphql", graphqlHTTP({

schema: schema,

rootValue: root,

graphiql: true

}));

app.listen(4000);

console.log('GraphQL API server available at http://localhost:4000/graphql')

We first define the schema using buildSchema() function. Then, we specify the root query and register one query type named hello.

Finally, we setup the express app and implement a request handler. Within the request handler, we configure the graphqlHTTP middleware to use our schema and root query.

A typical GraphQL server usually has only one endpoint. All queries are processed by the same endpoint unlike REST APIs where each resource has its own endpoint. Here, that particular endpoint is /graphql.

The graphiql flag is set to the value true. This flag enables the graphical user interface where you can play around with the queries and see the responses from the server. You can access the UI on http://localhost:4000/graphql.

See below:

Conclusion

GraphQL is a wonderful tool to build APIs that are adaptable to evolving customer requirements. If your API footprint is growing out-of-hand and consumers are complaining about the need to call multiple endpoints to work with your application, it might be good idea to explore GraphQL.

Depending on your application's current status, you can look at some common GraphQL Architectural Patterns for inspiration.

In case you have any comments or queries about this post, please feel free to mention them in the comments section below.

Upvote


user
Created by

Saurabh Dashora

Architect and Developer who loves to write and share stuff about programming and software development


people
Post

Upvote

Downvote

Comment

Bookmark

Share


Related Articles