Mansoorali Shaikh
7 min readMar 25, 2020

--

MySql+GraphQL+SpringBoot

Basic Integration of GraphQL with Sping Boot and MySql

You might have heard about how Facebook uses GraphQL in their applications . So in this article I intend to show you how GraphQL (Query Language For WebAPI’s) could be used with MySQL as a database and access it through a Spring boot application. First we make a Spring Boot application for the endpoint and then insert GraphQL as a layer between the client and the API. This is a pretty easy bottom up build. So let’s see what kind of miracle does GraphQL provides.

Why GaphQL ?

GraphQL is nothing but a query language for REST API endpoints . It isn’t tied to any sort of specific database or storage engine. Instead it is tied by your data and existing code.

The main benefits of using GraphQL are :

· Fetching data with a single API call. what I mean by this is no need to create multiple endpoints in an application unlike we do it in REST where we need to expose multiple endpoints to retrieve data like this :

https://localhost:8080/employee

https://localhost:8080/employee/{id}

Using GraphQL, we get the exact data we need or request. This is unlike in REST implementation, where we make an HTTP GET call to get a JSON response even if we are looking at the values for a few attributes. For example, when we query a REST API, we get the complete response in JSON format like below even we require only the id and name

{
"id": "100",
"first_name": "Aashish",
"last_name": "Chaubey",
"gender": "CannotDisclose"
}

GraphQL Right Usecase

GraphQL is often the right choice when network speed and latency is the primary concern and data isn’t spread across different domains but is instead centralized to one product. In this case a single network request can load many different kinds of resources at once, and selectively include only what that client needs. Particularly on mobile network connections, this can be a dramatic performance improvement.

So Let’s begin with our Spring Boot Application with GraphQL backed by MySql .

Visit Spring Initializr or use Eclipse/IntelliJ/STS IDE to generate a Spring Boot application with dependencies like Web, MySql, Spring Boot and GraphQL . And It will be a Maven project with JDK 1.8 or above.

Example of generated POM is this :

<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>3.2.0</version>
</dependency>

</dependencies>

Creating the Table


CREATE TABLE `employee` (
`id` int NOT NULL AUTO_INCREMENT,
`first_name` varchar(100) NOT NULL,
`last_name` varchar(100) NOT NULL,
`job_title` varchar(100) DEFAULT NULL,
`salary` double DEFAULT NULL,
`notes` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Insert Dummy data in the table

INSERT INTO `employee` (`first_name`, `last_name`, `job_title`, `salary`) VALUES
('Robin', 'Jackman', 'Software Engineer', 5500),
('Taylor', 'Edward', 'Software Architect', 7200),
('Vivian', 'Dickens', 'Database Administrator', 6000),
('Harry', 'Clifford', 'Database Administrator', 6800),
('Eliza', 'Clifford', 'Software Engineer', 4750),
('Nancy', 'Newman', 'Software Engineer', 5100),
('Melinda', 'Clifford', 'Project Manager', 8500),
('Harley', 'Gilbert', 'Software Architect', 8000);

Adding An API Endpoint

Let us start with a EmployeeController and add a POST request handler like this:

package com.ibm.graphql.graphqlexample.resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.ibm.graphql.graphqlexample.services.GraphQLService;
import graphql.ExecutionResult
@RestController
@RequestMapping(value = "/api/v1")
public class EmployeeController {

@Autowired
GraphQLService graphQLService

@PostMapping(value = "/employee")
public ResponseEntity<Object> getAllEmployees(@RequestBody String requestString) {
ExecutionResult executionResult = graphQLService.getGraphQL().execute(requestString);
return new ResponseEntity<>(executionResult, HttpStatus.OK);
}
}

Adding a Model Class

Let’s add a model class to represent an employee. We will name it as an Employee .

package com.ibm.graphql.graphqlexample.model;import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "employee")
public class Employee {
@Id
@GeneratedValue
@Column(name = "id")
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "job_title")
private String jobTitle;
@Column(name = "salary")
private int salary;
public Employee() {
}
public Employee(int id, String firstName, String lastName, String jobTitle, int salary) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.jobTitle = jobTitle;
this.salary = salary;
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getJobTitle() {
return this.jobTitle;
}
public void setJobTitle(String jobTitle) {
this.jobTitle = jobTitle;
}
public int getSalary() {
return this.salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
package com.ibm.graphql.graphqlexample.repository;import com.ibm.graphql.graphqlexample.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {

}

Creating a Book Repository

This respository extends JpaRepository .

package com.ibm.graphql.graphqlexample.repository;import com.ibm.graphql.graphqlexample.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {

}

Adding a GraphQL Schema

We will create a GraphQL schema , named employee.graphql in our src/main/resource folder .

schema {
query: Query
}
type Query {
getEmployee(id: Int): Employee
getAllEmployees: [Employee]
}
type Employee {
id: Int
firstName: String
lastName: String
jobTitle: String
salary: Int
}

This is a very important file and is the backbone of GraphQL. Here, we define a schema, which you can relate with a Query. We also need to tell the type of query which is triggered by any front-end applications.

In this example, we have shown two types:

· When a user queries for a specific employee by passing the id, then the application will return an employee object.

· When a user queries all the books (by using getAllEmployees) then the application will return an array of employee.

Adding a GraphQL Service

We need to add a GraphQL service. Let’s name it as GraphQLService.

package com.ibm.graphql.graphqlexample.services;import java.io.File;
import java.io.IOException;
import javax.annotation.PostConstruct;
import com.ibm.graphql.graphqlexample.services.datafetcher.AllEmployeesDataFetcher;
import com.ibm.graphql.graphqlexample.services.datafetcher.EmployeeDataFetcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
@Service
public class GraphQLService {
@Value("classpath:schema.graphql")
Resource resource;
private GraphQL graphQL;
@Autowired
private AllEmployeesDataFetcher allEmployeesDataFetcher;
@Autowired
private EmployeeDataFetcher employeeDataFetcher;
@PostConstruct
public void loadSchema() throws IOException {
// get the schema
File fileSchema = resource.getFile();
// parse schema
TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(fileSchema);
RuntimeWiring wiring = buildRuntimeWiring();
GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(typeRegistry, wiring);
graphQL = GraphQL.newGraphQL(schema).build();
}
private RuntimeWiring buildRuntimeWiring() {
return RuntimeWiring.newRuntimeWiring()
.type("Query", typeWiring -> typeWiring.dataFetcher("getAllEmployees", allEmployeesDataFetcher)
.dataFetcher("getEmployee", employeeDataFetcher))
.build();
}
/**
* @return the graphQL
*/
public GraphQL getGraphQL() {
return graphQL;
}
}

When the Spring Boot application runs, the Spring Framework calls the @PostConstruct method. In the buildRuntimeWiring() method of this service class, we are doing a runtime wiring with two data fetchers: getAllEmployees and getEmployee . The names getAllEmployees and getEmployee defined here must match with the types defined in the GraphQL file that we already created.

Creating the Data Fetchers

We need to write two separate data fetcher classes for the getAllEmployees and getEmployee types that we defined in the schema.

The data fetcher class for the getAllEmployees type is this.

package com.ibm.graphql.graphqlexample.services.datafetcher;import java.util.List;
import com.ibm.graphql.graphqlexample.model.Employee;
import com.ibm.graphql.graphqlexample.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
@Component
public class AllEmployeesDataFetcher implements DataFetcher<List<Employee>> {
@Autowired
EmployeeRepository employeeRepository;
@Override
public List<Employee> get(DataFetchingEnvironment environment) {
return employeeRepository.findAll();
}
}

The data fether class for the getEmployee type is this

package com.ibm.graphql.graphqlexample.services.datafetcher;import com.ibm.graphql.graphqlexample.model.Employee;
import com.ibm.graphql.graphqlexample.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
@Component
public class EmployeeDataFetcher implements DataFetcher<Employee> {
@Autowired
EmployeeRepository employeeRepository;
@Override
public Employee get(DataFetchingEnvironment environment) {
Integer id = environment.getArgument("id");
return employeeRepository.getOne(id);
}
}

Running the application

Let’s run our application and test it using the Postman client tool.

Run the application on port `8080` (By default Spring runs on an embedded Tomcat Server and you need not make any extra configurations in it)

Note that we have a single endpoint right now which is : `/api/v1/employee`

· Get all the employees :

query for the endpoint `/api/v1/employee` as a POST call and in the raw text body, pass this

query -

{
getAllEmployees {
id
firstName
lastName
jobTitle
salary
}
}

Response

{
"errors":[

],
"data":{
"getAllEmployees":[
{
"id":1,
"firstName":"Robin",
"lastName":"Jackman",
"jobTitle":"Software Engineer",
"salary":5500
},
{
"id":2,
"firstName":"Taylor",
"lastName":"Edward",
"jobTitle":"Software Architect",
"salary":7200
},
{
"id":3,
"firstName":"Vivian",
"lastName":"Dickens",
"jobTitle":"Database Administrator",
"salary":6000
},
{
"id":4,
"firstName":"Harry",
"lastName":"Clifford",
"jobTitle":"Database Administrator",
"salary":6800
},
{
"id":5,
"firstName":"Eliza",
"lastName":"Clifford",
"jobTitle":"Software Engineer",
"salary":4750
},
{
"id":6,
"firstName":"Nancy",
"lastName":"Newman",
"jobTitle":"Software Engineer",
"salary":5100
},
{
"id":7,
"firstName":"Melinda",
"lastName":"Clifford",
"jobTitle":"Project Manager",
"salary":8500
},
{
"id":8,
"firstName":"Harley",
"lastName":"Gilbert",
"jobTitle":"Software Architect",
"salary":8000
}
]
},
"extensions":null
}

· Query for the specific employee using id :

Here we are querying for a specific employee whose id is 2 and we want only the first_name and the last_name in its response.

query-

{
getEmployee("id":2){
"firstName
lastName"
}
}

Response-

{
"errors":[

],
"data":{
"getEmployee":{
"firstName":"Taylor",
"lastName":"Edward"
}
},
"extensions":null
}

So, that is the beauty of using GraphQL over REST API. Here we get exactly what we are looking for and not just the complete bunch of JSON response will all the attributes values in it.

You can clone/download the complete source code of this post from GitHub.

--

--