티스토리 뷰

SpringBoot 에서 JPA 와 GraphQL 을 연동하는 방법에 대해 간략히 소개하겠습니다. 해당 포스팅에선 PostgeSQL 을 사용하였습니다.

 

1. 의존성 추가

// GraphQL
implementation 'org.springframework.boot:spring-boot-starter-graphql'
implementation 'com.graphql-java-kickstart:graphql-spring-boot-starter:15.1.0'

// PostgreSQL
runtimeOnly 'org.postgresql:postgresql'

// JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  • GraphQL, PostgreSQL, JPA 의존성을 추가합니다.

 

2. App설정(application.yml)

spring:
  graphql:
    path: /api/query
  schema:
    locations: classpath:graphql/

graphql:
  playground:
    enabled: true
    endpoint: /api/query

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/mydb
    username: myuser
    password: 1234
    driver-class-name: org.postgresql.Driver

  jpa:
    hibernate:
      ddl-auto: none
    show-sql: true
  • GraphQL : 엔드포인트 '/api/query' 로 지정하고 schema 파일은 resources/graphql/*.graphqls 형태로 관리합니다. playground 를 활성해 웹으로 테스트 및 스키마를 확인할 수 있습니다.
  • PostgreSQL : 접속 정보를 작성합니다.
  • JPA : Hibernate 가 스키마를 관리하지 않도록하고, SQL 쿼리를 콘솔에 출력합니다.

 

3. User 도메인 작성

#User.java
@Entity
@Getter
@Setter
@Table(name = "users")
public class User {
  @Id
  private String userId;

  @Column(nullable = false)
  private String userName;
  private String email;

  @Column(nullable = false)
  private String password;
  private LocalDateTime createdAt = LocalDateTime.now();
  private LocalDateTime updatedAt = LocalDateTime.now();

  @ManyToOne
  @JoinColumn(name = "team_id", referencedColumnName = "teamId", insertable = false, updatable = false)
  private Team team;

  @Column(name = "team_id")
  private String teamId; // 단순 컬럼 매핑용 필드
}

#UserRepository.java
public interface UserRepository extends JpaRepository<User, String> {
  List<User> findAll(Sort sort);
}
  • users 테이블과 맵핑하고, team_id 로 teams 테이블과 조인합니다.
  • save 시, team_id 도 맵핑하기 위해 insert/update 를 false 로 작성하고, 단순 컬럼 매핑용 필드도 생성합니다.

 

4. Team 도메인 작성

#Team.java
@Entity
@Getter
@Setter
@Table(name = "teams")
public class Team {
  @Id
  private String teamId;

  @Column(nullable = false, unique = true)
  private String teamName;
  private String description;
  private LocalDateTime createdAt = LocalDateTime.now();
  private LocalDateTime updatedAt = LocalDateTime.now();

  @OneToMany(mappedBy = "team")
  private List<User> users;
}

#TeamRepository.java
public interface TeamRepository extends JpaRepository<Team, String> {
}
  • users 테이블과 조인하여 팀에 속한 사용자를 조회합니다.

 

5. 컨트롤러 작성

TeamController.java
@Controller
@RequiredArgsConstructor
public class TeamController {

  private final TeamService _teamService;

  /**
   * 팀 전체 조회
   */
  @QueryMapping
  public List<Team> getAllTeams() {
    return _teamService.getAllTeams();
  }

  /**
   * 팀 등록
   */
  @MutationMapping
  public Team createTeam(@Argument TeamRequest teamRequest) {
    return _teamService.createTeam(teamRequest);
  }

}
UserController.java
@Controller
@RequiredArgsConstructor
public class UserController {

  private final UserService _userService;

  /**
   * 전체 사용자 조회
   */
  @QueryMapping
  public List<User> getAllUsers(@Argument SortRequest sortRequest) {
    return _userService.getAllUsers(sortRequest);
  }

  /**
   * 사용자 조회 By Id
   */
  @QueryMapping
  public User getUserById(@Argument String id) {
    return _userService.getUserById(id);
  }

  /**
   * 사용자 추가
   */
  @MutationMapping
  public User createUser(@Argument UserRequest userRequest) {
    return _userService.createUser(userRequest);
  }

  /**
   * 사용자 삭제
   */
  @MutationMapping
  public DeleteResponse deleteUser(@Argument String id) {
    return _userService.deleteUser(id);
  }

  /**
   * 사용자 수정
   */
  @MutationMapping
  public User updateUser(@Argument UserRequest userRequest) {
    return _userService.updateUser(userRequest);
  }

}
  • GraphQL 은 @Controller 를 사용하고, 조회엔 @QueryMapping, 등록/수정/삭제엔 @MutationMapping 을 사용합니다.

 

6. 스키마 작성

/resources/
  └─graphql
    └─mutations.graphqls
    └─queries.graphqls
    └─request.graphqls
    └─response.graphqls

 

* requet.graphqls

input SortRequest {
  sortBy: String
  order: String
}

input UserRequest {
  userId: String
  userName: String
  email: String
  password: String
  teamId: String
}

input TeamRequest {
  teamId: String
  teamName: String
  description: String
}
  • 클라이언트로부터 입력받는 파라미터 스키마를 정의합니다.

 

* response.graphqls

# User 타입
type UserResponse {
  userId: ID!
  userName: String!
  email: String!
  password: String!
  team: TeamResponse!
}

# Team 타입
type TeamResponse {
  teamId: ID!
  teamName: String!
  description: String
  users: [UserResponse!]!
}

# DeleteResponse.java
type DeleteResponse {
  successYn: String
  message: String
}
  • 반환받을 스키마를 지정합니다.

 

*queries.graphqls

type Query {
  # 사용자 전체조회
  getAllUsers(sortRequest: SortRequest): [UserResponse!]!

  # ID로 사용자 조회
  getUserById(id: ID!): UserResponse

  # 팀 전체조회
  getAllTeams: [TeamResponse!]!
}
  • 조회 메서드의 파라미터와 리턴타입을 맵핑합니다.

 

*Mutations.graphqls

type Mutation {
  # 사용자 등록
  createUser(userRequest: UserRequest): UserResponse

  # 사용자 삭제
  deleteUser(id: ID!): DeleteResponse

  # 사용자 수정
  updateUser(userRequest: UserRequest): UserResponse

  # 팀 등록
  createTeam(teamRequest: TeamRequest): TeamResponse
}
  • 등록/수정/삭제 메서드의 파라미터와 리턴타입을 맵핑합니다.

 

7. 테스트(playground)

SpringBoot 서버를 실행후 /playground 로 접근합니다.

  • playground 로 테스트를 진행합니다.
#getAllUsers
{
  query { getAllUsers(sortRequest: {sortBy: "userName", order: "DESC"}) { userId userName email } }
}

#getAllTeams
{
  query { getAllTeams { teamId teamName description users { userId userName } } }
}

#getUserById
{
  query { getUserById(id: "USER001") { userId userName email team{ teamName }} }
}

#getUserById & getAllUsers
{
  query { getUserById(id: "USER001") {  userId   userName  email  team {  teamName  }  } getAllUsers(sortRequest: {sortBy: "userName", order: "DESC"}) {  userId  userName  email  } }
}

#createUser
{
  mutation { createUser(userRequest: { userId: "USER007", userName: "자유저", email: "user-007@test.co.kr", password: "7777", teamId: "TEAM004"  }) { userId } }
}

#updateUser
{
  mutation { updateUser(userRequest: { userId: "USER008", userName: "유저7", password: "7777", teamId: "TEAM003"  }) { userId userName email } }
}

#deleteUser
{
  mutation { deleteUser(id: "USER006") {successYn message} }
}
  • GraphQL 를 이용해 조회/등록/수정/삭제 테스트를 할 수 있습니다.

감사합니다.

최근에 올라온 글
Total
Today
Yesterday