As the complexity of software applications grows, there is also a rise in the number of interfaces between different systems. This leads to an ever-growing API footprint – an explosion of integrations between clients and servers.

Ultimately, this results in a maintenance nightmare. Even minor changes start taking more and more time to implement. You basically need to analyze more. Test more. And even then, there are chances that issues might creep in to your application.

More often than not, refactoring your interfaces appears to be the only solution to handle the problem of ever-growing maintenance costs. However, refactoring is a costly business and is usually not approved by the management unless there is a very strong reason to do so.

So what’s the solution to this tricky problem?

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

1 – Introduction to GraphQL

As per wikipedia, GraphQL is an open-source data query and manipulation language for APIs and a runtime for fulfilling queries with existing data.

In essence, GraphQL stands for Graph Query Language.

But don’t let those words mislead you. GraphQL is not like SQL. While it may be dubbed as a query language, we don’t query typical database tables directly using GraphQL.

GraphQL is more of a format or structure to define the contract between the client and the API server. Basically, you can think of it as a specification or a new API standard similar to REST.

However, it is often considered more efficient and flexible when compared to REST.

In fact, 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 in a much better way.

1.1 – GraphQL Origins

GraphQL was initially developed as an internal project at Facebook sometime in 2012. According to the co-creator, Lee Byron, the concept of GraphQL emerged when they were trying to design a native iOS news feed with a RESTful API.

They immediately encountered several issues. Some of them are listed below:

  • The API requests were slow on the network.
  • Co-ordination of requests for different model was problematic.
  • Multiple roundtrip requests had to be made on flaky mobile connections.
  • API changes had to be carefully carried over to the client code to prevent the app from crashing.
  • API Docs were often out of date from the actual implementation.

Necessity is the mother of inventions. And feedback is the father of improvements.

The goal of overcoming the challenges caused by using normal RESTful APIs led to the birth of GraphQL.

GraphQL was publicly released in 2015.

And ultimately in 2018, the project was moved from Facebook to the newly established GraphQL Foundation. Currently, the GraphQL Foundation is hosted by the non-profit Linux Foundation.

2 – How GraphQL Works?

At this point you might be wondering, how GraphQL works and what makes it so special?

Think of a vending machine. To get an item from the vending machine, we press a button and we get one item. To get a second item item, we press another button. If we have to get 10 items, we press 10 buttons.

This is how the RESTful API approach works. For every piece of data, the client needs to make a new request. Needless to say, the process is slow.

To get around this inconvenience, the traditional approach has been to creating special endpoints.

Think of it as the vending machine having special buttons to get a combination of things. Every special button handles one combination of items.

The problem, however, does not go away.

How many special buttons would you create? There might be hundreds of combinations a user might be interested in. Even if you create a hundred special buttons, you can never be sure that the customer might not look for a new combination.

Clearly, this approach is not suitable.

However, there is a third approach as well.

What if the vending machine supported an option to choose multiple items by pressing a combination of buttons? Basically, the user tells the machine exactly what it needs. And once that is done, you get everything you need in one go.

This is the essence of how GraphQL works.

A GraphQL API depends on what the client actually wants.

The client specifies exactly what it needs and the GraphQL server provides everything in one go. This is unlike RESTful APIs where the server controls everything and the client has to often make multiple requests.

3 – Features of GraphQL

Now that we have a basic overview of GraphQL, it is time to look at some important features of GraphQL.

3.1 – Declarative

In GraphQL, clients ask queries to the server. These queries are declarative in nature. 

A typical GraphQL query may look like the below example.

{
 book(id: "1") {
   title
   publishYear
 }
}

It 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.

The GraphQL server has to make sure that only the fields specified within the query are returned as part of the response. Check out the below response object.

{
 "data": {
   "book": {
     "title": "The Way of Kings",
     "publishYear": 2010
   }
 }
}

As you might notice, this is a totally different approach from REST API design. In a REST API, the client has very little control over what gets returned from the server.

3.2 – Hierarchical

Queries in GraphQL are also hierarchical. See below example:

{
 book(id: "1") {
   title
   publishYear
   authors {
     name
   }
 }
}

In this example, the client is asking for the Book with id of 1. However, along with the book, the client is also interested in getting the author-related information of the book (specifically the name of the author).

In GraphQL, queries can describe this type of hierarchical relationship quite easily. 

3.2 – Type Safety

Type safety is another important feature of GraphQL.

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. Below is an example of a basic schema.

type Book {
 title: String!
 publishYear: Int
 price: Float
}

Each attribute in the Book type has a data type of its own. The type system can use primitive types such as numeric integers, Booleans, and strings. However, it is also possible to use complex types such as objects. 

4 – GraphQL Core Concepts

Apart from the features, there are certain core concepts of GraphQL. These concepts form the backbone of GraphQL and it is important to know about them.

4.1 – Schema Definition Language

As we saw earlier, 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 an example of a very simple schema.

type Author {
  name: String!
}

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

4.2 – Queries

Queries are arguably the most important concept 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 where we specify the id of the book and the specific fields we want to fetch.

{
 book(id: "1") {
   title
   publishYear
 }
}

4.3 – Mutations

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

A mutation looks like this.

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

As you can see, the mutation syntax looks quite similar to the query. However, the mutation keyword makes the GraphQL server aware that the client wants to perform an update or create operation.

4.4 – Subscriptions

In many modern applications, it is important to have a real-time connection between server and client so that the client can be immediately informed about important events. This is known as a subscription.

Subscriptions don’t follow the typical request-response cycle. When a client subscribes to an event, it will hold the connection to the server. When a particular event occurs, the server pushes the data to the client.

In GraphQL, Subscriptions are also written using the same format as queries and mutations. Check out the below example.

subscription {
  newAuthor {
    name
    country
  }
}

Once the client sends such a subscription request to the server, a connection is opened between them. Whenever a new mutation happens that results in the creation of a new author, the server sends the requested information to the client.

{
  "newAuthor": {
    "name": "Robert Jordan",
    "country": "USA"
  }
}

5 – GraphQL Demo

Now that we have a pretty good idea about the features and concepts of GraphQL, it is time to see it in action.

And to do so, let us look at how to create a very simple GraphQL API server.

5.1 – Requirements

Basically, there are three things needed to setup a server.

  • A web server.
  • GraphQL schema with a resolver
  • A request handler to process incoming requests

First, for the web server part, we will use Express, a popular Node.js framework for building APIs.

Second, the schema and resolver are handled by the GraphQL package. This is a standard GraphQL implementation for JavaScript and forms the basis for other sophisticated implementations.

Lastly, for the request handler part, we will use the express-graphql package. This package is basically a middleware for Express that helps us handle incoming requests.

5.2 – Implementation

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

Note that for any of this to work, you need to have Node.js installed on your system: 

$ mkdir graphql-express-demo
$ cd graphql-express-demo
$ npm init -y
$ npm install express express-graphql graphql --save

Next, we create a file named server.js inside our project and place the below code in that file:

let express = require('express');
let { graphqlHTTP } = require('express-graphql');
let { buildSchema } = require('graphql')
let schema = buildSchema(`
   type Query {
       hello: String
   } `)
let root = {
   hello: () => {
       return "Hello, World"
   },
}
let 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'

After the necessary import statements, we define the schema using the buildSchema() function.

Then, we specify the root query and register one query type named hello. Next, we set up the Express app and implement a request handler to handle incoming requests.

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 single endpoint is /graphql.

The graphiql flag is set to the value true. This flag enables the graphical user interface for our application, where you can play around with the queries and see the responses from the server.

We can access the UI on http://localhost:4000/graphql.

express graphql

6 – GraphQL vs REST

Having seen a working demo of GraphQL, we are now in a good position to compare it with REST APIs.

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 the changing requirements of the client. This is where GraphQL offers benefits when compared to the RESTful approach.

6.1 – Over-Fetching Data

The major problem with REST is that you end up over-fetching data. This is because in the REST approach, 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 results in over-fetching of data.

6.2 – Under-Fetching Data

While over-fetching is a problem, there is another bigger problem with REST. And that is under-fetching data.

It is quite common that a single API endpoint in a RESTful approach does not provide the complete information that is needed by the client. 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.

The below illustration demonstrates the n + 1 problem where we have to make multiple calls to fetch the book and the author details when following the REST approach.

graphql vs rest

In GraphQL, the above problem does not occur. This is because the clients can write hierarchical queries with nesting information.

6.3 – Network Traffic

Going further, REST APIs can lead to unnecessary network traffic due to multiple calls.

In other words, 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.

6.4 – Improved Analytics

Lastly, 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 specific queries.

Imagine the use of this information from an analytics point of view. Monitoring of incoming queries can result in future improvement to the API offerings depending on what kind of queries are being asked by the clients.

7 – GraphQL Architectural Patterns

As we have seen till this point, GraphQL is extremely flexible. Due to this reason, it provides a lot of flexibility when it comes to the architecture of your applicable.

On a high-level, GraphQL follows a typical client-server architectural pattern. The client makes a request and the server provides a response.

However, there can be several variations for such applications.

7.1 – GraphQL Server with a Connected Database

This architectural pattern is the most suitable if you are starting a brand new project. Basically, something like a greenfield project.

graphql architectural patterns

In this setup, we have a single web-server. This server implements the GraphQL specification as per the core concepts we discussed earlier.

When a query is received, the server resolves or processes the query and returns a response.

Though we have marked the transport protocol as HTTP, it can use any other protocol as well. This is because GraphQL is transport-layer agnostic. Also, GraphQL server can connect to any database solution such as MySQL, MongoDB or AWS Aurora.

The advantage of this approach is low complexity in terms of data fetching. The data source is also close to the application logic due to which there is less latency. If possible, this is an ideal pattern to use.

However, it is possible only in the case of a new project where everything is done from scratch. In an existing application where we want to utilize existing parts of the system, we need to examine some of the other patterns.

7.2 – GraphQL Layer With Existing Systems

GraphQL provides a lot of flexibility to the client in terms of building a query and requesting for information.

However, an existing system might already be built using different solutions such as third party APIs, legacy services and a bunch of newer microservices.

Considering this, one might assume that we cannot use GraphQL in such a scenario. But this is an incorrect assumption.

As you can see, GraphQL can unify the existing systems and hide their complexity behind a unifying API endpoint. New client applications can simply interact with the GraphQL API without worrying about the underlying systems. The GraphQL server will be responsible to resolve the queries and package the responses as per the client’s requirements.

graphql with existing systems

This approach can suit a lot of big organizations where a large number of services are already present and it is time consuming and risky to duplicate the business logic for new requirements.

7.3 – Hybrid Approach

The third pattern is basically a hybrid approach. It is a combination of having a connected database as well as talking to existing legacy systems.

hybrid pattern

In this approach, when the GraphQL server receives a query, it will resolve it by retrieving the data from the database or talking to one of the services.

This approach can also pave the way for slow migration of business logic from legacy systems to the new GraphQL servers.

One could incrementally put more and more functionality into the GraphQL server and connected database while slowly deprecating old services.

8 – GraphQL Advantages and Disadvantages

Finally, it all boils down to the advantages and disadvantages. This section is important because these are exactly the points that may help you decide whether to use GraphQL or not.

8.1 – Advantages

  • API clients get way more freedom with GraphQL. The client applications can formulate queries depending on their requirements without being extremely dependent on the server.
  • Since GraphQL uses a Schema Definition Language based on type safety, it provides an automatic layer of validation. Developers consuming the GraphQL APIs can easily see what the schema supports and accordingly formulate the queries.

8.2 – Disadvantages

  • Since GraphQL supports hierarchical queries, complex queries with a lot of nesting can often lead to performance issues. To avoid these issues, we might have to implement rate-limiting or nesting limits for our application
  • While GraphQL is a great tool to reduce complexity, it might even be an overkill for small applications. For a simple application, a REST API might be a better option.
  • GraphQL does not support HTTP web caching.

9 – Conclusion

GraphQL is a wonderful tool to build APIs that are adaptable to evolving customer requirements.

If your application’s API footprint is growing out of hand and you’ve a bunch of disgruntled consumers complaining about the need to call multiple endpoints to work with your application, it might be a good idea to explore GraphQL.

Also, if you are looking to build APIs without needing to constantly push out new versions while maintaining older versions, GraphQL is a great choice.

Want to build complex applications? Check out this post on using GraphQL with NestJS.

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

Categories: BlogGraphQL

Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *