CODE WARS: GraphQL - A New Hope

The Case for GraphQL over REST

GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data. GraphQL was developed internally by Facebook in 2012 before being publicly released in 2015.

Main Argument

Imagine that you’re in your car. You’re driving, but instead of following the Road Traffic Act, you rely on something called “Road Traffic Recommendations Manual”. The latter doesn’t contain clear rules that everyone should follow, but guidelines on what’s recommended (but not compulsory) to do while driving. In a result everyone has the right to interpret the “Road Traffic Recommendations Manual” however they want. This may include: driving in whichever lane you want, starting and stopping the car whenever you want, as well as not giving signals to the other road users. If you think that this is a metaphor for the driving experience in Sofia, you’re wrong. This is just how I describe the REST communication. 

Someone may correct me and say that REST has had many “transparent and good practices” for a long time, but they will always remain just that – “good practices”. In reality, no one knows how to structure a well-organized and easy-to-understand API. Every good programmer has his own view on good practices. For example, how should resource paths look like? What HTTP methods to use for CREATE, READ, UPDATE, DELETE operations? What should the Request and Response objects look like? All of these issues are vary depending on the project and team in question. Therefore, in this day and age, it is necessary to use technologies with clear rules and strict principles. For instance, a good alternative to REST is the technology GraphQL. Launched by Facebook in 2015, GraphQL solves most of the problems in the client-server communication. 

 

Basic Concepts

THE BASIC CONCEPTS IN GRAPH QL 

  • Schema - schema is the basis for building the GraphQL API. It defines the rules by which the API will operate, and that includes what requests can be executed, what types will be expected, and what will be returned in response. Schema is the place where the whole design process, necessary to build a fully-featured and documented API, takes place. 

 

Example: 

type Query {

author(id: Int!): AuthorType

authors: [AuthorType]

book(id: Int!): BookType

books: [BookType]

}

type BookType {

id: Int!

name: String!

author: AuthorType

}

type AuthorType {

  id: Int!

  name: String!

}

type Mutation {

createBook(bookInput: BookInput!): BookType

}

input BookInput {

name: String!

authorId: Int!

}
 
  • Types – types are the way GraphQL achieves consistency. I’d like to pay special attention to the fact that there is an explicit way to mark nullable types. This leaves no chance for misinterpretation of what types to expect in the Request or Response objects. 

 

  • Validation – the combination of schema and strict types allows for a very good static validation and type introspection (the ability of different tools to read the schema and types for better visualization or "hints" when writing). 

 

There are three types of actions in GraphQL: 

  • Query – the way that information is retrieved  
  • Mutation – the way changes in information are made  
  • Subscription – a way for real-time communication

 

What problems does GraphQL solve?

UNDER-FETCHING

In our daily work as programmers, we are faced with problems that are already known and solved. One of them is the so-called "Under-fetching" or the situation in which the API does not retrieve all the necessary information to complete your job. As a result, it is vital to make several, or even dozens of requests in order to collect all that is needed. To make the argument clear, let's consider the following:  

If we have a data model that looks like this: 

Book

  • Id 
  • Name 
  • AuthorId 
  • UserId 

 

Author

  • Id 
  • Name

 

To get a Book object by an Id in REST, the query will look something like this:  

Request - /api​/Books​/GetById?id=1 
Response - { "id": 1, "name": "Clean code" } 

 

In GraphQL the same query will look like this: 

Request - query { book(id: 1) { id, name } } 
Response - { "id": 1, "name": "Clean code" }  

 

At first, the two queries may look the same, but the difference begin when we having more and more complex queries, such as loading additional fields from the Book object. In REST, this can be achieved by creating a new API or modifying an existing one. In GraphQL, this can be accomplished simply by modifying the query at the place in the code where needed: 

Request - query { book(id: 1) { id, name, authorId, userId } } 
Response - { "id": 1, "name": "Clean code", "authorId": 1, "userId": 1 }  

 

All other places, where requests are made, remain unchanged. This is the main advantage of using GraphQL – only the required information is used. Another example of Under-fetching is when we want to take several objects at the same time, such as Book and Author, in one query. In REST, this is once again a problem therefore a new API needs to be created, or two separate requests like this: 

Request - /api​/Books​/GetById?id=1 
Response - { "id": 1, "name": "Clean code" }  
Request - /api​/Authors​/GetById?id=1 
Response - { "id": 1, "name": "Uncle Bob" }  

 

More complex queries, which extract all the information, can be made in GraphQL: 

Request - query { book(id: 1) { id, name }, author(id: 1) { id, name } } 
Response - { book { "id": 1, "name": "Clean code" } , author { "id": 1, "name": "Uncle Bob" } } 

 

OVER-FETCHING

The second major problem is so-called "Over-fetching", or a situation in which the API retrieves more information than needed. If there is an existing API that retrieves all of the information about the Book object, it is often misused: 

Request - /api​/Books​/GetById?id=1 
Response - { "id": 1, "name": "Clean code", "authorId": 1, "userId": 1 }   

 

Many different functionalities can be dependent on the same source. Any change in the source will require updating the way it is used everywhere. In GraphQL, this is avoided because each functionality defines its own needs: 

Request - query { book(id: 1) { id, name, authorId, userId } } 
Response - { "id": 1, "name": "Clean code" }  

 

or even: 

Request - query { book(id: 1) { name } } 
Response - { "name": "Clean code" }  

DOCUMENTATION

A third problem. And it is a big one. We can use the following table for easier comparison: 

DESIGN

Fourth problem. This is a common problem about building an API that is easy to understand and convenient to use by everyone. In GraphQL there are two main approaches for building a schema. Their main advantages can be described as follows: 

SDL-first

  • Cross-team communication 
  • Fast implementation 
  • Fast mocking of API
  • Better design 

 

Code-first 

  • Fully driven by language
  • Tool support 
  • Better consistency 

There is a right time and place to use either of these approaches. It is very important to emphasize that they are not mutually exclusive. The SDL-first approach can very easily be used in group planning meetings by the frontend and backend teams, and then the backend team can use Code-first approach for the actual implementation. 

Proper design consistency will be achieved, whatever approach is taken. If you ask 10 different teams that use REST about their design, you will get 10 different answers. This is not the case in GraphQL. Teams mostly adhere to one of the popular conventions imposed by industry leaders, such as GitHub, GitLab or Magento.

SUPPORTING MULTIPLE VERSIONS

Fifth problem. Every API gets trough many changes over time. These changes often lead to the need of supporting multiple structural and functional differences in the same API. This happens most often when the different clients of the same API cannot be updated at the same time as the server. This requires constant attention to the changes you make so that the already-existing implementation doesn’t stop working. There are ways REST to allow multiple versions of the client to use changing APIs without “breaking”. This is true in theory, but not in practice. The main problem is the type system of statically typed.

Continue reading

Digitalising distribution channel management

Kamenitza is among the leading brewing companies in Bulgaria, founded in 1881, and owns the first beer in Bulgaria that is still produced today – Kamenitza. The company combines the beer expertise of the four world's most famous brewing traditions – the Czech, the German, the Belgian, and the Irish – with loved brands such as Burgasko, Staropramen, Stella Artois, Guinness, Corona, and more.

Committed to maintaining its market leadership, the company focuses on digital transformation to modernize operations for greater efficiency and responsiveness. One such solution, 'Beersteam' developed by Plan A, is part of a suite of software solutions exemplifying Kamenitsa's dedication to operational excellence and strategic innovation.

Why Java

Java, for the past thirty years, has been a mainstay in the software development world. Ever since it was first founded in the mid-1990s by Sun Microsystems, this flexible programming language has undergone significant evolution and has successfully adjusted to the evolving needs of developers and the businesses that use it. Its popularity is further evidenced by its widespread usage: Java has been mentioned over 1.9 million times on Stack Overflow, consistently ranks among the top languages in GitHub repositories, and frequently holds a top spot on the Tiobe Index for programming languages worldwide.

Initially designed for home devices, not just limited to interactive television—an idea ahead of its time that didn’t fully take off, Java became popular in the tech space through the implementation of its "Write Once, Run Anywhere" model. Year after year, Java has steadily earned a reputation for its reliability, security, and superior performance, making it the preferred choice for many applications, from large enterprise systems to mobile apps.

AI-Driven Biomimicry Platform

The AI-driven biomimicry platform is a web-based solution designed to help engineers and researchers find nature-inspired solutions to real-world problems. The platform allows users to design and oversee projects applying nature's approaches to solving problems to human and environmental issues by utilising the principles of biomimicry.

Assume that a research team studying sustainable architecture is looking for ways to cut down on energy use. They used the platform to analyse termite mound ventilation systems, applying these principles to design energy-efficient buildings with improved airflow and temperature regulation. By leveraging AI-driven insights, the team was able to optimise their design based on nature’s proven strategy.

Picture showcasing termite mound residential building

Newsletter

Stay up to date, subscribe to our newsletter !