GraphQL, From Theory to Real-World With Spring-Boot
This article is the first part of a series of articles that we will go through. The series is about mastering the necessary core concepts of the GraphQL Specification to set up a real-world server-side implementation example with spring boot. Each episode is designed to be consumed independently so feel free to start from what interests you the most.
- GraphQL Core concepts (this one) 📈
Getting started with the core concepts of GraphQL to build a real-world example - First GraphQL API and Efficient graphQL error handling in Spring-boot 🧯
Set up your Spring-boot project and expose your firsts GraphQL endpoints Get an in-depth understanding of GraphQL error handling mechanisms - Secure your graphQL APIs within a Spring-boot 👮♂️
Set up access control level on your APIs to define who can have access to which if your APIs - Testing your graphQL APIs in a Spring-boot app 🚀
Writing unit and integration tests for your graphQL APIs
Overview
What is GraphQL?
It is a new API Standard developed and used by Facebook since 2012 but open-sourced since 2015. It is a more flexible and powerful alternative to REST.
GraphQL specification has a rapidly growing community and some of the popular companies that use that are Github, Coursera, Twitter, Shopify, yelp, to name only a few.
GraphQL vs REST
The idea behind REST is great as it advocates the usage of stateless servers and structured access to resources. But there are shortcomings such as inefficiencies and lack of flexibility encountered by developers and that’s why graphQL was developed for.
To better illustrate the differences, we will introduce the Social Shopping App (SSApp) that we are going to develop all along with this series.
SSApp:
Our app consists of users, browsing some shopping articles within the app that they can like and buy. Users can sell articles and follow other users so that they can check their activities on the app. That’s it!
Ok, let’s come back to the illustration, consider we want to display the user home screen:
To achieve this is REST:
3 API endpoints from the server:
/users/<id>
Returning:
{
"user": {
"id": "flkzopgz12"
"name": "Samanta Calgon"
"address": {...}
"birthday": "May 15, 1995"
}}
Notice we just need the name
, but we are fetching useless additional data at this point. We are draining the user data plan. 🤦♂️
Then:
/users/<id>/articles?liked=true
Returning:
{
"articles": [{
"id": "dmflgmjlsfgs4z545"
"title": "Vuicci Sweet Shirt",
"description": "Lorem ipsum ...",
"liked": "true"
"reviews": [...]
},{
"id": "dlkfjge919zzz"
"title": "Diara Eau de Parfum",
"description": "dolor epsumet ...",
"liked": "true"
"reviews": [...]
},{...}
...]}
This time also, we just need the title
of the articles.
And
/users/<id>/followers
Returning:
{
"followers": [{
"id" : "dlkfhosdid2e15",
"name" : "Klark",
"address": { ... },
"birthday": "January 21, 1998"
},{
"id" : "94erg48h4j",
"name" : "Rose",
"address": { ... },
"birthday": "January 21, 1998"
},{ ... }
...
]}
Here, we are downloading a lot of data that we don’t need as well.🤦♂️
The fact that we are getting more than the data than we essentially want is called over fetching.
The fact that we can’t get enough information in one request, and need to send many ones to gather all information is known as the under fetching problem.
Yes, you can adapt your REST API to the screen so that it returns only the data needed for display, using the so-called View Models. By doing this, you are highly coupling your views to the endpoints. This way, each time the view will evolve, your API shall evolve too. Which is very bad for API scalability.
Fortunately, we can solve the above problems with graphQL. 🔥
We can retrieve what we need by issuing only one request. GraphQL uses only one endpoint, usually /graphql
.Sending a request in GrapQL means issuing a post request at this endpoint, and describe in the request body what data do we exactly need from the server.
query {
User(id: "flkzopgz12") {
name
articles(liked: True) {
title
}
followers{
name
}
}
}
Notice, in words in bold, we tell the server exactly what we need. The server will then process and match this description to the corresponding methods to get the data. Those methods are the resolvers. Resolvers will get the data from a DB, another web service, etc then package them into a JSON object and return them to the client.
{
"data": {
"user": {
"name": "Samanta Calgon",
"articles": [
{ "title": "Vuicci Sweet Shirt"}
{ "title": "Diara Eau de Parfum"}
{ "title": "Timiland Shoes"}
{ "title": "Lavis Jeans White Vintage"}
],
"followers": [
{ name: "Klark"},
{ name: "Rose"},
{ name: "Rick"},
{ name: "Josh"},
]
}
}
}
The root field of the data part of a graphQL response is data
, according to the graphQL specification.
GraphQL vs REST in a nutshell
No more over and under fetching
No need to adapt the APIs to the view which enables rapid product iterations.
Moreover, GraphQL uses a strong type system to define the cans and cants of your API. You just have to define your types in a Schema file, written in the Schema Definition Language (SDL). This schema will represent the contract between the Frontend and the backend teams, enabling them to work independently in an API-first like fashion.
Now that you know why GraphQL is a better alternative to REST, we can now dive into the core concepts of GraphQL.
GraphQL Core Concepts
The Schema Definition Language (SDL)
It lets us define our schema, which is made up of types.
This example illustrates a one-to-many relationship between 2 types:
type User {
id: ID! # Value generated by the server
name: String! # String,Int,ID are built-in type
age: Int! # ! means age is required
articles: [Article!] # A user can be have many Articles
}type Article {
title: String!
seller: User! # An article is sold by a User
description: String
}
In GraphQL, fetched data are not fixed, as you saw earlier, you can decide to retrieve ONLY the User articles, or retrieve JUST the User age, or even JUST the Users articles’ title. The client decides of what he needs.
One important thing to notice is that because we didn’t define a field password
in the User type in the schema, this field is unretrievable by the client. No more need to bother with JsonIgnore
configurations. That’s the power of the GraphQL strong type system. The server decides of what is possible or not for the client.
The client decides of what he needs
The server decides of what is possible or not for the client
The client decides what he needs by sending requests to the server
These are the three kind of requests:
- Query: Retrieve data
- Mutation: Change data
- Subscription: Event-based real-time notifications
Examples:
# Query
query{ #starts with the keyword query
allUsers {
name
}
}
# returns
{
"allUsers" : [
{"name":"Samanta Calgon"},
{"name":"Carlos Chavez"},
...
]
}# Mutation
mutation{ #starts with the keyword mutation
createUser(name: "Miguel Reyes", age: "21") {
id
}
}
# returns
{
"createUser" : {
"id" : "slkdjfr96f4d"
}
}# Subscription, listening to new articles creation
susbscription { #starts with the keyword susbscription
newArticle {
title
description
seller {
name
}
}
}
#When an article is created by another client,
#while the subscription is active, this client will receives
{
"Article" : {
"title" : "Marins Jacket, green",
"description" : "Real Marins Jacket refurbished from 2015"
"seller" : {
"name":"Carlos Chavez"
}
}
}
The Server decides what is possible or not by defining the schema
The schema, as mentioned earlier, is the contract between client and server, is written using SDL and defines the capabilities of the API by the means of GraphQL types.
Functionally, we can see types as of 2 kinds:
- Types to describe the data structure, custom, and built-in ones
(User, Article, String, ID, …)
- Types to describe the entry points exposed by the API
(Query, Mutation, and Subscription)
Let’s illustrate that by defining the schema corresponding to the examples we saw before.
#Custom and buitl-in Data Structure typestype User {
id: ID! # Value generated by the server
name: String! # String,Int,ID are built-in type
age: Int! # ! means the field is required
articles: [Article!] # A user can be have many Articles
followers: [User]}type Article {
title: String!
seller: User! # An article is sold by a User
description: String
}
#Types describing entrypointstype Query {
allUsers(last: Int): [User!]! #last parameter is optional
user(id: Int): User #No '!', The returned user can be empty #...}type Mutation {
createUser(name: String, age: Int): User!
#Want the client to create an article ? define the operation here
#...
}type Subscription {
newArticle: Article! }
Now that you have a better vision of what is GraphQL, you are able to step through the next part which is about writing your first GraphQL API with Spring Boot
Conclusion
GraphQL is a better alternative to REST because it offers flexibility and efficiency during application development. This article aimed to prove that while explaining the core concepts of this specification.
Nevertheless, GraphQL is just a specification, that needs to be implemented for both the client and server-side. We will focus on the server-side, especially with Java and Spring-boot for the next parts of this series.
Feedback is a Gift 🎁!