What is GraphQL?
- GraphQL stands for Graph Query Language. It is a language for querying the data as per user needs by using a single endpoint.
- It is an open-source query language that describes how a client should request information through an API by using a single endpoint. GraphQL is a syntax that can be used to ask for specific data as per client requirements and no need to give different APIs for each different data.
- It can be used with a custom query for API, and run the API in the form of the query language on the server side by using a type system that defines how you can define your data by query and run by using only one endpoint rather than the use of multiple APIs in REST.
- There are three major considerations while using GraphQL:
// Write for what you want //
{
project (name: "GraphQL") {
tagline
}
}
//Describe or define data //
type Project {
name: String
tagline: String
contributors: [User]
}
// Get the required result //
"project": {
"tagline": "A query
language for APIs"
}
}
How does GraphQL work?
- GraphQL provides a different set of types that query on that particular data by using schema and then, queries and mutations are come, and validated by using schema, and processed by using resolver.
- Schema- Schema is how you will define your data or how you request your data and how the API will respond to that data. The schema is the concept of server and client.
- Resolver- Resolver is used for fetching the data, processing the data, then transferring the fetched data and processing the data by using GraphQL array. Resolver gives the result by using the callable function.
Why use GraphQL instead of REST?
- It gives us a single endpoint, we do not need to create the different APIs for the same data. GraphQL is strongly typed, you can also check or validate the GraphQL query before the execution.
- GraphQL helps to build powerful APIs and clients also know what they exactly want and what different types of operations they can perform.
Example-
- Suppose, we have two applications one is Web Application and the second is Mobile Application, and /getBooks is an API for fetching the data.
- Web Application can send the request for getting the book details by using the field like id, title, description, price, and author, also Mobile application wants the same data but uses only two fields id and title only.
- But we made the normal APIs, so Mobile Application wants only two fields of id and title, but by using normal APIs Mobile Application gets all the data like id, title, description, price, and author when the Mobile application hits the same endpoint /getBooks.
- Even though we use different data we made the different REST APIs for Web Application and also for Mobile Application, so this is a very costly and inefficient way. This problem is solved by GraphQL. By using GraphQL the data is passed into the form of the query by using a single endpoint.
What is the difference between GraphQL and REST API?
- The difference between GraphQL and REST is how data will be sent by the client or in which manner they were sent. In the REST API, the client sends the HTTP request and gets the data as an HTTP response. Other than GraphQL, the client sends the request in the form of Queries.
Types of operations in GraphQL
- Two types of operations are performed in GraphQL:
- Queries
- Mutations
- Queries: By using Queries we fetch or get the data.
Queries are written like,
type Query {
Greetings
}
And how to run the Queries,
// query with name myQuery
query {
myQuery {
greetings
}
}
- Mutation: Mutations is use to modify server-side data. By using mutation, we insert, update or delete the data.
Mutation writes like,
type Mutation {
greetings
}
And how to run the Mutation,
// query with name myQuery
mutation {
myQuery (fieldname: {
greetings
})
}
Annotations in GraphQL with Springboot
- Annotations are used in GraphQL with Springboot:
- @SchemaMapping: The @SchemaMapping annotation is used with both Mutation, Query, and Subscription.
- @QueryMapping: The @QueryMapping is used to get the data.
- @MutationMapping: The @MutationMapping is used when modifying or creating the data.
- @Argument: The @Argument is used to filter out the data, like example: id.
Inbuilt data types in GraphQL:
- GraphQL provides some inbuilt datatype:
Data types | Description |
Int | A signed 32‐bit integer. |
Float | A signed double-precision and floating-point value. |
String | A UTF‐8-character sequence. |
Boolean | true or false. |
ID | The ID scalar type represents a unique identifier, often used to prefetch an object or as the key for a cache. |
ENUM | Enumeration types are a special type of scalar that is restricted to a particular set of allowed values, etc. |
Example of GraphQL with Spring Boot:
Follow the below steps:
- Create a Springboot project using spring initalizr.
- Choose the Project field as Maven, Language as Java, and Springboot version give the name to the project.
- Add dependency of Spring Web, Spring for GraphQL, Spring Data JPA, and choose any database driver (e.g., MySQL Driver here).
- Extract the Springboot application and import the application into any IDE (e.g., Eclipse here) and open the pom.xml, and check whether the dependency is correctly added or not.
// pom.xml //
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.1.1
com.graphql
graphqldemo
0.0.1-SNAPSHOT
graphqldemo
Demo project for Spring Boot
17
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-graphql
org.springframework.boot
spring-boot-starter-web
com.mysql
mysql-connector-j
runtime
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.springframework
spring-webflux
test
org.springframework.boot
spring-boot-devtools
runtime
true
org.hibernate
hibernate-core
6.2.4.Final
pom
com.fasterxml.jackson.core
jackson-databind
org.springframework.graphql
spring-graphql-test
test
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok
- Open the application.properties file. Configure the port for API and MySQL database.
// application.properties //
server.port=8009
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/Graphql_db
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
- Create the package in src/main/java directory, and create the model class(here, Book.java).
// Book.java //
package com.graphql.graphqldemo.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "book_details")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String title;
private String desc;
private String author;
private double price;
private int pages;
public Book() {
super();
// TODO Auto-generated constructor stub
}
public Book(int id, String title, String desc, String author, double price, int pages) {
super();
this.id = id;
this.title = title;
this.desc = desc;
this.author = author;
this.price = price;
this.pages = pages;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
@Override
public String toString() {
return "Book [id=" + id + ", title=" + title + ", desc=" + desc + ", author=" + author + ", price=" + price
+ ", pages=" + pages + "]";
}
}
- Create another package and create the Repo class (here, BookRespository.java).
// BookRespository.java //
package com.graphql.graphqldemo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.graphql.graphqldemo.model.Book;
public interface BookRepository extends JpaRepository{
}
- Create another package and create a Service class (here, BookServices.java).
We are injecting BookRepository dependency on this service.
// BookServices.java //
package com.graphql.graphqldemo.services;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.graphql.graphqldemo.model.Book;
import com.graphql.graphqldemo.repository.BookRepository;
@Service
public class BookServices {
@Autowired
BookRepository bookRepository;
//Adding Book
public Book addBook(Book book) {
bookRepository.save(book);
return book;
}
//GetAll Customers
public List getBooks(){
List book = new ArrayList<>();
bookRepository.findAll().forEach(books -> book.add(books));
return book;
}
//Get Customer findById
public Book getBookById(int id) {
return bookRepository.findById(id).get();
}
}
- Create another package and create the Controller class (here, BookController.java)
- Instead of @GetMapping in REST, in GraphQL we are using @QueryMapping to get or fetch the data.
- Instead of @PostMapping in REST, in GraphQL we are using the @MutationMapping to add or create the data.
// BookController.java //
package com.graphql.graphqldemo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.graphql.graphqldemo.model.Book;
import com.graphql.graphqldemo.services.BookServices;
import lombok.Getter;
import lombok.Setter;
@Controller
//@RestController
//@RequestMapping("/books")
public class BookController {
@Autowired
BookServices bookServices;
// @PostMapping("/addBook")
@MutationMapping("createBook")
public Book addBook(@Argument BookInput book) {
Book b = new Book();
b.setTitle(book.getTitle());
b.setDesc(book.getDesc());
b.setAuthor(book.getAuthor());
b.setPrice(book.getPrice());
b.setPages(book.getPages());
return this.bookServices.addBook(b);
}
// @GetMapping("/getBooks")
@QueryMapping("allBooks")
public List getBooks(){
return bookServices.getBooks();
}
// @GetMapping("/getBook/{id}")
@QueryMapping("getBook")
public Book getBookById(@Argument int id){
return bookServices.getBookById(id);
}
}
class BookInput{
private String title;
private String desc;
private String author;
private double price;
private int pages;
public BookInput() {
super();
// TODO Auto-generated constructor stub
}
public BookInput(String title, String desc, String author, double price, int pages) {
super();
this.title = title;
this.desc = desc;
this.author = author;
this.price = price;
this.pages = pages;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
@Override
public String toString() {
return "BookInput [title=" + title + ", desc=" + desc + ", author=" + author + ", price=" + price + ", pages="
+ pages + "]";
}
}
- Here is the folder structure:
- Go to the resources folder and create a graphql folder or if it already exists then don’t create it. Create one file into that folder name schema.graphqls.
- Writing GraphQL query into the schema.graphqls file.
- The Query is to get or fetch the data and in type Book their data fields like id, title, desc, author, price, pages, and also have many more fields that you can have and with its datatypes. There is an id that has the ID datatype and “!” with an ID datatype that indicates the Not null. And there is also String and Int datatype for other fields.
- Mutation is used to add or create the data and data will be inserted into the database.
// schema.graphqls //
type Mutation{
createBook(book:BookInput):Book
}
type Query{
allBooks:[Book]
getBook(id:Int):Book
}
type Book{
id:ID!
title:String
desc:String
author:String
price:Float
pages:Int
}
input BookInput{
title:String
desc:String
author:String
price:Float
pages:Int
}
- Run the application and go to the MySQL workbench for checking if the database was created or not, if it is created then open the Postman for checking the API.
- When opening the postman, we have to add some data to the database so select the POST method and write the API and write only ”localhost:8009/graphql”.
- Go to the MySQL workbench and check if the database was successfully created or not and after checking the database go to Postman and perform the POST operation.
- Now getting all the book details based on the field,
- Now getting the book record based on id,
We have covered GraphQL and its use case with the Spring Boot application. We also covered GraphQL schema types, queries, and mutations with examples. By using GraphQL the data is passed into the form of the query by using a single endpoint.