GraphQL이란 무엇인가
GraphQL은 클라이언트가 필요한 데이터만 효율적으로 요청하게 해 주지만, 캐싱과 성능 측면에서 고려할 점도 있습니다.
GraphQL은 클라이언트와 서버가 통신하는 여러 방식 중 하나입니다. RESTful API만큼 널리 사용되지는 않지만 뚜렷한 장점 덕분에 다양한 곳에서 활용되고 있습니다.
먼저 GraphQL이 REST API와 어떻게 다른지 살펴보겠습니다. 일반적인 REST API는 GET, POST, PUT, DELETE 메서드를 사용합니다.
# GET 요청 예시(사용자 정보 조회)
GET /api/users/123
# POST 요청 예시(새 사용자 생성)
POST /api/users
{
"name": "John Doe",
"email": "john@example.com"
}
# PUT 요청 예시(사용자 정보 수정)
PUT /api/users/123
{
"name": "Jane Smith",
"email": "jane@example.com"
}
# DELETE 요청 예시(사용자 삭제)
DELETE /api/users/123
반면 GraphQL은 모든 요청에 POST 메서드를 사용합니다.
# 하나의 엔드포인트에서 모든 작업 처리
POST /graphql
{
"query": `
query {
user(id: 123) {
name
email
}
}
`
}
# 사용자 생성 Mutation
POST /graphql
{
"query": `
mutation {
createUser(name: "John Doe", email: "john@example.com") {
id
name
email
}
}
`
}
# 사용자 정보 수정 Mutation
POST /graphql
{
"query": `
mutation {
updateUser(id: 123, name: "Jane Smith", email: "jane@example.com") {
id
name
email
}
}
`
}
# 사용자 삭제 Mutation
POST /graphql
{
"query": `
mutation {
deleteUser(id: 123) {
success
}
}
`
}
GraphQL은 POST 요청의 query 본문에 수행할 작업과 응답으로 받을 값을 함께 담아 전송합니다. 예를 들어 아래 쿼리는 ID가 123인 사용자를 지정하고 그 사용자의 이름과 이메일을 응답으로 요청합니다.
{
"query": `
query {
user(id: 123) {
name
email
}
}
`
}
GraphQL이 해결하려는 문제
1. Over-fetching: 서버에서 너무 많은 데이터 가져오기
사용자의 ID만 필요한데 REST API가 이름, 이메일, 주소까지 모두 반환한다면 클라이언트는 불필요한 데이터까지 받게 됩니다. GraphQL에서는 쿼리에 필요한 ID만 작성해 원하는 데이터만 가져올 수 있습니다.
2. Under-fetching: 서버에서 너무 적은 데이터 가져오기
사용자 테이블의 특정 사용자와 그 사용자가 속한 그룹의 이름을 함께 가져오려면 REST API에서는 보통 두 번 요청해야 합니다. 하나의 API에서 전부 반환하게 만들 수도 있지만, 대규모 프로젝트에서 모든 조합의 REST API를 일일이 작성하는 것은 비효율적입니다. GraphQL을 사용하면 원하는 데이터를 한 번의 요청으로 가져올 수 있습니다.
{
"query": `
query {
user(id: 123) {
id
groups {
name
}
}
}
`
}
실제로 over-fetching과 under-fetching은 함께 발생하는 경우가 많습니다. 사용자 ID만 필요한데 사용자 정보를 전부 받고, 그룹 이름만 필요한데 그룹 정보를 전부 받으면서도 원하는 결과를 얻기 위해 API를 두 번 호출해야 하는 식입니다.
GraphQL 작업 유형
- Query: 데이터를 조회합니다.
- Mutation: 데이터를 생성, 수정, 삭제합니다.
- Subscription: 데이터가 변경될 때 실시간 알림을 받습니다.
채팅 애플리케이션에서 새 메시지가 도착했을 때 실시간으로 알림을 받는 상황이 Subscription의 대표적인 예입니다. REST API에서는 클라이언트가 서버에 주기적으로 데이터를 요청해야 하지만, GraphQL에서는 데이터가 바뀔 때 서버가 클라이언트에 알릴 수 있습니다.
Subscription은 대략 다음과 같이 구현합니다.
- 서버: 스키마에 Subscription 타입을 정의하고 resolver를 구현한 뒤 WebSocket 등으로 클라이언트를 연결합니다.
- 클라이언트: Subscription 쿼리와 WebSocket 연결을 설정하고 서버에서 받은 실시간 업데이트를 처리합니다.
GraphQL의 단점
GraphQL은 클라이언트가 원하는 데이터만 가져올 수 있고 서버가 요구사항마다 별도 API를 만들 필요가 없다는 장점이 있습니다. 하지만 다음과 같은 단점도 있습니다.
- 캐싱이 어렵습니다. 요청마다 형태가 달라지는 복잡한 쿼리로 작성되기 때문입니다.
- 성능 문제가 생길 수 있습니다. 복잡하고 다양한 쿼리를 해석하는 과정이 서버에 부담을 줄 수 있습니다.
GraphQL에 적합한 서비스
- 데이터 모델이 복잡하고 방대한 서비스: over-fetching과 under-fetching이 자주 발생한다면 GraphQL이 유리할 수 있습니다.
- 클라이언트가 데이터 요청을 폭넓게 제어해야 하는 서비스: 여러 형태의 요청이 필요할 때 효율적으로 대응할 수 있습니다.
- 데이터 변경이 잦고 실시간 응답이 필요한 서비스: Subscription으로 실시간 업데이트를 받을 수 있습니다.
주요 기업의 활용 사례
- Facebook: 다양한 기기와 네트워크 환경에서 성능 최적화
- Shopify: 여러 스토어 테마와 앱에 맞춘 데이터 제공
- GitHub: 저장소, 이슈, Pull Request 등 복잡한 데이터 구조를 유연하게 조회