GraphQL, from Theory to Real-world with Spring-boot
imphilippesimo
Posted on June 13, 2020
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 exampleFirst GraphQL API and Efficient graphQL error handling in Spring-boot š§Æ
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 APIsTesting your graphQL APIs in a Spring-boot app š
Writing unit and integration tests for your graphQL APIs
Set up your Spring-boot project and expose your firsts GraphQL endpoints Get an in-depth understanding of GraphQL error handling mechanisms.
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:
We need, 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 how we tell the server exactly what we need with expressions corresponding to the data model schema:
User.name, User->articles.title, User->followers.name .
The server will then process and match this description to the corresponding methods to get the data.
Those methods are known as 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)
#Custom and buitl-in Data Structure types
type 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 entrypoints
type 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 š!
Posted on June 13, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.