Sunday 3 November 2019

Spring boot: GraphQL: Arguments

In GraphQL, you can pass arguments to fields. Every field in the query can get its own set of arguments.

For example, I can ask for last 2 employees details.
{
    employees (last : 2){
        firstName 
        email
        lastName
      permanentAddress{
        city
      }
    }
}

How to define arguments to a query?
It is just like how you define arguments to a method.

For example, below snippet defines two arguments first, last of type Int to the service employees.
type Query {
    employees(first: Int, last: Int): [Employee]
}

Corresponding method definition looks like below.
@Component
public class QueryResolver implements GraphQLQueryResolver {

  public List<Employee> employees(Integer first, Integer last) {
      ......
      ......
  }

}

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

}

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

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’ file under src/main/resources folder.

employees.graphqls
type Query {
    employees(first: Int, last: 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 'localhost:8080/graphiql' in browser.

Enter below query payload in left side of the window and click on 'Play' button.
{
    employees{
        firstName 
        email
        lastName
      permanentAddress{
        city
      }
  }
}


You will get 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"
        }
      }
    ]
  }
}


Get first 2 employees details


Query Payload
{
    employees(first : 2){
        firstName 
        email
        lastName
      permanentAddress{
        city
      }
  }
}


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"
        }
      }
    ]
  }
}

Get last 2 employees details

Query payload
{
    employees(last : 2){
        firstName 
        email
        lastName
      permanentAddress{
        city
      }
  }
}


Response
{
  "data": {
    "employees": [
      {
        "firstName": "Joel",
        "email": "joel@abc.com",
        "lastName": "Chelli",
        "permanentAddress": {
          "city": "Chennai"
        }
      },
      {
        "firstName": "Gopi",
        "email": "gopi@abc.com",
        "lastName": "Battu",
        "permanentAddress": {
          "city": "Bangalore"
        }
      }
    ]
  }
}

Get the metadata of query

Once you open the uri 'http://localhost:8080/graphiql' in browser, you can see a 'Docs' link on top right corner of the page.


Click on ‘Docs’ link.



Click on ‘Query’ link.


You can see list of queries.

You can download complete working application from this link.



Previous                                                    Next                                                    Home

No comments:

Post a Comment