Spring Boot GraphQL 구현해보기 (feat. API Gateway, MSA)
Skala 과정에서 마이크로 서비스 아키텍처 구조에 대해 새롭게 알게 되었습니다.
배운 것을 실제로 구현해보기 위해 이 여정을 시작하기로 했습니다.
처음 글부터 보러가기
계속해서 MSA 아키텍처를 구현하기 전에 GraphQL에 대해 학습을 진행해보겠습니다
GraphQL?
| 항목 | 설명 |
|---|---|
| 특징 | • 클라이언트가 필요한 데이터만 선택하여 요청 (오버페칭 방지) • 하나의 엔드포인트( /graphql)에서 모든 요청 처리• 계층적 데이터 구조를 JSON 형식으로 반환 |
| 주요 기능 | • Query: 데이터를 조회하는 요청 • Mutation: 데이터를 변경(추가, 수정, 삭제)하는 요청 • Subscription: 실시간 데이터 업데이트를 위한 WebSocket 기반 기능 |
| 장점 | • 클라이언트가 원하는 데이터만 요청 가능 (오버페칭 방지) • 여러 리소스를 한 번의 요청으로 조회 가능 (언더페칭 방지) • API 버전 관리 없이 스키마 수정만으로 확장 가능 |
| 단점 | • HTTP 캐싱이 어렵다 (모든 요청이 POST로 전달됨) • 복잡한 쿼리는 성능 저하 가능성 (N+1 문제 발생 가능) • 보안 이슈 (클라이언트가 자유롭게 요청을 조작 가능하므로, 필드 단위 권한 관리 필요) |
GraphQL 사용 예
라이브러리 추가
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
schema.graphqls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# type으로 Response DTO를 설정할 수 있음
type UserInfoResponse {
id: ID!
username: String!
email: String!
phone: String!
}
# input으로 Request DTO를 설정할 수 있음
input RegisterUserRequest {
username: String!
password: String!
email: String!
phone: String!
}
# GET 요청과 비슷함. Request Body나 Value 없이 데이터만 받아 옴
type Query {
user: [UserInfoResponse] # List 형식으로 받아옴
}
# POST 요청과 비슷함. Request Body나 Value를 넣어서 요청할 때 사용함
type Mutation {
#
registerUser(request: RegisterUserRequest): UserInfoResponse
}
위 코드는 실제로 제 토이 프로젝트에 적용해 본 코드입니다!
생각보다 많이 어렵지 않고, 이렇게 정의만 해두면 호출하고 싶은 변수를 골라서 호출 할 수 있다는 점이 굉장히 매력적인 것 같습니다.
Controller.java 구성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@QueryMapping
public Flux<UserInfoResponse> user() {
log.info("Get all users");
Flux<UserInfoResponse> responses = userServiceClient.getAllUsers();
log.info(responses.toString());
return responses;
}
@MutationMapping
public Mono<UserInfoResponse> registerUser(
@Argument("request") RegisterUserRequest request ) {
log.info("Register user");
Mono<UserInfoResponse> response = userServiceClient.registerUser(request);
log.info(response.toString());
return response;
}
컨트롤러는 다음과 같이 작성됩니다.
물론 GraphQL에서 설정해 둔 DTO로만 소통할 수 있는 것은 아니고, 따로 DTO Class를 작성해주어야 합니다!
DTO 명이 꼭 서로 일치해야 하는 것은 아니지만, 필드명은 꼭!! 같아야합니다!
@Argument 어노테이션으로 Request를 받아야 함을 명시합니다. (REST API 에서의 @RequestBody 등과 비슷함)
저는 WebFlux를 적용하여 비동기 방식으로 호출되는 API 서버를 구축했기 때문에 Mono, Flux 같은 래퍼로 감싸주었는데
동기 방식으로 호출한다면 래퍼를 사용하지 않아도 정상적으로 출력되는 것 같습니다.(ResponseEntity로 감싸주지 않았는데도 정상적으로 값을 받았습니다)
여기서 Mono와 Flux를 처음 사용해봤는데,
Mono는 단건 호출, Flux는 다중건 호출을 할 때 사용합니다.
반환 값
Postman을 이용하여 API를 호출해보았습니다!
url만 입력하면 GraphQL 스키마까지 읽어와주는 기능이 있어서 정말 편리했습니다.
Muation 실행 시
Query 실행 시
위 캡처화면을 보면 알 수 있듯이 입력 항목(Request) 뿐만 아니라 반환 항목(Response)까지 직접 설정해서 보내고 받을 수 있는 것을 알 수 있습니다.
REST API로 맨날 비슷한 API 반환값만 조금씩 다른거 만들다가 GraphQL를 사용해보니…아주…좋습니다……….
마치며
GraphQL 자체의 난이도는 엄청나게 어렵지 않았지만, Spring Cloud Gateway와의 연계성 때문에 가장 많은 시간을 쓴 것 같습니다..
이 부분은 바로 다음 글에서 자세하게 다뤄보겠습니다!
여러분은 시간 낭비 하지 마시고,,열받지 마시고,,,,,즐겁게 코딩하세요,,🥵
참고 자료


