Conceptly
← 전체 목록
📊

GraphQL

API클라이언트가 필요한 데이터를 쿼리로 정확히 요청하는 API 언어

GraphQL은 Facebook이 2015년에 공개한 API 쿼리 언어이자 런타임입니다. 클라이언트가 필요한 필드를 쿼리 문법으로 직접 명시하면, 서버는 그 구조 그대로 응답을 돌려줍니다. 단일 엔드포인트(/graphql)에서 모든 데이터 요청을 처리하며, 스키마로 API의 타입과 관계를 정의합니다. 데이터 조회는 query, 변경은 mutation, 실시간 구독은 subscription으로 구분합니다. 클라이언트가 응답 형태를 제어할 수 있어 과잉 페칭(over-fetching)과 부족 페칭(under-fetching) 문제를 구조적으로 줄입니다.

아키텍처 다이어그램

🔗 관계 다이어그램

점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다

왜 필요한가요?

REST API로 프론트엔드를 개발하다 보면 반복되는 마찰이 있습니다. 사용자 프로필 페이지에는 이름과 아바타만 필요한데, /users/123 응답에는 가입일, 설정, 활동 기록까지 수십 개 필드가 딸려옵니다. 반대로 사용자의 최근 게시글과 팔로워 수를 같은 화면에 보여주려면 /users/123, /users/123/posts, /users/123/followers 세 번을 호출해야 합니다. 모바일 앱은 데스크톱보다 훨씬 적은 데이터만 필요한데, 같은 엔드포인트를 쓰면 쓸모없는 바이트가 네트워크를 타고 옵니다. 프론트엔드 팀이 '이 화면에는 이 필드 조합이 필요합니다'라고 할 때마다 백엔드가 새 엔드포인트를 만들거나 기존 엔드포인트에 쿼리 파라미터를 추가하는 패턴이 반복되면, API 수가 늘어나고 양쪽 팀의 배포 주기가 엮이기 시작합니다.

왜 이런 방식이 등장했나요?

Facebook이 2012년 모바일 앱을 네이티브로 전환하면서 이 문제가 심각해졌습니다. 뉴스 피드 하나를 그리려면 사용자 정보, 게시글, 댓글, 좋아요, 사진 등 수십 종류의 데이터가 필요했고, REST 엔드포인트를 하나씩 호출하면 요청 수가 폭발하고 응답에는 화면에 쓰지 않는 필드가 대량으로 포함됐습니다. 모바일 환경에서 이 비효율은 곧 느린 로딩과 데이터 요금 낭비로 이어졌습니다. Facebook 내부에서 2012년부터 개발하던 GraphQL은 클라이언트가 필요한 데이터의 형태를 직접 기술하면 서버가 그 형태 그대로 응답하는 구조였습니다. 2015년 오픈소스로 공개된 후 GitHub, Shopify, Airbnb 등이 채택하면서 복잡한 프론트엔드 요구사항을 가진 서비스에서 빠르게 확산됐습니다.

안에서 어떻게 동작하나요?

GraphQL에서 API 호출은 세 단계로 동작합니다. 첫째, 스키마 정의입니다. 서버 측에서 어떤 타입이 있고, 각 타입에 어떤 필드가 있으며, 타입 간 관계가 어떤지를 스키마 언어로 선언합니다. 예를 들어 User 타입에 name, email, posts 필드가 있고 posts는 Post 타입의 배열이라고 정의합니다. 이 스키마가 API의 계약서 역할을 합니다. 둘째, 쿼리 작성입니다. 클라이언트는 필요한 필드를 중괄호 안에 나열하는 방식으로 쿼리를 씁니다. { user(id: 123) { name, posts { title } } }라고 보내면 이름과 게시글 제목만 요청하는 셈입니다. mutation 키워드로 데이터 변경, subscription으로 실시간 이벤트 수신도 같은 문법 구조를 씁니다. 셋째, 리졸버 실행입니다. 서버는 쿼리의 각 필드에 매핑된 리졸버 함수를 실행합니다. user 필드의 리졸버가 데이터베이스에서 사용자를 가져오고, posts 필드의 리졸버가 해당 사용자의 게시글을 가져옵니다. 리졸버는 데이터베이스, 다른 API, 캐시 등 어디서든 데이터를 가져올 수 있습니다. 실행이 끝나면 클라이언트가 요청한 구조 그대로 JSON 응답이 만들어집니다.

무엇과 헷갈리나요?

GraphQL과 REST는 둘 다 클라이언트-서버 간 데이터를 주고받는 API 계층입니다. 하지만 주도권의 위치가 다릅니다. REST에서는 서버가 엔드포인트와 응답 구조를 결정하고 클라이언트는 그걸 받아 씁니다. GraphQL에서는 클라이언트가 쿼리로 원하는 데이터 구조를 명시하고 서버가 그에 맞춰 응답합니다. REST가 더 적합한 경우는 리소스 구조가 단순하고 안정적일 때, HTTP 캐싱을 적극 활용해야 할 때, 외부에 공개하는 API를 최대한 단순하게 유지해야 할 때입니다. GraphQL이 더 적합한 경우는 화면마다 필요한 데이터 조합이 크게 다를 때, 한 번의 요청으로 여러 리소스를 가져와야 할 때, 프론트엔드가 백엔드 배포에 묶이지 않고 독립적으로 움직여야 할 때입니다. GraphQL의 한계도 있습니다. 단일 엔드포인트라서 HTTP 수준의 캐싱이 REST만큼 단순하지 않고, 쿼리 복잡도를 제어하지 않으면 서버 부하가 예측 어렵게 커질 수 있습니다. 또한 파일 업로드 같은 바이너리 처리에는 추가적인 규약이 필요합니다.

언제 쓰나요?

GraphQL은 프론트엔드의 데이터 요구사항이 복잡하고 자주 바뀌는 서비스에서 가장 큰 효과를 냅니다. 소셜 피드, 대시보드, 이커머스 상품 상세 페이지처럼 한 화면에 여러 종류의 데이터를 조합해 보여줘야 하는 경우, 쿼리 하나로 필요한 데이터를 정확히 가져올 수 있어 네트워크 왕복 횟수와 불필요한 데이터 전송이 줄어듭니다. 같은 백엔드를 웹, 모바일, 워치 앱 등 서로 다른 클라이언트가 공유할 때도 유용합니다. 각 클라이언트가 자기 화면에 맞는 쿼리를 보내면 되니, 클라이언트별 전용 엔드포인트를 만들 필요가 없습니다. 마이크로서비스 환경에서는 여러 서비스의 스키마를 하나로 합치는 페더레이션 패턴을 적용할 수 있습니다. 프론트엔드는 단일 그래프에 쿼리를 보내고, 게이트웨이가 해당 필드를 담당하는 서비스로 요청을 분배합니다. 도입을 검토할 때 주의할 점도 있습니다. 스키마 설계와 리졸버 최적화(N+1 문제 방지를 위한 DataLoader 등)에 초기 투자가 필요하고, 쿼리 복잡도를 제한하는 정책 없이 운영하면 한 번의 쿼리가 서버에 과도한 부하를 줄 수 있습니다. 단순한 CRUD API라면 REST가 더 빠르게 구축되고 운영 부담도 적습니다.

복잡한 프론트엔드다양한 클라이언트빠른 프로토타이핑마이크로서비스 통합