GraphQL API 설계와 구현: REST와 무엇이 다른가
GraphQL의 가치는 단순히 필요한 필드만 가져오는 데 있지 않습니다. 진짜 변화는 클라이언트가 응답 모양을 더 많이 통제하게 되면서, 서버가 실행 비용과 권한과 계약을 더 엄격하게 설계해야 한다는 점입니다.
그래서 GraphQL은 “REST를 한 엔드포인트로 합친 것”이 아니라, 별도의 실행 모델을 가진 API 계약 방식에 가깝습니다.
REST와 비교해 무엇이 달라지는가
REST에서는 보통 서버가 리소스 형태를 정하고, 클라이언트는 준비된 엔드포인트를 선택합니다. GraphQL에서는 서버가 스키마를 제공하고, 클라이언트가 그 스키마를 조합해 필요한 질의를 만듭니다.
이 차이는 다음 책임 이동을 만듭니다.
- 스키마 설계가 곧 제품 API 설계가 됨
- resolver 설계가 곧 실행 경로 설계가 됨
- 권한 검사가 필드와 관계 수준까지 내려감
- 성능 튜닝이 엔드포인트별 최적화에서 쿼리 형태 제어로 이동함
클라이언트 유연성은 커지지만, 서버는 더 이상 고정된 응답 형태를 전제로 운영할 수 없습니다.
스키마는 테이블 미러가 아니라 계약이어야 합니다
GraphQL API를 약하게 만드는 가장 흔한 실수는 데이터베이스 테이블 구조를 타입으로 그대로 노출하는 것입니다.
좋은 스키마는 비즈니스 개념과 클라이언트 사용 맥락을 반영합니다.
Order,Shipment,Invoice처럼 제품 언어를 사용- 필드 이름은 내부 컬럼명이 아니라 외부 계약 기준으로 설계
- 관계는 실제 화면 흐름과 조회 맥락을 반영
- deprecated 필드는 마이그레이션 대상 계약으로 관리
스키마가 persistence 구조를 그대로 닮기 시작하면, 내부 조인 구조와 리팩터링 흔적이 외부 API에 그대로 새어 나옵니다.
Resolver는 단순 구현 함수가 아니라 실행 계획의 일부입니다
Resolver 하나하나는 작아 보여도, 실제 요청에서는 이들이 조합되어 실행 계획을 만듭니다.
그래서 각 resolver는 최소한 다음을 의식해야 합니다.
- 어떤 데이터를 필요로 하는가
- DB 또는 외부 호출을 유발하는가
- batching에 참여하는가
- 오류를 어떤 방식으로 표면화할 것인가
스키마만 깔끔하고 resolver 설계가 느슨하면, GraphQL은 문서상으로만 우아하고 운영에서는 혼란스러운 시스템이 됩니다.
첫 번째 성능 문제는 대개 N+1입니다
GraphQL에서 가장 흔한 실전 성능 이슈는 CPU보다 resolver 단위의 반복 조회입니다.
예를 들어:
- 주문 50건을 조회
- 각 주문마다 고객 정보를 개별 조회
- 각 주문마다 라인 아이템을 다시 개별 조회
이렇게 되면 논리적으로는 한 요청이지만 실제로는 수십에서 수백 번의 DB 호출이 발생합니다.
실무에서는 보통 다음 전략이 필요합니다.
- 요청 범위 DataLoader 또는 동등한 batching 패턴 사용
- repository 계층을 set-based 조회 중심으로 설계
- resolver 내부에서 숨겨진 블로킹 I/O를 만들지 않기
- 엔드포인트 지연뿐 아니라 필드별 비용과 latency를 관측하기
N+1을 능동적으로 다루지 않으면 GraphQL은 금방 운영 비용이 높은 구조가 됩니다.
Mutation은 범용 저장보다 비즈니스 동사 중심이 좋습니다
GraphQL mutation은 saveUser, updateOrder처럼 범용 수정 API로 만들기보다, 비즈니스 행위를 드러내는 동사 중심으로 설계하는 편이 강합니다.
좋은 예:
placeOrdercancelSubscriptionapproveExpenseReport
약한 예:
updateOrdersaveUserpatchEntity
동사 중심 mutation은 검증 규칙, 권한, 감사 로그, 클라이언트 기대치를 더 명확하게 만듭니다.
권한은 엔드포인트 수준만으로 부족할 수 있습니다
REST에서는 라우트 수준 권한으로 충분한 경우가 많지만, GraphQL은 한 요청 안에서 서로 다른 필드와 중첩 관계를 동시에 조회할 수 있습니다.
그래서 보통 다음 계층을 함께 고려해야 합니다.
- operation 수준 권한
- 객체 수준 접근 제어
- 민감 필드에 대한 field-level 제한
- tenant 또는 ownership 기준 필터링
최상위 resolver에서만 권한을 검사하면, 하위 필드에서 의도치 않은 정보 노출이 일어나기 쉽습니다.
Query depth와 complexity는 운영 안전장치입니다
GraphQL의 표현력이 큰 만큼, 제어 장치가 없으면 그대로 운영 리스크가 됩니다.
실전에서는 보통 아래와 같은 통제가 필요합니다.
- 최대 query depth 제한
- weighted complexity 또는 field cost 제한
- persisted query 도입 검토
- 요청 본문 크기 제한
- timeout과 cancellation
이 제어는 선택 옵션이 아니라, 공개 API를 안전하게 운영하기 위한 기본 장치에 가깝습니다.
오류 처리 방식도 미리 정해야 합니다
GraphQL은 partial success를 허용하지만, 이것이 항상 장점으로만 작동하는 것은 아닙니다.
팀은 최소한 다음을 정해두는 편이 좋습니다.
- 어떤 실패는 필드 단위 null로 둘 것인가
- 어떤 실패는 전체 operation 실패로 볼 것인가
- 어떤 비즈니스 오류는 typed payload로 반환할 것인가
- 내부 오류는 어떻게 숨기면서도 추적 가능하게 남길 것인가
모든 오류를 단순한 GraphQL error 배열로만 보내면, 클라이언트와 운영팀 모두 문맥을 잃기 쉽습니다.
캐싱 전략은 REST와 다르게 생각해야 합니다
GraphQL은 over-fetching을 줄일 수 있지만, 고정 URL 기반 캐싱의 장점은 약해집니다. 여러 작업이 동일 엔드포인트를 공유하기 때문입니다.
그래서 캐싱은 보통 다음 쪽으로 이동합니다.
- 클라이언트의 normalized cache
- persisted query 키 기반 캐싱
- 참조 데이터에 대한 server-side resolver 캐시
- 하위 서비스 또는 federation 경계 캐시
즉, GraphQL이 성능을 자동으로 개선하는 것이 아니라 최적화 지점을 바꾼다고 보는 편이 정확합니다.
운영 전 체크리스트
운영 준비가 되었다고 말하려면 최소한 다음 질문에 답할 수 있어야 합니다.
- 가장 비싼 필드와 쿼리 패턴을 알고 있는가?
- 교차 엔터티 조회를 일관되게 batching하는가?
- depth와 complexity 제어가 있는가?
- 민감 필드가 최상위 resolver 아래에서도 보호되는가?
- mutation이 범용 수정이 아니라 비즈니스 행위 중심인가?
- 필드별 latency와 error rate를 관측하는가?
GraphQL이 잘 맞는 경우
다음과 같은 상황에서는 GraphQL이 특히 강합니다.
- 여러 클라이언트가 같은 도메인을 다른 모양으로 소비할 때
- 프론트엔드가 화면 구성을 빠르게 반복할 때
- 중첩 데이터 탐색이 제품 핵심일 때
- 잦은 버전 증가 없이 계약을 진화시키고 싶을 때
반대로 다음과 같은 경우에는 REST가 더 실용적일 수 있습니다.
- 도메인이 단순하고 리소스 중심일 때
- 안정적인 엔드포인트 캐싱이 더 중요할 때
- 실행 복잡도를 통제할 팀 역량이나 도구가 부족할 때
마무리
중요한 질문은 GraphQL이 REST보다 더 현대적인가가 아닙니다. 클라이언트 유연성을 얻는 대신 서버가 감당해야 할 실행 통제와 권한 통제 비용이 충분히 가치 있는가가 핵심입니다.
그 답이 yes라면 GraphQL은 매우 강력한 계약 모델이 됩니다. 아니라면 잘 설계된 REST API가 훨씬 단순하고 운영하기 쉽습니다.
Continue Reading
다음으로 읽기 좋은 글
비동기 작업 API의 멱등성과 상태 제어
긴 작업을 HTTP 요청 하나로 끝내지 않고 작업 생성, 재시도, 취소, 결과 조회까지 안정적으로 설계하는 방법을 정리합니다.
⚙️ Backend대용량 API 작업의 Job Status 패턴
오래 걸리는 백엔드 작업을 동기 API로만 다루면 사용자 경험과 운영 안정성이 함께 흔들립니다. Job status 패턴을 실전적으로 정리합니다.
💬 Language런타임 스키마 경계 실전 설계
TypeScript, Python, Java 같은 언어에서 정적 타입만으로 막기 어려운 외부 입력을 런타임 스키마로 보호하는 방법을 정리합니다.
🔧 ToolsPostman 실전 가이드: API 테스트, 자동화, 협업
Postman을 API 탐색 도구에서 끝내지 않고, 환경 관리, 컬렉션 구조, 공유 테스트 흐름, Newman 기반 CI 검증까지 실무적으로 사용하는 방법을 정리합니다.
다음 탐색