May 31st 2019
So what’s this GraphQL thing I keep hearing about?
만약 여러분이 저와 비슷하다면, 새로운 기술에 대한 소식을 들었을 때 아래의 세 단게를 겪을실 겁니다.
자바스크립트 라이브러리? jQuery면 됐지!
계속 소식을 듣게 되는데 한번 살펴봐야겠군
더 늦어지기 전에 당장 이 라이브러리를 배워야 해!
지금과 같이 빠르게 움직이는 시기에 평정심을 유지하는 방법은, 위의 2와 3단계 사이에 새로운 기술을 배워보는 것입니다. 그래서, 지금이 바로 GraphQL이 무엇이지 배워보기 좋은 시기라고 생각합니다.
간결하게 말하면, GraphQL은 데이터롤 어떻게 요청하는 지에 대한 Syntax이며, 일반적으로 서버에서 클라이언트로 데이터를 불러올 때 사용합니다. GraphQL은 아래와 같은 세 개의 주요 특징을 가지고 있습니다.
그러면 GraphQL은 왜 등장하게 되었을까요? GraphQL은 어떤 방식으로 사용되고 사용할 수 있을까요? 아래의 내용을 참고해 주세요.
GraphQL은 Facebook에서부터 시작되었습니다. 하지만 복잡하지 않은 애플리케이션이라도 전통적인 REST API의 한계에 마주칠 수 있습니다.
예로, 포스트 리스트를 화면에 보여줘야 하고, 각 포스트는 user-name과 avatar가 있는 likes 리스트를 함께 보여준다고 가정해 보겠습니다. 해당 데이터를 위한 API 요청은 그리 어렵지 않습니다. 포스트가 유저 정보를 내포하고 있는 likes 배열을 가지도록 조금 수정할 수 있습니다.
하지만, 환경이 모바일 앱이라고 가정해 봅시다. 모든 부가적인 데이터를 로드하는데 더 많은 시간이 걸리기 시작합니다. 때문에, 이제 두 개의 endpoint가 필요하게 됩니다. 하나는 likes가 없이, 그리고 다른 하나는 likes가 포함된 것입니다.
한가지 더 덧붙이자면, 포스트가 MySQL 데이터베이스에 저장되는 동안, likes는 Redis에 위치하게 됩니다.
여러 data source 및 facebook이 관리하는 API 클라이언트에서 위와 같은 시나리오를 예상할 수 있고, REST API의 한계가 보이기 시작할 겁니다.
Facebook이 도출해 낸 해결방안은 개념적으로 매우 간단합니다. 다량의 endpoints를 생성하는 대신, 복잡한 쿼리를 수용할 수 있는 단일의 스마트한 endpoint를 만들고 클라이언트가 요청하는 어떤 형태의 데이터도 응답을 할 수 있게 만드는 것입니다.
사실 GraphQL Layer는 클라이언트와 하나 또는 여러 데이터 리소스 사이에 위치합니다. 그리고 클라이언트로부터 요청을 받으면 데이터를 불러오게 됩니다. 무슨 의미인지 헷갈리시나요? 그럼 좀 더 쉽게 비유해 보겠습니다.
REST 모델은 피자를 주문하고 식료품 배달을 요청하고 세탁소에 맡긴 옷을 찾을 때, 세 곳의 장소에 각각 전화를 하는 것과 같습니다.
GraphQL은 개인 비서가 도와주는 것과 같습니다. 비서에게 세 장소의 주소를 알려주었다면, 여러분은 단지 원하는 것을 말하고(드라이 크리닝, 라지 피자, 계란 한 판), 기다리면 됩니다.
즉, GraphQL은 이런 마법같은 비서에게 의사 전달을 하는 표준적인 언어를 수립한 것입니다.
실무에서 GraphQL API는 크게 Schema, Query, Resolvers로 구성됩니다.
GraphQL이라는 개인 비서에게 보내는 요청이 바로 query이며, 기본적으로 아래와 같은 형태를 취합니다.
query {
stuff
}
우리는 'query' 키워드를 사용해 query를 선언했습니다. 이 query는 stuff라는 이름의 field를 요청하고 있습니다. GraphQl의 좋은 점 중 하나는 중첩이 가능하다는 것입니다. 우리는 아래와 같이 중첩해서 query를 작성할 수 있습니다.
query {
stuff {
eggs
shirt
pizza
}
}
보시다시피, 클라이언트에서 query를 생성할 때 어떤 '상점'애서 데이터를 받아와야 하는지 고민하지 않아도 됩니다. 원하는 것을 요청하고, GraphQL 서버가 나머지 일을 처리하도록 하게 합니다.
Query field는 배열로 설정할 수도 있습니다. 예로, 아래는 포스트 리스트를 요청하는 일반적인 패턴입니다.
query {
posts { // 이것은 배열입니다.
title
body
author { // 중첩해서 들어갈 수 있습니다.
name
avatarUrl
profileUrl
}
}
}
Query field는 argument를 지원합니다. 만약 특정 포스트를 보여주고 싶다면, 아래와 같이 id를 argument로 추가할 수 있습니다.
query {
post(id: "123foo") {
title
body
author {
name
avatarUrl
profileUrl
}
}
}
마지막으로 id argument를 좀 더 다이나믹하게 구성하고 싶다면, 우리는 변수를 선언하고 이 변수를 query 안에서 사용할 수 있습니다. (참고로, 아래와 같이 Query 자체에 이름을 붙일수 있습니다.)
query getMyPost($id: String) {
post(id: $id) {
title
body
author {
name
avatarUrl
profileUrl
}
}
}
GitHub’s GraphQL API Explorer를 이용하면 위에서 설명한 것을 연습하기 좋습니다. 링크를 클릭해 GraphQL API Explorer에 접속한 후 아래의 query를 작성해 보세요.
query {
repository(owner: "graphql", name: "graphql-js") {
name
description
}
}
우리가 새로운 필드명을 입력하려 타이핑을 하면, IDE가 GraphQL API에서 자동완성된 목록을 보여줍니다.
GraphQL query에 대해 좀 더 알고자 한다면 Anatomy of a GraphQL Query 글을 참고해 보세요.
아무리 훌륭한 비서가 도와준다고 해도, 우리가 주소를 전달하지 않으면 비서는 우리에게 드라이 크리닝을 찾아다 주지 못 합니다.
마찬가지로 GraphQl도 우리가 resolver를 이용하라고 말하지 않는다면 query를 받아도 무슨 일을 해야할 지 알지 못 합니다.
Resolver는 GraphQL에게 어떻게 그리고 어디서 해당하는 field에 상응하는 Data를 불러올지에 대해 알려줍니다. 예를 들어, 아래와 같이 위의 포스트 field에 대한 resolver를 작성할 수 있습니다.
Query: {
post(root, args) {
return Posts.find({ id: args.id });
}
}
Resolver는 Query에 직접 작성합니다. Root level에세 포스트에 대한 query를 작성하기 위해서입니다. 하지만 sub-field에 대한 resolver 또한 작성할 수 있습니다. 예로 아래와 같이 post's author에 대한 하위 필드 resolver를 작성할 수 있습니다.
Query: {
post(root, args) {
return Posts.find({ id: args.id });
}
},
Post: {
author(post) {
return Users.find({ id: post.authorId })
}
}
resolver는 단순히 데이터 베이스를 불러오는 역할만 할 수 있는것이 아닙니다. 예를들어 commentsCount라는 기능을 Post 타입에 추가할 수 있습니다.
Post: {
author(post) {
return Users.find({ id: post.authorId });
},
commentsCount(post) {
return Comments.find({ postId: post.id }).count();
}
}
핵심은 GraphQl에서, 여러분의 API Schema와 데이터베이스 Schema는 분리할 수 있다는 것입니다. 바꿔말하면, 우리의 데이터베이스에 author, commentsCount filed가 존재하지 않을 수 있지만 resolver를 이용하면 이러한 field가 있는것처럼 만들 수 있습니다.
앞서 살펴보았듯이 resolver안에서 자유롭게 코드를 작성할 수 있기 때문에, 여러분의 데이터베이스의 내용을 수정할 수 있습니다. 이러한 경우를 mutation resolver라고 합니다.
GraphQL’s typed schema system에 의해 위에서 설명한 것들이 가능합니다. 저는 오늘 GraphQL에 대해 부담되지 않고 간결한 소개만 작성하고자 합니다. 그렇다 하더라고, GraphQL-공식문서를 살펴보는 것을 추천합니다.
잠시 한숨을 돌리며 몇가지 일반적인 질문에 대해 정리해 보는 시간을 갖도록 하겠습니다.
거기 뒤쪽에 계신 분이요. 네, 당신이요. 뭔가 궁긍하신 것이 있다는 것을 알고있습니다. 숨기지 마시고 아래 내용을 좀 더 읽어보세요.
GraphQL은 Grapph 자료구조와 많은 관련은 없습니다. "Graph"라는 이름은 field와 sub-field를 거치며 데이터를 취하는 아이디어에서 나왔습니다. QL은 "Query Language"를 의미합니다.
여러분이 아직 REST를 사용하며, GraphQL로 해결하려는 문제를 마주치지 않았다면 좋은 증상이라고 말하고 싶습니다.
GraphQL로 REST를 대신해도 여러분의 앱에대한 사용자 경험은 크게 나아지지 않을것입니다. 따라서 GraphQL로 변경하는 작업은 사활이 걸린 문제가 아닐 것입니다. 그렇다 하더라도, 작은 프로젝트에서라도 GraphQL을 사용해 보는 것을 추천합니다.
네, 사용할 수 있습니다. GraphQL은 단순히 spec이기 때문에 어떠한 라이브러리, 플랫폼에서도 사용할 수 있습니다. 클라이언트나 직접 GraphQL 서버로 요청을 보내는 방식으로 사용할 수 있습니다. Apollo와 같은 경우 웹, iOS, Angular용 GraphQL GraphQL 클라이언트를 가지고 있습니다.
말씀드렸듯이 GraphQL은 단순히 스펙이며, Facebook에서 작성한 한 줄의 코드도 실행할 필요가 없습니다.
Facebook의 support를 받는 것은 GraphQL 생태 환견에 큰 장점이 될 수 있다고 생각하지만, 현재 Facebook이 사용을 중지한다고 해도 GraphQL은 생존할만큼 커뮤니티가 활성화 되었다고 생각합니다.
Resolver를 여러분이 직접 작성하기 때문에 안전에 대한 문제는 여러분이 resolver를 어떻게 작성하는지에 달려있습니다.
예를 들어, 클라이언트에서 데이터를 얼마나 받을지에 대한 제한을 직접 규정하도록 하게 한다면, 여러분은 아마도 해당하는 수에 대한 제한을 두어 클라이언트에서 한 번에 많은 양의 요청을 보내는 공격에 대비할 것입니다.
일반적으로 GraphQL을 이용해 앱으르 구현하기 위해서 최소 두 개의 부분이 필요합니다. 이 외에 다른 여러 방법들도 존재합니다.
이제 여러분은 GraphQL에 대해 어느정도 알게 되었으니, GraphQL에서 main player들이 어떠한 것들이 있는지 알아보도록 하겠습니다.
GraphQL 서버에 관한 파트입니다. GraphQL 자체는 단순히 스펙입이기 때문에, 서버에 대한 여러 선택지가 있습니다.
GraphQL의 오리지널 참고 구현이면 express-graphql과 함꼐 사용해서 여러분의 API 서버를 만들 수 있습니다.
Apollo 팀에서 제작한 GraphQL 서버입니다. GraphQL-JS보다 널리 퍼지지는 않았지만 문서가 잘 정리되어 있고 지원이 잘 돼 있어서 빠르게 커지고 있습니다.
여기를 클릭하면 여러 언어로 지원된 GraphQL 서버를 확인할 수 있습니다. (Python, Ruby etc)
query를 보내기 위해서 특정 클라이언트 라이브러리가 필요한 것은 아니지만, 이것은 여러분의 삶은 좀 더 쉽게 만들어 줄 수 있습니다.
Facebook에서 제작한 GraphQL Toolkit입니다. 사용해 본 적은 없지만, facebook의 필요에 맞추어 만들어 졌다고 합니다. 대부분의 경우 사용하기에 과도하게 설계되었습니다.
새롭게 등장했지만 빠르게 이 영역에서 확장하고 있습니다. 일반적인 Apollo 클라이언트 스택은 아래와 같습니다.
기본적으로 Apollo 클라이언트는 데이터를 Redux를 이용해 저장합니다. Redux는 매우 잘 설계된 상태 관리 라이브러리이기 때문에 이러한 점은 좋은 장점이라고 생각합니다.
이미 GraphQL을 사용한 여러 오픈 소스들이 존재합니다.
저는 VulcanJS의 lead maintainer입니다. 저는 React/GraphQL로 앱을 만들때 많은 boilerplate 작성을 줄일수 있도록 VulcanJS를 만들었습니다. 현대 웹 생태계의 철도라 소개할 수 있으며, CRUD 앱을 매우 간단하게 작성할 수 있습니다.
Gatsby는 React로 만들어진 정적 페이지 생성기입니다. GraphQL과 함께 사용되어 Gatsby는 여러 GraphQL에 API 요청을하고, 이것을 이용해 정적인 클라이언트 React 앱을 만들수 있습니다.
GraphiQL는 브라우저에서 GraphQL endpoint로 query를 작성하는데 매우 유용한 IDE입니다.
중첩된 GraphQL query로 인해서, 하나의 query가 다수의 database call을 보내는 경우가 많습니다. 성능 문제를 피하기 위해서 batching, caching을 할 수 있는 DataLoader 같은 라이브러리를 사용할 수 있습니다. DataLoader는 facebook에서 만들어 졌습니다.
Create GraphQL Server는 커맨드라인 유틸리티이며, Node server와 MongoDB를 이용해 GraphQL 서버를 빠르게 생성해 줍니다.
Create graphQL Server와 유사합니다. GraphQL 백엔드 구축을 위해 GraphCool을 이용합니다.
GraphQL 백엔드를 서비스로 제공하는 여러 회사들도 존재합니다. 이러한 서비스를 이용해 처음 GraphQL 생태계에 발을 담궈보기 좋을 것입니다.
free developer plan을 사용해 GraphQL과 AWS Lambda를 결합한 유연합 백엔드 플랫폼입니다.
Graphcool과 유사한 서비스를 제공합니다.
GraphQL에 대해 배워볼 수 있는 여러 장소가 이미 많이 존재합니다.
공식 GraphQL 사이트
LearnGraphQL, LearnApollo는 GraphCool에서 만들 무료 코스입니다.
Apollo와 GraphQL에 관한 매우 잘 작성된 글이 많습니다.
GraphQLcool 팀에 의해 큐레이팅 된 뉴스레터
GraphQL, React, Meteor를 커버하는 뉴스레터
GraphQL을 이용해 Intercom clone을 해보는 튜토리얼
GraphQL 링크와 관련 리소스
이제 어떻게 GraphQL 지식을 실제로 사용할 수 있을까요? 아래와 같이 몇몇 도움될 만한 자료를 준비했습니다.
Next.js와 React에 익숙하다면 이 예제 GraphQL endpoint를 설정하고 Apollo를 이용해 query를 작성할 수 있습니다.
간단하게 GraphQL data layer를 설정하기에 좋습니다. All-in-one 플랫폼이기 때문에 별도의 설정없이 바로 시작할 수 있습니다.
React / GraphQL 앱을 빌드하기 위해 여섯 단계의 튜토리얼을 제공합니다.
GraphQL을 처음 접하면 현대 개발 분야의 여러 부분에 걸쳐져 있기 때문에 복잡해 보일수 있습니다. 하지만, 근본적인 개념을 이해하기 위해 시간을 투자하면, 많은 부분을 이해할 수 있습니다.
여러분이 GraphQL을 실제 이용하던 그렇지 않던 간에, GraphQL에 익숙해 지는 시간을 가져보는 것은 가치가 있다고 생각합니다. 많은 회사와 프레임워크가 이 기술을 채택하고 있기 때문입니다. 그리고 아마도 몇 년 후 웹 개발에 있어서 주요 기술로 자리잡을 것입니다.