스프링 부트를 사용한 GraphQL

GraphQL이란 무엇입니까?
기존 REST API는 서버가 관리하는 리소스 개념으로 작동합니다. 이러한 리소스는 다양한 HTTP 동사에 따라 몇 가지 표준 방식으로 조작될 수 있습니다. 이것은 API가 리소스 개념에 맞는 한 잘 작동하지만, 이를 벗어나야 할 때 빠르게 무너집니다.

클라이언트가 동시에 여러 리소스의 데이터를 필요로 하는 경우에도 이 문제가 발생합니다. 예를 들어 블로그 게시물과 댓글을 요청합니다. 일반적으로 이 문제는 클라이언트가 여러 요청을 하도록 하거나 서버가 항상 필요하지 않을 수 있는 추가 데이터를 제공하도록 하여 응답 크기가 더 커지도록 함으로써 해결됩니다.

GraphQL은 이 두 가지 문제에 대한 솔루션을 제공합니다. 이를 통해 클라이언트는 단일 요청에서 하위 리소스 탐색을 포함하여 원하는 데이터를 정확하게 지정할 수 있으며 단일 요청에서 여러 쿼리를 허용합니다.

여기서는 GraphQL을 Spring 부트와 통합하는 방법에 대해 논의할 것입니다.

나는 이것을 달성하기 위해 아래를 사용할 것입니다 :
  • 스프링 부트 라이브러리
  • GraphQL 라이브러리
  • 봄 JPA
  • 최대 절전 모드
  • 롬복
  • 포스트그레스

  • GraphiQL이란 무엇입니까?
    GraphQL에는 GraphiQL이라는 동반 도구도 있습니다. 이것은 모든 GraphQL 서버와 통신하고 이에 대한 쿼리 및 변형을 실행할 수 있는 UI입니다.

    데이터베이스가 연결된 GraphQL 서버
    이 아키텍처에는 통합 데이터베이스가 있는 GraphQL 서버가 있으며 종종 새 프로젝트에서 사용할 수 있습니다. 쿼리를 받으면 서버는 요청 페이로드를 읽고 데이터베이스에서 데이터를 가져옵니다. 이를 쿼리 해결이라고 합니다. 클라이언트에 반환되는 응답은 공식 GraphQL 사양에 지정된 형식을 따릅니다.



    위의 다이어그램에서 GraphQL 서버와 데이터베이스는 단일 노드에 통합되어 있습니다. 클라이언트(데스크톱/모바일)는 HTTP를 통해 GraphQL 서버와 통신합니다. 서버는 요청을 처리하고 데이터베이스에서 데이터를 가져와 클라이언트에 반환합니다.

    다음은 종속성의 전체 목록입니다. 저는 GraphQL 및 Spring Boot로 작업하는 데 사용했습니다.

    implementation group: 'io.leangen.graphql', name: 'graphql-spqr-spring-boot-starter', version: '0.0.6'
    implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.20'
    implementation 'org.apache.commons:commons-collections4:4.4'
    implementation 'org.jdal:jdal-core:2.0.0'
    implementation group: 'com.graphql-java', name: 'graphql-java-extended-scalars', version: '2021-06-29T01-19-32-8e19827'
    implementation group: 'org.hibernate', name: 'hibernate-core', version: '5.5.2.Final'
        implementation group: 'commons-net', name: 'commons-net', version: '3.8.0'
        implementation group: 'com.graphql-java-kickstart', name: 'graphiql-spring-boot-starter', version: '7.1.0'
        compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.20'
        implementation group: 'org.apache.commons', name: 'commons-collections4', version: '4.4'
        implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.12.3'
        implementation group: 'com.graphql-java-kickstart', name: 'graphql-spring-boot-starter', version: '7.0.1'
        implementation group: 'org.springframework', name: 'spring-web', version: '5.3.6'
        implementation group: 'com.graphql-java-kickstart', name: 'graphql-spring-boot-starter-test', version: '7.0.1'
        implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.5.0'
        implementation group: 'commons-io', name: 'commons-io', version: '2.10.0'
        compileOnly group: 'org.hibernate.orm', name: 'hibernate-jpamodelgen', version: '6.0.0.Alpha6'
        implementation group: 'org.modelmapper', name: 'modelmapper', version: '2.4.4'
        implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.20'
        implementation group: 'com.graphql-java-kickstart', name: 'playground-spring-boot-starter', version: '5.10.0'
        implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
        compileOnly 'org.hibernate:hibernate-jpamodelgen'
        annotationProcessor('org.hibernate:hibernate-jpamodelgen')
        implementation 'org.springframework.boot:spring-boot-starter'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
        compileOnly 'org.projectlombok:lombok'
        annotationProcessor 'org.projectlombok:lombok'
    


    내 샘플 프로젝트 구조



    내 엔티티 클래스

  • 직원.자바

  • package com.example.demo.entities;
    
    import io.leangen.graphql.annotations.GraphQLNonNull;
    import io.leangen.graphql.annotations.types.GraphQLType;
    import lombok.Data;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.OneToOne;
    import javax.persistence.Table;
    import java.math.BigInteger;
    import java.time.LocalDate;
    
    @Entity
    @Data
    @GraphQLType
    @Table(name = "employee")
    public class Employee {
    
        @Id
        @Column(name = "emp_id")
        private BigInteger employeeId;
        @Column(name = "ename")
        @GraphQLNonNull
        private String employeeName;
        @Column(name = "email_id")
        private String email;
        @Column(name = "city")
        private String city;
        @Column(name = "country")
        private String country;
        @Column(name = "dept_id")
        private Integer deptId;
        @Column(name = "dob")
        private LocalDate dob;
    
        @OneToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "dept_id", insertable = false, updatable = false)
        private Department department;
    }
    


    2. Department.java

    package com.example.demo.entities;
    
    import io.leangen.graphql.annotations.GraphQLQuery;
    import io.leangen.graphql.annotations.types.GraphQLType;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.Id;
    import javax.persistence.OneToMany;
    import javax.persistence.Table;
    import java.util.List;
    
    @Entity
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @GraphQLType(description = "This is Department")
    @Table(name = "department")
    public class Department {
    
        @Id
        @Column(name = "dept_id")
        @GraphQLQuery(description = "This is deptID")
        private Integer deptId;
        @Column(name = "dname")
        private String deptName;
    
        @OneToMany(fetch = FetchType.LAZY, mappedBy = "department")
        private List<Employee> employee;
    }
    


    내 저장소 **
    **1. DepartmentDao.java

    package com.example.demo.dao;
    
    import com.example.demo.entities.Department;
    import org.springframework.data.repository.CrudRepository;
    import org.springframework.stereotype.Repository;
    
    import java.util.List;
    
    @Repository
    public interface DepartmentDao extends CrudRepository<Department, Integer> {
    
        public Department findByDeptName(String deptName);
    }
    


    2.직원다오.자바

    package com.example.demo.dao;
    
    import com.example.demo.entities.Employee;
    import org.springframework.data.repository.CrudRepository;
    import org.springframework.stereotype.Repository;
    
    import java.math.BigInteger;
    import java.util.List;
    
    @Repository
    public interface EmployeeDao extends CrudRepository<Employee, BigInteger> {
        public List<Employee> findByEmployeeName(String ename);
    }
    


    내 서비스 수업
    1.직원 서비스.자바

    package com.example.demo.service;
    
    import com.example.demo.dao.EmployeeDao;
    import com.example.demo.entities.Employee;
    import com.example.demo.entities.EmployeeDto;
    import com.example.demo.exception.ResourceNotFoundException;
    import org.apache.commons.collections4.IteratorUtils;
    import org.apache.commons.lang.RandomStringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.math.BigInteger;
    import java.util.List;
    
    @Service
    public class EmployeeService {
    
        @Autowired
        private EmployeeDao employeeDao;
    
    
        public List<Employee> getAllEmployee() {
            return IteratorUtils.toList(employeeDao.findAll().iterator());
        }
    
        public Employee getEmployeeByID(BigInteger eid) {
            return employeeDao.findById(eid).orElseGet(() -> {
                throw new ResourceNotFoundException("No Employee found");
            });
        }
    
        public List<Employee> getEmployeeByName(String ename) {
            return employeeDao.findByEmployeeName(ename);
        }
    
    }
    


    2. DepartmentService.java

    package com.example.demo.service;
    
    import com.example.demo.dao.DepartmentDao;
    import com.example.demo.entities.Department;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class DepartmentService {
    
        @Autowired
        private DepartmentDao departmentDao;
    
        public Department getDeptByName(String deptName) {
            return departmentDao.findByDeptName(deptName);
        }
    }
    


    내 쿼리 클래스
    1.직원 쿼리.자바

    package com.example.demo.queries;
    
    import com.example.demo.entities.Employee;
    import com.example.demo.service.EmployeeService;
    import io.leangen.graphql.annotations.GraphQLArgument;
    import io.leangen.graphql.annotations.GraphQLQuery;
    import io.leangen.graphql.spqr.spring.annotations.GraphQLApi;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.math.BigInteger;
    import java.util.List;
    
    @Component
    @GraphQLApi
    public class EmployeeQuery {
    
        @Autowired
        private EmployeeService employeeService;
    
        @GraphQLQuery(description = "This query is used to fetch all Employee ")
        public List<Employee> searchAllEmployee() {
            return employeeService.getAllEmployee();
        }
    
        @GraphQLQuery(description = "This query is used to fetch Employee by employeeId")
        public Employee searchEmployeeById(@GraphQLArgument(name = "employeeId") BigInteger eid) {
            return employeeService.getEmployeeByID(eid);
        }
    
        @GraphQLQuery(description = "This query is used to fetch employeeId by employeeName")
        public List<Employee> searchEmployeeByName(@GraphQLArgument(name = "employeeName") String eName) {
            return employeeService.getEmployeeByName(eName);
        }
    }
    


    2.부서쿼리.자바

    package com.example.demo.queries;
    
    import com.example.demo.entities.Department;
    import com.example.demo.service.DepartmentService;
    import io.leangen.graphql.annotations.GraphQLArgument;
    import io.leangen.graphql.annotations.GraphQLQuery;
    import io.leangen.graphql.spqr.spring.annotations.GraphQLApi;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    @GraphQLApi
    public class DepartmentQuery {
    
        @Autowired
        private DepartmentService departmentService;
    
        @GraphQLQuery(description = "This query is used to fetch department by department name")
        public Department searchDeptByName(@GraphQLArgument(name = "deptName") String deptName) {
            return departmentService.getDeptByName(deptName);
        }
    }
    


    *이제 서버를 시작한 후 graphql 스키마 문서를 볼 수 있습니다. *

    URL: http://localhost:8080/graphiql







    적은 수의 쿼리 실행





    여기에서는 Spring 부트를 graphQL과 통합하는 모든 단계를 공유했습니다. 다음 포스트에서 다른 주제로 찾아오겠습니다.

    고맙습니다..
    아르판

    연결하자:
    링크드인 :

    좋은 웹페이지 즐겨찾기