Wednesday, 30 October 2019

Spring Boot: GraphQL: Hello World Application


In this post, I am going to explain how to setup a spring boot GraphQL project and experiment with it.

Step 1: Create new maven project ‘springbootGraphQL’.

Step 2: Update pom.xml with graphql and springboot dependencies.

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>springbootGraphQL</groupId>
   <artifactId>springbootGraphQL</artifactId>
   <version>1</version>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.6.RELEASE</version>
   </parent>

   <name>springbootApp</name>
   <url>http://maven.apache.org</url>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>

   <dependencies>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>


      <dependency>
         <groupId>com.h2database</groupId>
         <artifactId>h2</artifactId>
      </dependency>

      <dependency>
         <groupId>com.graphql-java</groupId>
         <artifactId>graphiql-spring-boot-starter</artifactId>
         <version>5.0.2</version>
      </dependency>

      <dependency>
         <groupId>com.graphql-java</groupId>
         <artifactId>graphql-java-tools</artifactId>
         <version>5.2.4</version>
      </dependency>

      <dependency>
         <groupId>com.graphql-java</groupId>
         <artifactId>graphql-spring-boot-starter</artifactId>
         <version>5.0.2</version>
      </dependency>


   </dependencies>
</project>

I am using H2 in memory database to store the data.

Step 3: Create entity classes (Employee, Address, Department).


Department.java
package com.sample.app.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "department")
public class Department {
   @Id
   @GeneratedValue
   private long id;
   private String departmentName;

   public Department() {
      this("none");
   }

   public Department(String departmentName) {
      super();
      this.departmentName = departmentName;
   }

   public long getId() {
      return id;
   }

   public void setId(long id) {
      this.id = id;
   }

   public String getDepartmentName() {
      return departmentName;
   }

   public void setDepartmentName(String departmentName) {
      this.departmentName = departmentName;
   }

   @Override
   public String toString() {
      StringBuilder builder = new StringBuilder();
      builder.append("Department [id=").append(id).append(", departmentName=").append(departmentName).append("]");
      return builder.toString();
   }

}


Address.java
package com.sample.app.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "address")
public class Address {
   @Id
   @GeneratedValue
   private long id;

   private String city;
   private String state;
   private String country;

   public Address() {
      this("none", "none", "none");
   }

   public Address(String city, String state, String country) {
      super();
      this.city = city;
      this.state = state;
      this.country = country;
   }

   public long getId() {
      return id;
   }

   public void setId(long id) {
      this.id = id;
   }

   public String getCity() {
      return city;
   }

   public void setCity(String city) {
      this.city = city;
   }

   public String getState() {
      return state;
   }

   public void setState(String state) {
      this.state = state;
   }

   public String getCountry() {
      return country;
   }

   public void setCountry(String country) {
      this.country = country;
   }

   @Override
   public String toString() {
      StringBuilder builder = new StringBuilder();
      builder.append("Address [id=").append(id).append(", city=").append(city).append(", state=").append(state)
            .append(", country=").append(country).append("]");
      return builder.toString();
   }

}


Employee.java
package com.sample.app.entity;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name = "employees")
public class Employee {
   @Id
   @GeneratedValue
   private long id;
   private String firstName;
   private String lastName;
   private String email;

   @OneToOne(cascade = CascadeType.ALL)
   private Address permanentAddress;

   @OneToOne(cascade = CascadeType.ALL)
   private Address temporaryAddress;

   @OneToOne(cascade = CascadeType.ALL)
   private Department department;

   public long getId() {
      return id;
   }

   public void setId(long id) {
      this.id = id;
   }

   public String getFirstName() {
      return firstName;
   }

   public void setFirstName(String firstName) {
      this.firstName = firstName;
   }

   public String getLastName() {
      return lastName;
   }

   public void setLastName(String lastName) {
      this.lastName = lastName;
   }

   public String getEmail() {
      return email;
   }

   public void setEmail(String email) {
      this.email = email;
   }

   public Address getPermanentAddress() {
      return permanentAddress;
   }

   public void setPermanentAddress(Address permanentAddress) {
      this.permanentAddress = permanentAddress;
   }

   public Address getTemporaryAddress() {
      return temporaryAddress;
   }

   public void setTemporaryAddress(Address temporaryAddress) {
      this.temporaryAddress = temporaryAddress;
   }

   public Department getDepartment() {
      return department;
   }

   public void setDepartment(Department department) {
      this.department = department;
   }

   @Override
   public String toString() {
      StringBuilder builder = new StringBuilder();
      builder.append("Employee [id=").append(id).append(", firstName=").append(firstName).append(", lastName=")
            .append(lastName).append(", email=").append(email).append(", permanentAddress=")
            .append(permanentAddress).append(", temporaryAddress=").append(temporaryAddress).append(", department=")
            .append(department).append("]");
      return builder.toString();
   }

   public static EmployeeBuilder builder() {
      return new EmployeeBuilder();
   }

   public static class EmployeeBuilder {

      Employee emp;

      public EmployeeBuilder() {
         emp = new Employee();
         emp.setPermanentAddress(new Address());
         emp.setTemporaryAddress(new Address());
         emp.setDepartment(new Department());
      }

      public Employee build() {
         return emp;
      }

      public EmployeeBuilder firstName(String firstName) {
         emp.setFirstName(firstName);
         return this;
      }

      public EmployeeBuilder lastName(String lastName) {
         emp.setLastName(lastName);
         return this;
      }

      public EmployeeBuilder email(String email) {
         emp.setEmail(email);
         return this;
      }

      public EmployeeBuilder permanentAddress(Address permanentAddress) {
         emp.setPermanentAddress(permanentAddress);
         return this;
      }

      public EmployeeBuilder temporaryAddress(Address temporaryAddress) {
         emp.setTemporaryAddress(temporaryAddress);
         return this;
      }

      public EmployeeBuilder department(Department department) {
         emp.setDepartment(department);
         return this;
      }

   }

}

Step 4: Create EmployeeRepository interface.

EmployeeRepository.java
package com.sample.app.repository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.sample.app.entity.Employee;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {

}

Step 5: Create QueryResolver class which implements GraphQLQueryResolver interface.

QueryResolver.java
package com.sample.app.resolvers;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import com.sample.app.entity.Employee;
import com.sample.app.repository.EmployeeRepository;

@Component
public class QueryResolver implements GraphQLQueryResolver {
   @Autowired
   public EmployeeRepository empRepo;

   public List<Employee> employees() {
      List<Employee> emps = new ArrayList<>();
      Iterable<Employee> empsIterable = empRepo.findAll();

      for (Employee emp : empsIterable) {
         emps.add(emp);
      }
      return emps;
   }
}

Step 6: Create main application class.


App.java
package com.sample.app;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import com.sample.app.entity.Address;
import com.sample.app.entity.Department;
import com.sample.app.entity.Employee;
import com.sample.app.repository.EmployeeRepository;

@SpringBootApplication
public class App {

   @Autowired
   public EmployeeRepository empRepo;

   public static void main(String[] args) {

      SpringApplication.run(App.class, args);
   }

   @Bean
   public CommandLineRunner demo() {
      return (args) -> {

         Employee emp1 = Employee.builder().firstName("ram").lastName("Gurram").email("krishna@abc.com")
               .permanentAddress(new Address("Bangalore", "Karnataka", "India"))
               .temporaryAddress(new Address("Hyderabad", "Telangana", "India"))
               .department(new Department("Infrastructure Services")).build();

         Employee emp2 = Employee.builder().firstName("Joel").lastName("Chelli").email("joel@abc.com")
               .permanentAddress(new Address("Chennai", "Tamilnadu", "India"))
               .temporaryAddress(new Address("Hyderabad", "Telangana", "India"))
               .department(new Department("Core Systems")).build();

         Employee emp3 = Employee.builder().firstName("Gopi").lastName("Battu").email("gopi@abc.com")
               .permanentAddress(new Address("Bangalore", "Karnataka", "India"))
               .temporaryAddress(new Address("Chennai", "Tamilnadu", "India"))
               .department(new Department("Infrastructure Services")).build();

         empRepo.saveAll(Arrays.asList(emp1, emp2, emp3));

      };
   }

}

Configurations
Create application.propeties file under src/main/resources folder


application.properties
logging.level.root=WARN
logging.level.org.hibernate=ERROR

## H2 specific properties
spring.h2.console.enabled=true
spring.h2.console.path=/h2

spring.datasource.url=jdbc:h2:file:~/db/myOrg.db;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;

spring.datasource.username=krishna
spring.datasource.password=password123

spring.datasource.driverClassName=org.h2.Driver

## JPA specific properties
# Creates the schema, destroying previous data.
spring.jpa.hibernate.ddl-auto=create

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

## Database connection pooling properties
# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.max-wait=10000

# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=10
spring.datasource.tomcat.max-idle=5
spring.datasource.tomcat.min-idle=3

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

# Used to trace the transaction behavior
logging.level.org.springframework.transaction.interceptor=TRACE

Create ‘employees.graphqls’ file that define the definition of types and queries.


employees.graphqls
type Query {
    employees: [Employee]
}

type Employee {
    id: Int
    firstName: String
    lastName: String
    email: String
    permanentAddress: Address
    temporaryAddress: Address
    department: Department
}

type Address {
   id: Int
   city: String
   state: String
   country: String
}

type Department{
   id: Int
   departmentName: String
}


Total project structure looks like below.

Run App.java.


Open the url ‘http://localhost:8080/graphiql’ in browser, you can see below kind of screen.


On left side of window add below graphQL payload.
{
    employees {
        firstName
        email
    }
}

Click on Play button.


You can see below response.
{
  "data": {
    "employees": [
      {
        "firstName": "ram",
        "email": "krishna@abc.com"
      },
      {
        "firstName": "Joel",
        "email": "joel@abc.com"
      },
      {
        "firstName": "Gopi",
        "email": "gopi@abc.com"
      }
    ]
  }
}



If you want lastName, and city field of permanentAddress too, you can construct query like below.
{
    employees {
        firstName
        email
        lastName
      permanentAddress{
        city
      }
    }
}


You will receive below response.
{
  "data": {
    "employees": [
      {
        "firstName": "ram",
        "email": "krishna@abc.com",
        "lastName": "Gurram",
        "permanentAddress": {
          "city": "Bangalore"
        }
      },
      {
        "firstName": "Joel",
        "email": "joel@abc.com",
        "lastName": "Chelli",
        "permanentAddress": {
          "city": "Chennai"
        }
      },
      {
        "firstName": "Gopi",
        "email": "gopi@abc.com",
        "lastName": "Battu",
        "permanentAddress": {
          "city": "Bangalore"
        }
      }
    ]
  }
}

You can download complete working application from this link.


Previous                                                    Next                                                    Home

No comments:

Post a Comment