CS Insights

GraphQL 쿼리의 추상화 모델과 REST API 공간 패턴의 치명적 설계 한계 극복 전략

GraphQL 쿼리의 추상화 모델과 REST API 공간 패턴의 치명적 설계 한계 극복 전략
최근 실무에서 이 기술을 프로젝트에 적용해 보면서 정말 많은 시행착오를 겪었습니다. 답답한 마음에 제가 직접 정리해 본 핵심 내용입니다. 현대의 복잡한 다중 플랫폼 프론트엔드 환경에서 서버와 클라이언트가 데이터를 주고받는 방식은 전통적인 REST(Representational State Transfer) 아키텍처의 철학을 점차 벗어나고 있습니다. REST API 구조 하에서는 모든 시스템 자원(Resource)이 고유의 URI(Uniform Resource Identifier) 모델 공간에 정적으로 종속되어 있습니다. 만약 프론트엔드가 사용자 프로필 페이지를 렌더링하기 위해 '사용자 정보', '최근 작성 게시글 목록', '팔로워 명단'이라는 3가지 뷰 컴포넌트를 필요로 한다면, REST를 엄격하게 따르는 이상 /users/1, /users/1/posts, /users/1/followers 라는 세 번의 완전히 독립적인 네트워크 라운드트립(Round Trip)을 호출해야만 합니다. 이처럼 필요한 데이터를 한 번에 가져올 수 없어 여러 번 API를 치는 현상을 언더페칭(Underfetching)이라고 부르며, 모바일 환경에서 치명적인 레이턴시 병목을 일으킵니다. 반면 어포던스를 위해 /users/1/profile-full 이라는 무거운 단일 엔드포인트를 열어주면, 정작 목록 화면 등에서 사용자 이름만 간단히 필요한 경우에도 불필요한 이미지 바이너리 경로와 텍스트까지 전부 받아와야 하는 데이터 낭비, 즉 오버페칭(Overfetching)의 늪에 빠지게 됩니다. 이 끔찍한 양극단의 강제적 설계 모순을 해결하기 위해 페이스북(Meta)에서 고안해 낸 명세가 바로 GraphQL입니다. GraphQL은 백엔드가 아닌, 순전히 클라이언트 어플리케이션 측에서 자신이 원하는 데이터 모델의 형태와 깊이(Depth)를 구체적인 쿼리 언어 블록으로 직접 명시하여 서버로 단발성 전송을 보냅니다. 백엔드는 이 쿼리 그래프를 파싱한 뒤, 각 필드에 매핑된 리졸버(Resolver) 함수들을 재귀적으로 순회 렌더링하여 클라이언트가 요구한 정확히 그 모양 그대로의 JSON 트리를 단 한 번의 단일 HTTP 응답으로 묶어 반환합니다. 이 그래프 탐색 로직은 무적병기가 아닙니다. GraphQL을 잘못 설계할 경우 해커나 클라이언트의 악의적인 버그로 인해 트리 깊이가 무한대로 치솟는(Deeply Nested Query) N+1 쿼리 폭탄을 백엔드 데이터베이스에 투하할 위험을 내재하고 있습니다. 이를테면 글, 글 작성자, 다시 그 작성자의 다른 글들을 무한히 호출하는 요청은 서버를 순식간에 물리적으로 마비시킬 수 있습니다. 이를 방어하기 위해 숙련된 API 엔지니어들은 Dataloader 유틸리티를 활용하여 쪼개진 개별 리졸버 호출들을 한 번의 글로벌 배치 단위로 합쳐서 SQL IN 예약어로 묶어 쿼리하도록 레이어를 구축하고, AST(Abstract Syntax Tree) 분석을 통해 쿼리의 복잡도 한계(Max Complexity)를 제한하는 엄격한 방어 스위칭 로직을 반드시 수반해야만 상용 수준의 마이크로서비스 무결성을 담보할 수 있습니다.