How to make your website clean and maintainable with GraphQL
By: Ondřej Polesný
Tags: GraphQL, JavaScript, Microservices, Web Development, Nodejs

REST API services, SQL databases, markdown files, text files, SOAP services… can you think of yet another way to store and exchange data and content? Production websites usually work with several different services and ways to store data, so how can you keep the implementation clean and maintainable?

Every Node.js website, regardless if it is a single page application or a regular site, needs to connect to a third-party service or system. At the very least it needs to get content from markdown files or a headless CMS. But the need for other services quickly surfaces. First, it’s a contact form — you need to store its submissions. Then it’s a full-text search — you need to find a service that enables you to create indexes and search through them. And the list goes on and on depending on the size of your project.

What is the problem with that? Well, nothing at first. When you are motivated to finish a project you create a component for each of these functionalities. Communication is encapsulated within the respective components, and after a few quick tests, you are happy it all works. The customer is happy the project was delivered before the deadline, and as a side effect, you also became an expert on a Content as a Service API, form submission services, and automatic search index rebuilding.

You got the website up and running so quickly that you got promoted! And the knowledge of the project and its details with you.

In a few weeks, your colleagues are asked to do some changes to the project. The customer wants to use a different search provider as the original one is too expensive. The developers are also working on another project that needs a contact form, so they thought about using the same component, but store the submissions in a different service. So they come to you asking about the specifics of your implementation.

When you finally give up searching your memory, they will need to do the same research as you did originally to figure out the implementation. The UI is so tightly coupled with the functionality, that when they want to reuse the components, they will probably end up implementing them again from scratch (and maybe copy-pasting bits and pieces of the old code).

Decoupled infrastructure showing GraphQL communication and specific GraphQL resolvers

The Right Level of Abstraction

So how can we avoid these issues to keep our code maintainable and clean? Take a look at the graphic above where I divided the communication with third-party services and the UI. The specifics of each external service API are implemented in the middleware on the back-end of the website. The components on the front-end all use a single way to fetch and submit data — GraphQL.

GraphQL

So what is GraphQL and why use it to communicate between front-end and back-end? GraphQL is a query language, a protocol, that was founded exactly for this purpose — to decouple the data the website front-end needs from the queries required to fetch them. It is similar to a REST API from a functionality point of view as it enables you to query for data. For more information check out the GraphQL homepage.

The main difference is in the way you ask for the data. Let’s say a new developer on the project is tasked with creating a blog page. The page should display blog posts that are stored within a headless CMS. I am using Kentico Cloud, which is a Content as a Service (CaaS) platform allowing you to store various types of content in clear hierarchical structures and obtain the content via a REST API. Therefore the GET request for data using a REST API could look like this:

https://deliver.kenticocloud.com/{projectID}/items?system.type=blog_post

Sample response would be:

{

"items":[

{

"system":{

"id":"0282e86e-8c72–47f3–9d3d-2acf93a8986b",

...

"last_modified":"2018–09–18T10:38:19.8406343Z"

},

"elements":{

"title":{

"type":"text",

"name":"Title",

"value":"Hello from new Developer Evangelist"

},

"content":{

...

}

...

}

}

]

}

The response contains data of all blog posts in JSON form. As the page displays only a list of blog posts, a lot of returned data (starting with content field) are redundant as we do not need to display them. To save bandwidth (which you usually pay for), the developer would need to use additional columns filter:

https://deliver.kenticocloud.com/{projectID}/items?system.type=blog_post&elements=title,image,teaser

They need to know the specifics of the API and probably have its reference open in another browser window while building the query.

Getting the same data with GraphQL is much easier. Its schema is natively describing what the front-end is capable of rendering. The developer needs to specify what data to fetch in graph notation:

query BlogPosts {

getBlogPosts {

elements {

title

image

teaser

}

}

}

(Find more examples of GraphQL queries in this Why GraphQL? article by Shankar Raju.)

Now when you decide to switch the content storage from headless CMS to markdown files or SQL database, the implementation of the blog page will not change. The GraphQL query will still look the same.

How is that possible? Let’s look under the hood for a moment. The separation of the front-end implementation from external services is achieved using the following parts:

GraphQL schema

GraphQL resolvers

Apollo server

GraphQL Schema