UrbanNoise first steps — GraphQL introduction
Finally we(yes, we are 3 members!!) are making some progress defining our architecture for this open source project. We don’t want to suffer with possible modifications in the future, so we are investing a lot of time in this topic in order to get a brand new and awesome backend architecture which provides us all the best benefits of modern distributed systems and of course best practices.
This was our first article when the idea was presented and I was looking for some people to help me on this, so if you didn’t read it please feel free to do it:
Common Scenario
I am sure that many of the developers who can be reading this right now can imagine themselves in this situation:
- Fast paced company with fast paced product features
- “REST” APIs trying to live in the middle of the jungle (monolith) called “Tech debt”
- UIs cooking great spaghetti code with spicy frameworks/libraries like ReactJS or VueJS in the same pot (frontend monolith)
If you can imagine yourself in that company you will have night sweats tonight. Features coming and changing during the SDLC will mess up the API design, developers will try to accomplish the goal just creating endpoints and consuming them without thinking before what the product really needs in a long term.
Overfetching (fetching too much data, meaning there is data in the response you don’t use) and underfetching (not having enough data with a call to an endpoint, forcing you to call a second endpoint) happen every time a page is loaded in the client, affecting the performance of the UI and API.
API design will get more crazy every day and it will arrive at a critical point where it is impossible to maintain, to test, to scale, to modify and even impossible to create simple things in a straight way.
Same for the UI, adding more and more code just to get the data they need from several endpoints, adding more and more code and getting the same problems mentioned above in the API scenario.
You would think at this point
“Oh man, these guys need a distributed architecture”
Yeah, they need it without any doubt, but they need to think about their project, how it is evolving, how it is changing quickly… and try to be one step ahead of these problems.
And that’s we stand. We try to be one step ahead of the future and after investigating a lot and thinking even more we decided to use GraphQL for our communication between the server and the client(s).
Why GraphQL?
GraphQL is quite a hot trend topic these days but it was created by Facebook some years ago in 2012 (and open sourced in 2015).
It is query language for any application layer. At the end, you can decouple your data in any way, and you can ask for the data you want to be consumed and getting predictable results from the client.
It has some core concepts which need to be understood before.
Schema Definition Language (SDL)
GraphQL has its own type system that’s used to define the schema of an API. The syntax for writing schemas is called Schema Definition Language (SDL).
Queries
When working with REST APIs, data is loaded from specific endpoints. Each endpoint has a clearly defined structure of the information that it returns. This means that the data requirements of a client are effectively encoded in the URL that it connects to.
The approach that’s taken in GraphQL is radically different. Instead of having multiple endpoints that return fixed data structures, GraphQL APIs typically only expose a single endpoint. This works because the structure of the data that’s returned is not fixed. Instead, it’s completely flexible and lets the client decide what data is actually needed.
That means that the client needs to send more information to the server to express its data needs — this information is called a query.
Mutations
Next to requesting information from a server, the majority of applications also need some way of making changes to the data that’s currently stored in the backend. With GraphQL, these changes are made using so-called mutations. There generally are three kinds of mutations:
- Creating new data
- Updating existing data
- Deleting existing data
Mutations follow the same syntactical structure as queries, but they always need to start with the mutation keyword.
Subscriptions
Another important requirement for many applications today is to have a realtime connection to the server in order to get immediately informed about important events. For this use case, GraphQL offers the concept of subscriptions.
Schema
The schema is one of the most important concepts when working with a GraphQL API. It specifies the capabilities of the API and defines how clients can request the data. It is often seen as a contract between the server and client.
Generally, a schema is simply a collection of GraphQL types. However, when writing the schema for an API, there are some special root types:
type Query { ... }
type Mutation { ... }
type Subscription { ... }
The Query, Mutation, and Subscription types are the entry points for the requests sent by the client.
Now imagine we are building a Schema to get all the users that we have in a blog post application. The Schema should have something like this:
type Query {
allPersons(last: Int): [Person!]!
}type Mutation {
createPerson(name: String!, age: Int!): Person!
}type Subscription {
newPerson: Person!
}type Person {
name: String!
age: Int!
posts: [Post!]!
}type Post {
title: String!
author: Person!
}
We are using SDL to define all the schema as needed. We have different scalar types and also we can create relationships between types like in Person where there is a one-to-many-relationship with Posts.
Here is an example how we can use the SDL to define a simple type called Person:
We also have the Mutation to create new users in the web application and the subscription for these ones!
Now everything is defined to imagine how the “allPersons” query will perform. Let’s start for a simple example fetching all the persons but only their name and age information.
This would be the query sent in the request body for that particular case:
{
allPersons {
name
age
}
}
And this would be the response:
{
"data": {
"allPersons": [
{
"name": "Johnny",
"age": 23
},
{
"name": "Sarah",
"age": 20
}
]
}
}
Now imagine that our Product Manager comes running to the office after another meeting and says:
“Guys guys guys! we need to show all the posts created by the logged in user in the main page! They are requesting this asap to get the renewal!!”
And you as a GraphQL evangelist stay calm and shows him that particular case is already done in the backend in this way:
{
allPersons {
name
age
posts {
title
}
}
}
Receiving the next response:
{
"data": {
"allPersons": [
{
"name": "Johnny",
"age": 23,
"posts": [
{
"title": "GraphQL is awesome"
},
{
"title": "Relay is a powerful GraphQL Client"
}
]
},
{
"name": "Sarah",
"age": 20,
"posts": [
{
"title": "How to get started with React & GraphQL"
}
]
]
}
}
In case of using the defined mutation in the schema above, you would need to pass this request body (remember you can ask what you need in the response, you can need name and age like in this example):
mutation {
createPerson(name: "Bob", age: 36) {
name
age
}
}
And you would get this response:
{
"data": {
"createPerson": {
"name": "Bob",
"age": 36
}
}
}
Easy peasy, isn’t it? Now let’s move to benefits and disadvantages of GraphQL
Benefits of GraphQL
Most of them have been mentioned along this article before, but let’s summarize the principal ones:
- Simplicity: Data is collected under a common endpoint or call that is variable concerning the type of data and request as stated in the initial call.
- Stability: With simplicity comes stability. The more simple a process is, the less likely there are to be faults in the planning, construction, execution, and continued operation over time.
- Efficiency: Because data is defined on the server with a graph-based scheme, data can be delivered as a package rather than through multiple calls.
And more of them like robustness, speed of development, ease of refactoring, etc.
Disadvantages of GraphQL (are there any?)
Most of these disadvantages are commong with distributed architectures, but like we did it whi the benefits, let’s pick only the most important ones:
- You need to learn how to set up GraphQL. The ecosystem is still rapidly evolving so you have to keep up
- You need to define the schema beforehand (architecure phase is longer than expected in some cases)
- Graphql queries are more bytes than simply going to a REST endpoint
- Rate limiting of calls becomes difficult coz now the user can fire multiple queries in one call
And some others like authentication, authorization, pagination, etc, but nothing more than interesting challenges for a motivated team!
Distributed architectures using GraphQL
Our last point in this introduction article about GraphQL is a common situation nowadays. You had convinced your company that you need microservices and GraphQL. You have explained everything about benefits, examples and of course disadvantages. But your CTO asks you:
“If we have different microservices or serverless functions using GraphQL you will have different schemas which have different URLs and at the end the clients will need to perform several endpoints to get specific data in some cases. Right?”
“Oh man, he caught me”
Do not panic.
In this case, you have two options:
- Schema stitching: is the process of creating a single GraphQL schema from multiple underlying GraphQL APIs, merging schemas and adding resolvers between schemas
- Schema federation: you can divide your data graph’s implementation across distinct, composable services with Apollo Federation. Apollo Federation uses a declarative programming model that makes it easy for each implementing service to implement only the part of your data graph that it should be responsible for.
They are deep and advanced concepts of GraphQL and they need another article to try to explain them in a right way. But at least you know that it is possible and lot of people have done it so far.
Conclusion
And based on pretty much everything I mentioned above, we decided to go with GraphQL. We think that because of its benefits, GraphQL is becoming more and more important for distributed architectures and applications with frequent changes. Like we were using web services and we evolved to APIs, we are more or less convinced that we will be using GraphQL in the near future for web/mobile applications.
We’ll continue this article with our solution for UrbanNoise, our open source project. Just a tiny spoiler, we’ll use serverless Azure Functions (v3 preview) with .NET Core 3 together with GraphQL.NET Nuget Package and DDD. Ill try to cover our particular architecture in a generic way for all functions we’ll have.
Hope you enjoyed it
References
https://nordicapis.com/5-potential-benefits-integrating-graphql/
https://www.adaltas.com/en/2018/11/27/graphql-advantages-over-rest/
https://www.apollographql.com/docs/intro/benefits/
https://stackoverflow.com/questions/44564905/what-is-over-fetching-or-under-fetching
https://www.howtographql.com/basics/2-core-concepts/
https://stackoverflow.com/questions/40689858/are-there-any-disadvantages-to-graphql
https://www.apollographql.com/docs/graphql-tools/schema-stitching/
https://www.apollographql.com/docs/apollo-server/federation/introduction/