GraphQL, from Theory to Real-world with Spring-boot

imphilippesimo

imphilippesimo

Posted on June 13, 2020

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.

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:

Alt Text

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 šŸŽ!

šŸ’– šŸ’Ŗ šŸ™… šŸš©
imphilippesimo
imphilippesimo

Posted on June 13, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related