프론트엔드 개발자로서 데이터 처리를 할 때 가장 거슬리는 부분들 중 하나는 지나치게 많은 데이터를 불러와서 가공해야 하는 것, 그리고 데이터가 부족해서 더 많은 HTTP 통신을 해야 하는 상황이다. 백엔드 API를 아무리 Restful하게 구성한다고 해도 복잡한 UX를 구현해야 하는 현대 웹 어플리케이션에서는 현실적으로 데이터의 Overfetching, 그리고 Underfetching이 존재할 수밖에 없다. 서로 다른 모양의 다양한 요청들에 효과적으로 응답하기 위해, 결국 페이스북에서는 2015년 GraphQL이라는 쿼리 언어를 발표하게 된다.
GraphQL이란?
GraphQL은 API를 위한 쿼리 언어이자, 이미 존재하는 데이터로 쿼리를 수행하기 위한 런타임이다. 쿼리 언어라고 하면, 우리는 흔히 SQL을 떠올릴 수 있다. SQL은 데이터베이스에 저장된 데이터를 효율적으로 가져오고자 한다. 그러나 GraphQL은 목적 자체가 다르다. 웹 클라이언트가 서버에서 데이터를 효율적으로 가져오기 위해 탄생한 쿼리언어이기 때문에, 같은 쿼리 언어라도 실전에서 쓰이는 방식은 완전히 다르다. SQL 쿼리는 주로 백엔드 시스템에서 실행하는 반면, GraphQL 쿼리는 주로 클라이언트에서 실행하게 된다. 일반 HTTP API가 특정 데이터베이스나 플랫폼에 종속적이지 않은 것처럼, GraphQL 역시 어떤 데이터베이스나 특정한 스토리지 엔진과 관계되어 있지 않으며 기존 코드와 데이터에 의해 대체될 수 있다.
REST API와의 비교
REST란, URI를 통해 자원(Resource)을 명시하고, HTTP 메서드를 통해 해당 자원에 대한 CRUD Operation을 적용하는 것을 말한다. REST를 기반으로 만들어진 API는 URL, 그리고 메서드를 조합해서 만들어지기 때문에 다양한 Endpoint가 존재한다. 각각의 Endpoint마다 데이터베이스에 접근하기 위한 SQL 쿼리 역시 달라진다. 이는 하나의 API가 정해진 구조의 데이터로만 응답을 줄 수 있다는 의미다. 반면 GraphQL은 단 하나의 Endpoint가 존재한다. 클라이언트에서 스키마의 타입을 지정하면, 주어진 API를 통해 받아올 데이터의 종류를 자유자재로 결정할 수 있다.
왜 GraphQL이 필요할까?
REST API와 대비되는 GraphQL만의 장점들을 세 가지 정도로 소개해보고자 한다.
먼저, 클라이언트는 여러 가지 상황에서 필요한 데이터를 명시적으로 요청할 수 있다. API에 GraphQL 쿼리를 보내면, 항상 예측 가능한 결과를 반환하게 된다. 클라이언트는 서버가 아닌 데이터를 제어하기 때문이다. 이는 위에서 언급했던 데이터의 Overfetching 문제를 해결하는 데에 결정적인 역할을 한다. 의도한 시점에 필요한 데이터만 받아오는 것은 네트워크 비용을 줄이고 통신 관련 프론트엔드의 복잡도를 줄일 수 있다.
다음 코드들은 GraphQL 쿼리와 이에 대한 응답 JSON이다.
{
hero {
name
height
mass
}
}
{
"hero": {
"name": "Luke Skywalker",
"height": 1.72,
"mass": 77
}
}
필요한 데이터만을 명시적으로 요청할 수 있다.
두 번째로, GraphQL을 통해 연결된 리소스들을 하나의 HTTP 요청으로 받을 수 있다는 장점도 있다. GraphQL 쿼리는 하나의 리소스 속성 뿐 아니라, 리소스 간의 참조를 이해할 수 있기 때문이다. 일반적인 REST API는 연결된 리소스의 복잡한 데이터를 받아오기 위해 여러 개의 API를 호출해야 하지만, GraphQL API는 한 번의 요청으로 앱에 필요한 데이터를 받을 수 있다. 즉, 데이터의 Underfetching 문제를 해결한다.
다음은 복잡한 리소스를 요청하는 쿼리와 응답 JSON이다.
{
hero {
name
friends {
name
}
}
}
{
"hero": {
"name": "Luke Skywalker",
"friends": [
{ "name": "Obi-Wan Kenobi" },
{ "name": "R2-D2" },
{ "name": "Han Solo" },
{ "name": "Leina Organa" },
]
}
}
Endpoint가 나뉜 REST API였다면 두 개의 요청으로 쪼개져야 했을 데이터가 단 한번의 HTTP 요청으로 해결되는 것을 볼 수 있다.
마지막으로, 별도의 Versioning 없이 API를 디벨롭시킬 수 있다. 오래되어 미사용되는 필드를 숨기거나, 새롭게 요구되는 필드를 추가하기 위해서 백엔드 API 자체를 수정할 필요가 없다. 클라이언트가 자신이 필요한 시점에 필요한 데이터를 받아오도록 스키마를 업데이트하면 된다.
즉 GraphQL은 클라이언트에게 필요한 것을 정확하게 요청할 수 있는 기능을 제공한다. 뷰에 필요한 데이터를 정확하게 지정해서 한 번의 요청으로 통해 불러올 수 있는 새로운 방법을 제시한다. 리소스 기반의 REST 같은 기존 접근 방법에 비해 더 효과적으로 데이터를 불러온다는 장점이 있으며, 서버 측에서 중복된 로직이 반복되거나, 이를 피하기 위해 커스텀 엔드포인트를 추가하는 일을 작업을 방지한다.
여기까지 GraphQL이 등장한 배경과 장점을 간략하게 알아보았다. 실제 사용을 위해서는 우선 GraphQL이 가지는 언어적 특징들을 알아야 하는데, 개인적으로는 타입 시스템과 데이터를 표현하는 방법들의 상당수가 타입스크립트에서 차용해온 것과 같은 인상을 받았다. 다음 기회에는 데이터 스키마를 활용하는 방법에 대해 포스팅해봐야겠다.