Having a conversation with an API thru GraphQL

Elastique
DataSeries
Published in
10 min readMay 8, 2019

--

At Elastique we’re always looking for new and innovative ways to reach users and create a unique experience. Whether it’s voice interfaces, gaming, pixel perfect animations or a bold implementation of GraphQL, we’re never afraid of the challenge. Today full-stack developer Bob Meijwaard takes you through his experiments with GraphQL, and what it could do for you.

TL;DR

  • GraphQL enables us to write ‘custom’ queries against an API.
  • Exposing parts of the domain model gives the consumer freedom to ask the API whatever they want.
  • Using GraphQL we move some of the business logic away from the backend to the frontend, depending on your business this can either be useful or a big problem.
  • GraphQL gives a lot of freedom to the frontend, which is ideal when you don’t already know all of the specific use cases.
  • The flexibility and richness of the query language also adds complexity that may not be worthwhile for simple API’s.

The conversation starter: why talk about GraphQL at all?

So why am I going to spend time talking about GraphQL? Of course we’ve heard about it before, but our first real contact with GraphQL was through AWS AppSync. Because of the current cloud platform movement, with many of our API’s powered by Amazon AWS, Google Cloud or other cloud based solutions, a lot of questions come to mind, like “Is this a potential replacement for our ‘default’ REST API’s? And more specifically, what would be the impact if when we choose to develop an API with (only) a GraphQL endpoint? To answer this we first need to know what GraphQL is.

As with any new development, first thing to do is to turn to Wikipedia:

“GraphQL is an open-source data query and manipulation language for API’s, and a runtime for fulfilling queries with existing data.”

GraphQL gives us an efficient and flexible approach to developing Web API’s, and is directly compared to the “normal” REST API’s. Question is of course: how?. Using GraphQL the client, if it’s a webpage or a native application, defines the structure of the data it needs at that time, instead of the server. This means that instead of returning all the data available, the client only receives the data it actually asked for. It’s like ordering a hamburger at MacDonalds and actually getting a hamburger, not the hamburger, a side salad (why?) and 2 Coke’s, because this burger was only available in a menu.

Interestingly, GraphQL was initially developed internally by Facebook back in 2012. Facebook noticed that their iOS and Android apps suffered poor performance. At this time their native apps acted as thin wrappers around the mobile website, which might sound like a great idea, but in reality pushed the webviews beyond their limits. The amount of code that was needed to parse all the different forms of data, both on the server as on the client, inspired them to shape GraphQL. Fast forward back to the now, Facebook released the GraphQL project to the public, and even moved it away to the Linux Foundation as an open source project. Nowadays big companies like Github, Pinterest, KLM and (no surprise) Facebook, implemented GraphQL into their products.

Let’s get physical, from REST to GraphQL

Moving from REST to GraphQL has an interesting way of rethinking responsibilities and what this means to work with, from a back- and frontend perspective. So far in my journey I found that speaking to a GraphQL endpoint (Query) makes a lot more sense then teaching GraphQL to change the data (Mutation). Huh, say what? It was quite a hassle to make mutations. I’m reading more and more criticism from others implementing GraphQL in their API. Some even call it being on the same level as SOAP is/was in terms of frustration.

The ground rules

Today we’re talking about the pros and cons of implementing GraphQL in a .NET Core environment. I’ve setup a single .NET Core 2.2.3 REST API and implemented a simple Entity–relationship model as a base for our domain model to cover the grounds of the basics required to implement a meaningful API service. This will enable us to have a conversation with our API and ask them all kinds of questions related to our domain.

The ingredients: GraphQL in five statements

  1. GraphQL is a ‘replacement’ or ‘competition’ for normal API’s
  2. GraphQL allows the client to define the structure of the required data
  3. GraphQL prevents excessive amounts of data transfers
  4. GraphQL’s flexibility also adds complexity that may not be worthwhile for simple API’s
  5. GraphQL offers a query language, execution semantics, validation and type introspection

For the sake of argument I will add the following statement from GraphQL.org:

GraphQL isn’t tied to any specific database or storage engine and is instead backed by your existing code and data

Why? Within our company I was talking to other developers about GraphQL and enthusiastically telling them about building a GraphQL endpoint in a .NET Core application. The first question that most of them asked was “Does this store the data?” And “How is GraphQL storing the data?”.

This question can be traced back to our experience, which I’ve mentioned earlier on, with AWS AppSync. With AWS App Sync the complete (backend) package is offered, including storage. In terms I would explain that GraphQL only offers an endpoint into which we could query against. It’s a query language for API’s. What it does is transfer data requested by the user, but we’re still in control of storing that data. As such, GraphQL is only a part of the presentation layer (3-Tier Architecture).

The 3-tier Architecture

This 3-tier architecture is also where one of the considerations apply. By using GraphQL we (partially) move away business logic into the presentation layer. To construct this into a logical architecture one could wonder, is this what we really want to be doing? The first thing that comes to mind is when providing statistics. GraphQL could ‘easily’ provide data through some query where the backend (and the business logic) doesn’t really care about what the client is asking from the API.

That being said, let’s get back to my statements about GraphQL.

1. GraphQL is a ‘replacement’ or ‘competition’ for normal API’s

Is GraphQL really a contender in the pool of established web service architecture? Let’s dive in. When creating the first iteration of a GraphQL endpoint I noticed that you actually have to create an endpoint for the GraphQL service to consume, which is a HTTP POST method endpoint that consumes some kind of request body that could transform into a GraphQL request.

For me this means two things. 1) Ultimately it is more of an icing on top of a traditional REST API, since you only have 1 endpoint compared to many. And 2) this means I can easily write a combination between a standard REST API and a GraphQL endpoint. To me, that’s a huge benefit. On one side I could create specific API endpoints for calls that we do not want to pass through GraphQL. I mean, just think about all of the complex and use case specific calls or security reasons to use to enable this. If you have a system that has a set of Roles and Claims set, then imagine reconfiguring your GraphQL endpoint to handle this additional logic. Being able to (temporarily) avoid diving into depths in GraphQL technic can save some serious headache and development cost. What it also means is that migrating from an existing REST API could be done in ‘steps’ instead of fully committing to GraphQL from the start.

2. GraphQL allows the client to define the structure of the required data

The client defining the structure of the data is a very strong part of the GraphQL technique, and the biggest reason (for me) to navigate into the possibilities that GraphQL has to offer. This can be done using a query (GraphQL separates lookups from writes, updates, deletes into Query and Mutation). The query can be build up into a statement and has a JSON like form of writing. I could ask the endpoint something like, give me a list of email addresses from all users. Translating that into a GraphQL query it would be something like:

{  users {    email  }}

Structures like this makes it possible to look up all sorts of data against various different queries. From a frontend perspective this could be very useful. You do not need an additional API endpoint from the backend, rather you just write your own query. This means you could change the request easily if you need more (or less) information and you could even write your queries in such ways that you can potentially reduce server to client roundtrips.

But, data structures like this are a direct implementation of your domain, while you typically want to do all kinds of lookups. A possible question could also be, give me a list of email addresses from users who haven’t confirmed their email. Well, f*ck me, this is where the shit starts to stink. We could also put the emailConfirmationDate in the result of the first request and make the client responsible for filtering. Or we could improve our GraphQL schema to provide this type of query.

So in order for the GraphQL endpoint to be able to answer this question, we’d have to create a field on the query schema. Meaning we’re coupling a part of our business logic layer to the GraphQL schema to be able to expose this. This sounds very close to creating a new API endpoint. So this is not really helping us developers, we are still bothered to program additional logic.

An example of a GraphQL query getting specific user information

3. GraphQL prevents excessive amounts of data transfers

Looking back at the previous topic we had a single API call where we could say: “Give me a list of email addresses of all users”. If you’d have a repository or service that had a function of something like this _userService.ReadAsync(), which returns a list of all users. This call is hooked into a field of the GraphQL schema. So, what will happen? The end user will only receive an array of users with the email address of this user. Nothing more. We’ve just prevented excessive amounts of data transfer. False, we did so between server and client. But if you where to look in the diagnostics tool of your IDE you would notice that a request is fired against your database which basically translates to SELECT * FROM Users So the rest of the data is cut-off somewhere in your backend code. Not to mention if you have enabled lazy loading of all your navigating properties. Yes, this reduces data transfer from API to client, but it simply hides fetching bulks of unused data from your data source. So, not really what you want…

4. GraphQL’s flexibility also adds complexity that may not be worthwhile for simple API’s & 5. GraphQL offers a query language, execution semantics, validation and type introspection

They definitely got that right. Being able to be more flexible on the queries has proven to add a lot of complexity. It could be that my lack of experience with GraphQL has something to do with this, but it was definitely more challenging than expected. Every entry on an entity has to be defined in the schema, and every relationship with another entity has to be defined as well. Aggregating data cannot be done out of the box. You can hookup DTO’s and services to the schema, rather than repositories, creating the default abstraction between your data layer and our presentation layer. This enables you to expose composites and aggregated objects of your domain to GraphQL.

This on the other hand nullifies the reduced work of not having to write various API endpoints, you’re basically just adding the same logic to the GraphQL schema. So how could we tackle this problem? Enter Entity Framework (EF). EF provides the option to work against an IQueryable. The IQueryable is an interface that evaluates queries against a specified data source. So it would be useful for our GraphQL endpoint to have access to this interface in order to expose our domain to custom (runtime) queries. This way (in theory) we only query what we ask the GraphQL endpoint. Definitely a good topic for further research is to enable GraphQL to work with the IQueryable interface and provide true flexibility to our endpoint.

The roundup

There is some merit in creating an endpoint using GraphQL. The option to enable at least flexible queries to lookup parts of your domain can be very useful and could potentially speed up the development process. However there are some pitfalls to take into account. Creating a full blown GraphQL endpoint with Mutation, sockets, query caching and authentication is not something I’d recommend if you don’t have the experience. GraphQL is just a nice ‘icing’ on your API and can hide some serious amounts of unused data going through your application. You definitely have to think about some strategic advantage to use GraphQL and properly expose the right parts of your domain. Going with a hybrid solution (with a part of your GraphQL solution being a ‘regular’ REST API) is safest and might also be a wise choice when migrating from REST to GraphQL. Take it small steps at a time and pay good attention to what happens ‘under-the-hood’.

Did you like this article? And do you want to keep up to date on our next posts? Follow us on LinkedIn and see directly when a new post is live!

Elastique is a dynamic digital boutique agency. A collective of tech wizards, concept guru’s and design rockstars dreaming up award-winning digital experiences. We work with leading brands and media companies to create innovative solutions that truly stand out. This is what Elastique stands for and we are always looking for people who want to stretch the paradigm of storytelling and interactivity. Get in touch at https://elastique.nl or info@elastique.nl.

--

--

Elastique
DataSeries

We are digital pioneers. A solid team of tech wizards, concept guru’s and design rockstars dreaming up award winning digital experiences. https://elastique.nl