GraphQL
은 페이스북이 2012년에 개발하여 2015년에 오픈소스로 공개된 쿼리 언어입니다. 클라이언트는 필요한 데이터의 구조를 지정하고 서버는 정확히 동일한 구조로 데이터를 반환하는 방식으로 불필요한 데이터를 받게 되거나 필요한 데이터를 받지 못하는REST API
의 단점을 해결하여 많은 곳에서 도입하고 있습니다.
GraphQL은 쿼리 언어이다.
GraphQL API에서는 불러오는 데이터의 종류를 쿼리 조합을 통해서 결정합니다. 여기서 쿼리는 SQL(Structed Query Language)의 쿼리와 같은 의미입니다. 즉, 내가 필요한 것만 쿼리(요청)하고 그것만 응답 받습니다.
SQL이 데이터베이스 시스템으로부터 데이터를 가져오는 것이 목적이라면, GraphQL은 클라이언트가 데이터를 서버로부터 가져오는 것이 목적입니다.
REST API에서는 각 Endpoint마다 데이터베이스 SQL 쿼리가 달라지는 반면, GraphQL API는 GraphQL 스키마의 타입마다 데이터베이스 SQL 쿼리가 달라집니다.
기존 REST API의 단점
영화와 관련된 서비스를 만들고 있어 특정 영화에 대한 정보를 REST API를 통해서 가져온다고 가정해 봅시다.
예를 들어 '투 건스' 라는 영화의 필요한 정보(제목, 장르, 평점)를 가져오기 위해 이 REST API를 이용한다면
'투 건스' 영화에 대한 모든 정보(제목, 장르, 설명, 평점, 배경 이미지 등) 를 반환해 줍니다.
저는 제목과 장르 그리고 평점 데이터만 필요하지만 설명과 배경 이미지 주소 등 나에게 필요없는 정보도 모두 반환해 줍니다.
또한 API로 받은 정보가 또 다른 API와 연결되어 있다면 REST API는 API를 두 번 연결해야 합니다. GraphQL
은
이러한 기존 REST API의 단점을 해결해 줍니다.
REST API vs GraphQL
REST API는 URL, METHOD 등을 조합하기 때문에 다양한 Endpoint가 존재합니다.
반면 GraphQL
은 단 하나의 Endpoint만 존재합니다.
https://www.apollographql.com/blog/graphql/basics/graphql-vs-rest/
영화에 대한 API를 설계할 떄 REST API를 사용한다면 다음과 같은 엔드포인트가 존재할 것입니다.
- /movies/list
- /movie/${id}
- /movie_review/${id}
반면 GraphQL은 하나의 엔드포인트에 쿼리를 조합하여 요청하면 되기 때문에 API가 늘어나도 따로 URL 설계를 하지 않아도 됩니다.
Query & Mutation
모든 GraphQL 서비스는 Query
타입을 가지며 Mutation
타입은 가질수 도 있고 가지지 않을 수도 있습니다.
Query와 Mutation의 차이는 크지 않습니다. Query
는 데이터를 읽는데(R) 사용하고,
Mutation
은 데이터를 조작(CUD)하는데 사용합니다.
다음은 영화 '투 건스'의 정보를 GraphQL로 가져오기 위해 쿼리를 이용해서 응답을 받고 있습니다.
REST API와는 다르게 필요한 정보만 반환 받습니다.
좌측은 쿼리 문이고 우측은 서버로 부터 받은 응답입니다.
다음은 새로운 데이터를 추가하는 Mutation
입니다.
Schema & Type
위의 GraphQL 쿼리를 보시면 GraphQL 쿼리 언어는 기본적으로 객체의 필드를 선택하는 것을 알 수 있습니다. GraphQL 쿼리의 형태가 결과와 거의 일치하기 때문에 서버에 대해 모르는 상태에서 쿼리가 반환할 결과를 예측할 수 있습니다. 여기서 서버에 요청할 수 있는 데이터에 대한 정확한 표현을 갖는 것이 좋습니다. 이를 위해 스키마를 사용합니다.
모든 GraphQL 서비스는 해당 서비스에서 쿼리 가능한 데이터들에 타입을 정의하고, 쿼리가 들어오면 해당 스키마에 대해 유효성이 검사된 후 실행됩니다.
type Movie {
id: Int!
title: String!
year: Int
rating: Float!
runtime: Float
genres: [String!]!
summary: String
language: String
background_image: String
}
- 객체 타입: Movie
- 필드: id, title, year 등
- 스칼라 타입: Int, String, Float 등
- 느낌표(!): 필수 값을 의미 (non-nullable)
GraphQL에서는 스칼라 타입들이 기본 제공됩니다.
Int
: 부호가 있는 32비트 정수Float
: 부호가 있는 부동소수점 값String
: UTF-8 문자열Boolean
:true
또는false
값ID
: ID 스칼라 타입은 객체를 다시 요청하거나 캐시의 키로써 자주 사용되는 고유 식별자를 나타냅니다.
기본 제공되지 않는 타입들은 커스텀 스칼라 타입
을 이용해서 직접 지정할 수 있습니다.
Root filed & Resolvers
모든 GraphQL 서버의 최상위 레벨은 GraphQL API에서 사용 가능한 모든 진입점을 나타내는 타입으로
Root
타입 혹은 Query
타입이라고 합니다.
GraphQL에서는 데이터를 가져오는 구체적인 과정을 직접 구현해야 합니다. 쿼리문 파싱은 대부분의 GraphQL 라이브러리에서
처리를 하지만, GraphQL에서 데이터를 가져오는 구체적인 과정은 resolver
가 담당하고, 이는 직접 구현해야 합니다.
아래 예제에서 Query
타입은 인자 id
를 받아 movie
필드를 반환합니다.
resolver
함수는 데이터베이스에 접근한 다음 movie
객체를 생성하고 반환합니다.
Query: {
movie(parent, args, context, info) {
··· // DB 접근 코드 생략
},
}
resolver
함수는 네 개의 인수를 받습니다.
parent
: 첫 번째 인자로 대부분 사용되지 않는 루트Query
타입의 이전 객체로 필요 없는 경우 통상__
(언더바 2개)을 넣어줍니다.args
: 두 번째 인자로 GraphQL 쿼리의 필드에 들어온 인수context
: 세 번째 인자로 모든resolver
함수에 전달되며 현재 로그인한 사용자, 데이터베이스 액세스와 같은 중요한 문맥 정보를 보유하는 값info
: 네 번째 인자로 필드 이름, 루트에서 필드로 이동하는 경로 등 작업의 실행 상태에 대한 정보가 들어 있습니다. 통상 잘 사용하지 않는 인자입니다.