GraphQL with Spring Boot
Tags: graphql, java, webdev, beginners
Published: 2021-12-14 16:05:38

**What Is GraphQL?**
Traditional REST APIs work with the concept of Resources that the server manages. These resources can be manipulated in some standard ways, following the various HTTP verbs. This works very well as long as our API fits the resource concept, but quickly falls apart when we need to deviate from it.

This also suffers when the client needs data from multiple resources at the same time. For example, requesting a blog post and the comments. Typically, this is solved by either having the client make multiple requests or by having the server supply extra data that might not always be required, leading to larger response sizes.

GraphQL offers a solution to both of these problems. It allows for the client to specify exactly what data is desired, including from navigating child resources in a single request, and allows for multiple queries in a single request.

Here I am going to discuss how to integrate GraphQL with Spring boot.

I am going to use below to achieve this :
1.	Spring boot libraries 
2.	GraphQL libraries 
3.	Spring JPA
4.	Hibernate
5.	Lombok
6.	Postgres

**What is GraphiQL?**
GraphQL also has a companion tool called GraphiQL. This is a UI that is able to communicate with any GraphQL Server and execute queries and mutations against it

**GraphQL Server with Connected Database**
This architecture has a GraphQL Server with an integrated database and can often be used with new projects. On the receipt of a Query, the server reads the request payload and fetches data from the database. This is called resolving the query. The response returned to the client adheres to the format specified in the official GraphQL specification.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/78ot5fatxroot5b1s23i.jpg)

In the above diagram, GraphQL server and the database are integrated on a single node. The client (desktop/mobile) communicates with GraphQL server over HTTP. The server processes the request, fetches data from the database and returns it to the client.


**Here is the full list of dependencies , I have used to work with GraphQL & Spring Boot**

```
implementation group: 'io.leangen.graphql', name: 'graphql-spqr-spring-boot-starter', version: '0.0.6'
implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.20'
implementation 'org.apache.commons:commons-collections4:4.4'
implementation 'org.jdal:jdal-core:2.0.0'
implementation group: 'com.graphql-java', name: 'graphql-java-extended-scalars', version: '2021-06-29T01-19-32-8e19827'
implementation group: 'org.hibernate', name: 'hibernate-core', version: '5.5.2.Final'
	implementation group: 'commons-net', name: 'commons-net', version: '3.8.0'
	implementation group: 'com.graphql-java-kickstart', name: 'graphiql-spring-boot-starter', version: '7.1.0'
	compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.20'
	implementation group: 'org.apache.commons', name: 'commons-collections4', version: '4.4'
	implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.12.3'
	implementation group: 'com.graphql-java-kickstart', name: 'graphql-spring-boot-starter', version: '7.0.1'
	implementation group: 'org.springframework', name: 'spring-web', version: '5.3.6'
	implementation group: 'com.graphql-java-kickstart', name: 'graphql-spring-boot-starter-test', version: '7.0.1'
	implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.5.0'
	implementation group: 'commons-io', name: 'commons-io', version: '2.10.0'
	compileOnly group: 'org.hibernate.orm', name: 'hibernate-jpamodelgen', version: '6.0.0.Alpha6'
	implementation group: 'org.modelmapper', name: 'modelmapper', version: '2.4.4'
	implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.20'
	implementation group: 'com.graphql-java-kickstart', name: 'playground-spring-boot-starter', version: '5.10.0'
	implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
	compileOnly 'org.hibernate:hibernate-jpamodelgen'
	annotationProcessor('org.hibernate:hibernate-jpamodelgen')
	implementation 'org.springframework.boot:spring-boot-starter'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
```

**My Sample Project Structure**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bsfuxs6okzab5bmhif4z.PNG)

**My Entity Classes** 

1. **Employee.java**

```
package com.example.demo.entities;

import io.leangen.graphql.annotations.GraphQLNonNull;
import io.leangen.graphql.annotations.types.GraphQLType;
import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import java.math.BigInteger;
import java.time.LocalDate;

@Entity
@Data
@GraphQLType
@Table(name = "employee")
public class Employee {

    @Id
    @Column(name = "emp_id")
    private BigInteger employeeId;
    @Column(name = "ename")
    @GraphQLNonNull
    private String employeeName;
    @Column(name = "email_id")
    private String email;
    @Column(name = "city")
    private String city;
    @Column(name = "country")
    private String country;
    @Column(name = "dept_id")
    private Integer deptId;
    @Column(name = "dob")
    private LocalDate dob;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dept_id", insertable = false, updatable = false)
    private Department department;
}
```
**2. Department.java**

```
package com.example.demo.entities;

import io.leangen.graphql.annotations.GraphQLQuery;
import io.leangen.graphql.annotations.types.GraphQLType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.util.List;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@GraphQLType(description = "This is Department")
@Table(name = "department")
public class Department {

    @Id
    @Column(name = "dept_id")
    @GraphQLQuery(description = "This is deptID")
    private Integer deptId;
    @Column(name = "dname")
    private String deptName;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "department")
    private List<Employee> employee;
}
```

**My Repositories **
**1. DepartmentDao.java**

```
package com.example.demo.dao;

import com.example.demo.entities.Department;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface DepartmentDao extends CrudRepository<Department, Integer> {

    public Department findByDeptName(String deptName);
}
```
**2.EmployeeDao.java**

```
package com.example.demo.dao;

import com.example.demo.entities.Employee;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import java.math.BigInteger;
import java.util.List;

@Repository
public interface EmployeeDao extends CrudRepository<Employee, BigInteger> {
    public List<Employee> findByEmployeeName(String ename);
}
```
**My Service classes**
**1.EmployeeService.java**

```
package com.example.demo.service;

import com.example.demo.dao.EmployeeDao;
import com.example.demo.entities.Employee;
import com.example.demo.entities.EmployeeDto;
import com.example.demo.exception.ResourceNotFoundException;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigInteger;
import java.util.List;

@Service
public class EmployeeService {

    @Autowired
    private EmployeeDao employeeDao;


    public List<Employee> getAllEmployee() {
        return IteratorUtils.toList(employeeDao.findAll().iterator());
    }

    public Employee getEmployeeByID(BigInteger eid) {
        return employeeDao.findById(eid).orElseGet(() -> {
            throw new ResourceNotFoundException("No Employee found");
        });
    }

    public List<Employee> getEmployeeByName(String ename) {
        return employeeDao.findByEmployeeName(ename);
    }

}
```
**2. DepartmentService.java**

```
package com.example.demo.service;

import com.example.demo.dao.DepartmentDao;
import com.example.demo.entities.Department;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DepartmentService {

    @Autowired
    private DepartmentDao departmentDao;

    public Department getDeptByName(String deptName) {
        return departmentDao.findByDeptName(deptName);
    }
}
```
**My Query classes**
**1.EmployeeQuery.java**

```
package com.example.demo.queries;

import com.example.demo.entities.Employee;
import com.example.demo.service.EmployeeService;
import io.leangen.graphql.annotations.GraphQLArgument;
import io.leangen.graphql.annotations.GraphQLQuery;
import io.leangen.graphql.spqr.spring.annotations.GraphQLApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigInteger;
import java.util.List;

@Component
@GraphQLApi
public class EmployeeQuery {

    @Autowired
    private EmployeeService employeeService;

    @GraphQLQuery(description = "This query is used to fetch all Employee ")
    public List<Employee> searchAllEmployee() {
        return employeeService.getAllEmployee();
    }

    @GraphQLQuery(description = "This query is used to fetch Employee by employeeId")
    public Employee searchEmployeeById(@GraphQLArgument(name = "employeeId") BigInteger eid) {
        return employeeService.getEmployeeByID(eid);
    }

    @GraphQLQuery(description = "This query is used to fetch employeeId by employeeName")
    public List<Employee> searchEmployeeByName(@GraphQLArgument(name = "employeeName") String eName) {
        return employeeService.getEmployeeByName(eName);
    }
}
```
**2.DepartmentQuery.java**

```
package com.example.demo.queries;

import com.example.demo.entities.Department;
import com.example.demo.service.DepartmentService;
import io.leangen.graphql.annotations.GraphQLArgument;
import io.leangen.graphql.annotations.GraphQLQuery;
import io.leangen.graphql.spqr.spring.annotations.GraphQLApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@GraphQLApi
public class DepartmentQuery {

    @Autowired
    private DepartmentService departmentService;

    @GraphQLQuery(description = "This query is used to fetch department by department name")
    public Department searchDeptByName(@GraphQLArgument(name = "deptName") String deptName) {
        return departmentService.getDeptByName(deptName);
    }
}
```
**Now we can see the graphql schema documentation after starting the server : **

_URL : http://localhost:8080/graphiql_

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d2la0ixv1yiulawcexs0.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/amq7qnkfpaqt8p7b2oo9.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x97g8hxo6qae6hdq96th.png)

**Execute few of queries** 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uhwpppe7pueuljinqpk3.PNG)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/444beqe3vv4zlsjmj7bs.PNG)

Here I have shared all the steps to integrate Spring boot with graphQL. I will come with other topics in my coming posts.

Thank you.. 
Arpan

Let's connect:
LinkedIn : https://www.linkedin.com/in/arpan-bandyopadhyay-bb5b1a54/