Tuesday 5 November 2019

Spring boot: GraphQL: Operation or query Name


In GraphQL, we can provide meaningful name to the queries that we are going to execute (Operation name is similar to the function name in programming language).

Example
query employeeDetails {
  employees {
    firstName
    lastName
    permanentAddress {
      ...permAddressInfo
    }
    temporaryAddress {
      ...permAddressInfo
    }
  }
}

fragment permAddressInfo on Address {
  city
  state
  country
}

I give operation name as ‘employeeDetails’.

Find the below working application.


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();
    }

}


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();
    }

}


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;
        }

    }

}


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, Long> {

}


EmployeeController.java
package com.sample.app.controller;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
@RequestMapping("api/v1/employees")
public class EmployeeController {
    @Autowired
    public EmployeeRepository empRepo;

    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity<List<Employee>> allEmployees() {
        List<Employee> emps = new ArrayList<> ();
        Iterable<Employee> empsIterable = empRepo.findAll();
        
        for(Employee emp: empsIterable) {
            emps.add(emp);
        }
        return ResponseEntity.ok(emps);
    }

}


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(Integer first, Integer last) {
        List<Employee> emps = new ArrayList<>();
        Iterable<Employee> empsIterable = empRepo.findAll();

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

        if (first != null)
            return emps.subList(0, first);

        if (last != null)
            return emps.subList(emps.size() - last, emps.size());

        return emps;
    }

    public Employee employee(Long id) {
        return empRepo.findById(id).get();
    }
}


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));

        };
    }

}

Create ‘application.properties’ 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’ under src/main/resources folder.


employees.graphqls
type Query {
    employees(first: Int, last: Int): [Employee]
    employee(id: Int!) : 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
}


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>


Total project structure looks like below.

Run App.java.

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

Execute a query by providing query name

Query Payload
query employeeDetails {
  employees {
    firstName
    lastName
    permanentAddress {
      ...permAddressInfo
    }
    temporaryAddress {
      ...permAddressInfo
    }
  }
}

fragment permAddressInfo on Address {
  city
  state
  country
}

Click on Execute or Play button, you will get below response.

{
  "data": {
    "employees": [
      {
        "firstName": "ram",
        "lastName": "Gurram",
        "permanentAddress": {
          "city": "Bangalore",
          "state": "Karnataka",
          "country": "India"
        },
        "temporaryAddress": {
          "city": "Hyderabad",
          "state": "Telangana",
          "country": "India"
        }
      },
      {
        "firstName": "Joel",
        "lastName": "Chelli",
        "permanentAddress": {
          "city": "Chennai",
          "state": "Tamilnadu",
          "country": "India"
        },
        "temporaryAddress": {
          "city": "Hyderabad",
          "state": "Telangana",
          "country": "India"
        }
      },
      {
        "firstName": "Gopi",
        "lastName": "Battu",
        "permanentAddress": {
          "city": "Bangalore",
          "state": "Karnataka",
          "country": "India"
        },
        "temporaryAddress": {
          "city": "Chennai",
          "state": "Tamilnadu",
          "country": "India"
        }
      }
    ]
  }
}

You can download complete working application from this link.
    

Previous                                                    Next                                                    Home

No comments:

Post a Comment