Monday 4 November 2019

Spring boot: GraphQL: Fragments


Fragments are reusable things in GraphQL. You can assume fragments like functions in a programming language.

How to create a fragment?
Below syntax is used to create a fragment.

Syntax
fragment {fragment_name} on {type_name} {
  city
  state
  country
}


Example
fragment permAddressInfo on Address {
  city
  state
  country
}

How to use the fragment in query?
Using ... you can refer the fragment.

Syntax
...fragmentName


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

As you see I used 'permAddressInfo' fragment in employees query.

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.


Use fragments to query employees details

Query Payload
{
  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