RESTAPI와 GraphQL의 차이점과 특징에 대해 공부해보자.
초기 페이스북 앱은 HTML 웹사이트를 웹뷰로 감싼 형태로 개발되었다.
그러나 2012년 트래픽 증가와 함께 이런 구조가 성능 저하와 빈번한 크래쉬를 일으키는 문제가 발생했었다.
이에 페이스북 개발팀은 네이티브 앱으로 전환을 시도하게 되었고, 데이터를 HTML 대신 API로 전송해야 했다.
하지만 기존의 REST API는 기대만큼의 성능을 보이지 못했고, 이러한 과정에서 페이스북은 모든 기능과 데이터를 다룰수 있고 사용하기 쉬우며 높은 성능을 가진 Data Fetching API를 필요로 했다.
이러한 조건을 충족하기 위해 2012년에 개발된 기술이 바로 GraphQL이다.
그리고 3년 뒤인 2015년 GraphQL은 오픈소스화 되었다.
GraphQL이란?
GraphQL은 API를 위한 쿼리 언어로 여기에서 말하는 QL은 Query Language를 뜻한다.
Query Language는 클라이언트가 서버로부터 데이터를 요청할 때 사용할 수 있는 특수한 언어이다.
우리가 흔히 사용하는 Query Language로는 SQL이 있다. SQL은 Spring이나 Node.js같은 웹 서버 어플리케이션에서 데이터베이스로 원하는 데이터를 검색할 수 있다.
이처럼 Query Language는 일반적으로 데이터베이스에 데이터를 요청할 때 많이 사용되지만 페이스북은 이런 개념을 API 설계에 적용해 GraphQL을 만들어냈다.
한마디로 GraphQL을 정의하자면 클라이언트가 원하는 데이터를 명확히 정의하고 효율적으로 요청할 수 있도록 통제권을 제공하는 API 쿼리 언어라고 할 수 있다.
GraphQL의 특징
특징1. 네트워크 대역폭 최적화
가상의 앱을 예시로 들어보자. BEST 상품들이 보여지는 화면, 최신 상품들이 보여지는 화면, 그리고 검색 결과 게시물이 보여지는 화면 총 3개의 화면이 있다고 가정해보자.
각각의 페이지는 요구사항에 따라 보여지는 URI가 다르다고 할때, 이때 RestAPI와 GraphQL의 설계 방식에 따라 어떤 차이가 있는지 알아보자.
먼저 RestAPI는 리소스 중심의 설계를 따르며 각 리소스는 고유한 URI를 가진다. 그래서 해당 앱을 개발하기 위해 각각의 엔드포인트 총 3가지를 만들어야 한다.
예시)
https://example.com/posts/best
https://example.com/posts/recent
https://example.com/posts/search
그리고 클라이언트와 서버는 각각의 엔드포인트에 맞는 DTO를 생성해서 관리하게 된다.
예시)
data class BestPostDTO{
val title:String,
val viewCount: Int,
val createdAt: LocalDateTime,
}
data class RecentPostDTO{
val title: String,
val content: String,
val createdAt: String,
}
data class SearchPostDTO{
val title: String,
val content: String,
val imageUrl: String
}
반면에 GraphQL은 이런 문제를 해결하기 위해 단일 엔드포인트 구조를 채택했다.
모든 데이터 요청은 GraphQL과 같은 엔드포인트의 쿼리를 통해 이루어진다.
그래서 각각의 엔드포인트에 대응하는 DTO를 만들 필요 없이 하나의 DTO로 여러 요구사항에 맞는 데이터를 처리할 수 있다.
data class PostDTO{
val title: String,
val viewCount: Int,
val content: String,
val imageUrl: String,
val createdAt: LocalDateTime,
}
이런 특징으로 관리해야 할 엔드포인트와 코드의 양을 줄여주어 유지보수에 훨씬 유리함을 주게 된다. 물론 이러한 경우에 Null에 대한 처리가 추가적으로 필요할 수 있다.
이번에는 유저의 정보와 제목이 포함된 게시물 리스트를 그려야 하는 페이지를 생각해 보자.
이때 RestAPI의 접근 방식을 살펴보면 유저의 정보를 조회하는 API 요청 1번, 게시물 리스트를 조회하는 API 요청 1번으로 총 2번의 API 요청을 필요로 한다.
이렇게 필요한 데이터를 한 번에 모두 가져올 수 없는 문제를 언더페칭이라고 한다.
언더페칭은 네트워크 트래픽을 증가시키고 요청 대기 시간이 늘어날 수 있다는 단점이 있다.
반면에 GraphQL은 단일 쿼리를 통해 유저의 정보와 게시물의 정보를 한 번에 요청할 수 있다.
이러한 방식을 통해 네트워크 효율을 향상시킬 수 있다.
다시 RestAPI로 돌아와서 현재 앱에서는 유저의 이메일이나 게시물의 내용은 보여지고 있지 않다고 가정을 해 보자.
RestAPI에는 이메일이나 게시물 내용이 필요없는 데이터임에도 불구하고 데이터를 받아오고 있다고 할 때, 이러한 문제를 오버페칭이라고 한다.
오버페칭은 네트워크 대역폭을 낭비하고 클라이언트에서 불필요한 데이터를 처리해야 하는 부담을 초래할 수 있다.
반면에 GraphQL은 클라이언트에서 쿼리를 통해 원하는 데이터 필드만 지정할 수 있는 기능을 제공한다.
이런 특징을 통해 RestAPI의 오버페칭을 방지하고 네트워크 대역폭을 절약할 수 있다.
그리고 클라이언트 측에서는 데이터를 더 효율적으로 처리할 수 있게 된다.
이 특징은 마치 SQL의 SELECT문과 비슷한 느낌을 주기도 한다.
특징2. 확장에 열려있다.
다음 특징을 알아보기 위해 앱의 UI가 변경되는 업데이트가 있었다고 가정해 보자.
업데이트 내용은 유저의 정보엔 직업이 추가되었고, 게시물엔 좋아요 개수가 추가되었다고 하고, 이때 Rest API 방식에서는 두 가지 해결 방법이 있다.
하나는 기존의 API에 필요한 데이터 필드를 추가하는 것이다. 이 방법은 아주 간단하지만 오버 페칭에 대한 네트워크 대역폭 낭비가 더 심해지는 문제가 있다.
다은 방법은 새로운 엔드포인트를 추가하는 것이다. 예를 들어 각각 버전2의 엔드포인트를 만들어 필요한 데이터만 포함시키는 것이다.
하지만 이 방법은 관리해야 할 엔드포인트가 늘어나는 문제가 있다.
GraphQL은 이 문제는 깔끔하게 해결해 줄 수 있다.
특징3. 문서화
마지막 특징은 문서화이다.
RestAPI의 경우 OpenAPI같은 도구를 사용해서 API구조나 사용 방법, 엔드포인트, 요청응답 형식을 문서화한다.
이런 문서화로 개발자가 API 사용법을 이해하는데 도움을 준다.
하지만 RestAPI의 문서화는 API코드와 별도로 유지 및 관리되어 가끔 코드와 문서간의 불일치가 발생할 수도 있다.
예를 들어 문서에는 유저의 나이 필드가 정수형으로 명시되어 있는데, 실제로 수신된 데이터가 문자열이라면 수신된 프레임워크나 언어에 따라 오류를 발생시킬 수도 있다.
다른 케이스로는 필드명 불일치가 있다. 예를 들어 유저의 리스트 정보를 받아오는 users 엔드포인트에서는 유저 이름 필드명이 name으로 되어있지만, 하나의 유저 정보를 조회하는 엔드포인트에서는 유저 이름 필드명이 username으로 되어 있다.
이러한 경우 시스템상의 문제는 없겠지만, 프론트엔드 개발자의 입장에서는 데이터를 일관되게 처리하기 어려울 수 있다.
물론 이런 문제는 일관된 네이밍 컨벤션을 정의하고 엄격하게 준수함으로 방지할 수 있겠지만, 휴먼에러라는 것이 완전하게 방지하는 것은 불가능하다고 생각한다.
그리고 이 문제는 다시 버전관리에 대한 문제를 초래할 수도 있다.
반면 GraphQL은 스키마 정의 언어 SDL을 통해 스키마를 정의한다.
스키마는 서버에서 API의 모든 타입, 필드, 쿼리를 명확하게 기술하게 된다.
그리고 이 스키마는 자체가 문서 역할을 한다.
스키마에 정의된 내용은 자동으로 문서화가 되고, API와의 불일치가 발생할 가능성이 굉장히 적다.
실제로 테스트 코드를 작성하게 되면 불일치가 거의 0에 수렴한다.
그래서 API가 업덷이트되면 스키마도 같이 갱신되기 때문에 문서와 코드 간의 일관성이 유지된다.
그리고 이런 특징은 GraphQL의 테스트 도구들이 스키마의 타입들을 조회할 수 있게 해준다.
작성된 스키마를 기반으로 자동완성이나 자체적으로 보기좋게 문서를 만들어주기도 한다.