
현대에 있어서 모바일 애플리케이션 환경이 점점 더 복잡해졌습니다. 때문에 기존의 REST 방식은 필요한 데이터만 가져오기 위해 엔드포인트를 제작하거나, 여러 번 반복했어야 했고, 또한 불필요한 데이터가 오는 오버페칭(Overfetching)도 불가피했습니다.데이터 요금이 제한적이거나 비싼 모바일 사용자에게 지연과 비효율 문제가 발생했습니다. 이에 페이스북 개발팀은 모바일 앱을 확장하는 과정에서 기존
REST API와FQL(Facebook Query Language)의 한계를 문제를 해결하기 위해 GraphQL을 개발했습니다.
GraphQL은 클라이언트가 애플리케이션 프로그래밍 인터페이스(API)와 상호 작용하는 방식을 지정하는 오픈 소스 쿼리 및 조작 언어입니다.
GraphQL의 특징은 다음과 같습니다.
GraphQL의 이러한 특성 덕분에 클라이언트가 필요한 데이터의 구조를 정의하고, 반환하여 웹 및 모바일 애플리케이션 환경에서 REST API를 대체하는 강력한 도구로 자리잡게 되었습니다.
🔗에 따르면 아직 REST가 주류를 이루고 있음을 보여줍니다. 하지만 Gratner의 보고서에 따르면 2025년까지 기업의 50% 이상이 GraphQL을 프로덕션에 사용할 것으로 예측했습니다.

이 글에서는 GraphQL과 REST를 살펴보며 GraphQL에 대해 알아보겠습니다.
API를 위한 쿼리 언어인 GraphQL은 같은 쿼리 언어인 SQL과 비교해보면 서로 목적 자체가 다릅니다.
즉, REST에서는 반환되는 응답(response) 데이터가 정해져 있어 컬럼의 수정과 DTO를 추가 생성하거나 수정해야한다.
하지만, GraphQL은 쿼리로 요청하기 때문에 원하는 데이터를 뽑아와 커스터마이징할 수 있습니다.
아래 REST와의 차이점을 보며 자세히 알아보겠습니다.
응답 형식은 동일하지만, REST와 GraphQL은 모두 JSON 형식의 응답을 반환하지만, GraphQL은 데이터 간소화 및 통합에 중점을 둡니다.
GET 요청의 경우 자체적으로 캐싱이 가능합니다. GraphQL은 특정 애플리케이션 아키텍쳐나 데이터베이스에 종속되지 않으며, 다양한 환경(IDE)에 배포할 수 있습니다. 기존 API 관리 도구와 함께 사용하거나 REST API 위에서도 구현할 수 있습니다.
[GraphQL Query]
↓ (1. GraphQL 쿼리 서버로 전송)
[Query Language Processor]
┌─ Parse
└─ Validate
↓ (2. 파싱 및 유효성 검사)
[GraphQL Resolver]
- RDB
↓ (3. 리졸버가 필요한 데이터를 가져옴)
[Output (JSON)] (4. JSON 클라이언트에 반환)
데이터 모델의 객체 필드를 정의합니다. 예시로, 사용자 객체는 이름과 이메일 같은 필드를 가집니다.
!는 non-null 타입을 나타냅니다. 해당 값을 가져야 하며, null이 될 수 없습니다.
# 객체 타입 정의
type User {
id: ID! # 필드
name : String!
email: String!
}
GraphQL 서버가 검색할 수 있는 데이터 타입을 정의합니다. 일반적으로 객체 타입에 속하며, 스칼라 타입(문자열,정수, 부동 소수점, 불리언, ID 등)으로도 정의됩니다.
API 개발자가 만든 스키마는 클라이언트가 요청할 수 있는 객체와 해당 객체의 필드를 정의합니다. GraphQL은 스키마 정의 언어(SDL)로 모든 데이터 타입을 기록하는 강력한 타입 시스템을 사용합니다.
# 스키마 정의
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
GraphQL API에서 데이터를 검색(조회)하는 데 사용됩니다. 쿼리는 스키마에 따라 유효성을 검사한 후 실행됩니다.
# 쿼리 정의
type Query {
user(id: ID!) : User
allUsers: [User!]!
}
# 사용
query {
# user 123의 데이터 가져오기
user(id: "123") {
id
name
email
}
}
서버의 데이터를 생성, 업데이트, 삭제하는 GraphQL 작업입니다. RESTful API의 POST, PUT, PATCH, DELETE 작업과 유사합니다.
# 뮤테이션 정의
type Mutation {
createUser(name: String!, email: String!) : User!
updateUser(id: ID!, name: String, email: String) : User
}
# 뮤테이션 사용
mutation {
createUser(name: "Alice", email: "alice@example.com") {
id
name
email
}
updateUser(id: "123", name: "Alice Updated", email: "alice@example.com") {
id
name
email
}
}
스칼라 타입은 기본적인 데이터 타입을 나타냅니다. 스칼라 타입은 더 이상 세분화되지 않는 단일 값을 표현합니다. 다음은 스칼라의 종류입니다.👇
문자열자바에선 필요한 의존성을 프로젝트에 추가하여 사용가능합니다.
# Scalar 정의
scalar Date
# 스칼라 타입을 사용하는 객체
type Event{
id: ID!
title: String!
date: Date!
}
GraphQL 서버로부터 실시간 데이터 업데이트를 받는 데 사용됩니다.
# 구독 정의
type Subscription {
userAdded: User!
}
구독 기능은 실시간 앱에서 유용하게 사용됩니다.
스키마의 각 필드에 대한 데이터를 채우는 함수입니다. 리졸버는 데이터베이스, 클라우드 서비스, 또는 다른 소스에서 데이터를 검색할 수 있습니다. 이를 통해 legacy 시스템을 GraphQL 기반으로 전환하는 데 활용할 수 있습니다.
기존의 SQL은 데이터를 가져오기 위해서 SQL을 작성했습니다. 이는 데이터베이스에 데이터를 가져오는 구체적인 과정이 구현되어 있습니다. 하지만 GraphQL는 개발자가 리졸버 함수를 직접 구현해야 하며 각 필드마다 데이터를 어떻게 가져올지 정의해야 합니다. 이 차이로 인해 GraphQL은 더 유연하지만, 개발자가 데이터 검색 로직을 직접 구현해야 하는 책임을 갖게 됩니다.
// 리졸버 함수 (javaScript)
const resolvers = {
Query: {
user: (parent, args, context) => {
// 데이터베이스에서 사용자 조회 로직
},
allUsers: (parent, args, context) => {
// 모든 사용자 조회 로직
}
},
Mutation: {
createUser: (parent, args, context) => {
// 새 사용자 생성 로직
},
updateUser: (parent, args, context) => {
// 사용자 정보 업데이트 로직
}
},
Subscription: {
userAdded: {
subscribe: (parent, args, context) => {
// 새 사용자 추가 이벤트 구독 로직
}
}
}
}
서버에서 현재 정의된 스키마의 실시간 정보를 공유할 수 있게 하는 기능입니다. 이를 통해 클라이언트는 별로의 API 명세서 없이 서버의 스키마 정보를 실시간으로 확인할 수 있습니다. 보안상의 이유로 상용 환경에서는 이 기능의 사용을 신중히 고려해야 합니다.
GraphQL은 현대적인 API 개발 방식으로, 다양한 장점이 있어 매력적으로 다가오지만 몇 가지 고려해야 할 단점도 있습니다. 이를 정리하면 아래와 같습니다. 👇
REST API에서 백엔드는 프론트엔드에 단일 요소만 필요한 경우에도 각 리소스에 사용할 수 있는 데이터를 정의하고 응답 시 모든 데이터를 반환하여 오버페칭을 발생시킵니다. 이와 달리 GraphQL은 클라이언트가 필요한 데이터만 정확히 요청하고 받을 수 있어 오버페칭과 언더페칭 문제를 해결합니다.
GraphQL은 단일 엔드포인트를 통해 모든 데이터를 쿼리할 수 있으며, 관리가 용이합니다. 또한, GraphQL 스키마가 신뢰할 수 있는 단일 소스 역활을 합니다.
강력한 타입 시스템으로 인해 클라이언트와 서버 간의 통신이 더 명확해집니다.
단일 쿼리로 여러 리소스를 요청할 수 있어 HTTP 요청 횟수를 줄이고, 필요한 데이터만 응답받아 응답 크기를 최소화할 수 있습니다.
RESTful API에서는 프론트엔드 개발자는 API에서 작성한 request/response 형식에 의존하게 되어 커뮤니케이션이 강제되는 경우가 많습니다.
GraphQL은 새로운 API 관리 전략이 필요할 수 있습니다. 반면, REST API는 기존 API 관리 모델에 적합한 경향이 있습니다. 만약 GraphQL을 도입하고 새로운 API 관리 전략을 추가하면 전체 비용이 증가할 수 있습니다. 또한 서버 개발자는 쉽게 유지 관리할 수 있는 데이터 모델을 개발하는 데 더 많은 시간을 사용해야 합니다.
GraphQL에서의 캐싱은 REST에 비해 더 복잡합니다. 그 이유에는 GraphQL 요청이 HTTP 메서드에서 POST만 사용합니다. HTTP 프로토콜에서 POST 요청은 서버의 상태를 변경할 수 있는 작업에 주로 사용되기 때문에 기본적으로 캐시되지 않습니다.
GraphQL에서는 캐싱을 구현하기 위해 추가적인 솔루션이나 커스텀 캐싱 메커니즘이 필요합니다.
또한, GraphQL은 단일 엔드포인트만 사용합니다. 이것은 엔드포인트의 URL이 캐시할 수 없는 여러 가지 다양한 응답을 생성한다는 것을 의미합니다. 이러한 이유로 캐싱이 복잡해질 수 있습니다.
마무리로 주요 장점과 고려사항을 요약하자면 👇
GraphQL이 복잡한 웹 및 모바일 애플리케이션에 대응하기 위해 출시됐지만 REST를 완전히 대체하기보다는 각 프로젝트 요구사항에 맞춰 적절히 선택하는 것이 중요합니다.
각 프로젝트의 요구사항에 따라 적절한 기술을 선택하는 것이 중요해 보입니다. REST와 GraphQL의 장단점을 고려하여 서비스에 가장 적합한 방식을 채택해야 합니다. 특히 복잡한 데이터 구조를 가진 프로젝트나 빠른 개발 주기가 필요한 애자일 환경에서 큰 장점을 발휘할 것이라 생각합니다. 필자가 생각하기에는 신규 기술이 아닌 유지 보수 단계에서는 어려울 것이라 생각하며, 돋보이는 장점이 있지 않은 한, 기존의 레거시 코드에서 넘어가는 것은 힘들 것이라는 생각이 있습니다.