GraphQL Federation 직접 부딪히며 배우기

2025. 9. 23. 03:08·Learnings
반응형

회사에서 내가 구축한 영상 이해 데이터 플랫폼의 연장으로, 브랜드 대시보드 프로젝트를 진행하면서 GraphQL과 Apollo Federation을 본격적으로 다뤘다.

그 과정에서 Federation 환경의 GraphQL 서버를 개발하며 느낀 것들을 담아봤다


GraphQL에 대한 오해

GraphQL은 흔히 overfetching(불필요한 데이터까지 가져오는 문제)과 underfetching(한 번에 필요한 데이터를 다 못 가져오는 문제)을 해결한다고 설명된다.

 

처음에 내가 잘못 생각했던 부분은, “각 요청마다 딱 맞는 스키마를 계속 추가해야 한다”라고 생각한 것이다.

즉, 상황별로 최적화된 쿼리와 응답을 위해 스키마를 세분화·확장하는 방식이 맞다고 여겼다.

설계를 하면서는 내가 정말 잘 하고 있다고 생각했고, 깔끔하다고 느끼기까지 했다.

하지만 리더의 리뷰를 받으며 “기존 거 최대한 그대로 쓸 수 있게 고민해 봐라” 라는 말을 듣고, 이유도 들을 필요 없이 이건 GraphQL 철학과 맞지 않다는 걸 바로 깨닫게 되었다.

 

내가 설계했던 방식대로 하면 스키마와 쿼리가 기하급수적으로 늘어나 관리가 불가능해진다.

GraphQL의 진짜 장점은 스키마를 계속해서 늘리는 것이 아니라 (어떻게 보면 맞기도 하다.),

하나의 스키마에서 클라이언트가 원하는 필드를 선택할 수 있다는 점에 있다는 걸 뒤늦게 이해했다.


쿼리 단순화

처음에는 대시보드 기능을 위해 쿼리를 세 개나 두려고 했다.

하지만 분석해보니 세 번째 쿼리는 두 번째 쿼리의 부분집합이었다.

# 원래 생각했던 구조
query getBrandVideos { ... }
query getBrandVideosStatDetail { ... }
query getBrandVideosDailyStat { ... } # 사실상 부분집합

결국 두 번째와 세 번째 쿼리를 합쳐, 총 두 개의 쿼리만으로 충분히 커버할 수 있었다.

이로 인해 개발/관리할 쿼리가 두 개가 되면서 편해지기도 했고, 코드 자체도 로직이 효율적으로 합쳐지며 깔끔해졌다.

GraphQL의 장점을 잘 살린 사례가 아닐까..? 싶다.


Federation 구조와 제약

이 작업에서는 총 3개의 서버가 상호작용을 하는데, 그 중 두 개는 아래와 같다.

  • info 서버: 원본 데이터베이스의 내용을 GraphQL로 그대로 노출. 서비스의 일반적인 View의 응답 담당
  • brand 서버: 브랜드 관련 기능(가공, 확장, 통계 등) 담당

회사의 모든 서버는 Apollo Federation으로 묶였고, gateway가 각 subgraph의 스키마를 조합해 클라이언트에 제공한다.

여기서 중요한 점은 federation의 위임 방식이다.

예를 들어, brands 필드는 gateway가 해당 스키마를 정의한 subgraph(여기서는 info 서버)에 요청을 넘긴다.

즉, 내 brand 서버에서는 brands 내부 데이터를 직접 필터링하거나 가공할 수 없다.

 

내 서버에서 특정 조건에 맞는 브랜드만 필터링해 반환하고 싶었는데,

brands 필드의 제어권은 info 서버에 있기 때문에 brand 서버에서 할 수 있는 방법은 새로운 필드를 정의하는 것뿐이었다.

그래서 filteredBrands라는 스키마를 별도로 구성하였다.

# 예시: 특정 ID에 맞는 브랜드만 필터링
query getFilteredBrands {
  filteredBrandsById(id: "b1") {
    id
    name
    sentiment
  }
}

여기서도 GraphQL이 정말 유연하다는 것을 느꼈는데, 저 filteredBrands 스키마는 한 영상 내에서 ‘언급된 브랜드’에 대한 데이터만 필터링해 보여주는 필드였다.

“영상 정보”의 일환인데, 일반적으로는 다른 영상 정보에서 필요한 필드를 지정하고, filteredBrands와 합쳐서 응답을 보내주는 방식으로 구성하게 될 것이다.

하지만 GraphQL Federation에서는, 특정 필드만 지정하는 게 아니고 기존 영상 정보와 ‘결합’되도록 구성할 수 있었다.

extend type Video @key(fields: "videoId") {
  videoId: ID! @external
  filteredBrands(brandId: String): [Brand]
}

이렇게 구성하면, 클라이언트는 갑자기 영상 내 다른 필드가 필요할 때에도 서버 수정 없이 바로 응답을 받을 수 있고, 영상 내 새로운 필드가 추가되어도 일일이 반영할 필요가 없다.


Lessons Learned

  1. GraphQL 철학에 대한 이해
    • Overfetching/underfetching 문제는 필드 선택권으로 해결된다.
    • 요청마다 최적화된 스키마를 새로 정의하는 방식은 오히려 관리 지옥으로 이어진다.
  2. GraphQL Federation 환경에 대한 이해
    • Federation에서는 각 subgraph가 맡은 필드에 다른 서버가 개입할 수 없다.
    • 따라서 가능한 한 기존 스키마의 조합으로 쿼리를 설계하는 게 건강하다.
    • 불가피하게 새로운 스키마를 정의해야 한다면, 기존 스키마를 확장하는 방식으로 유연하게 설계할 수 있다.
반응형

'Learnings' 카테고리의 다른 글

오픈서치(엘라스틱서치) 인덱스와 매핑, 그리고 리인덱싱  (0) 2025.09.05
MongoDB로 동시성과 상태 관리하기  (0) 2025.09.04
'Learnings' 카테고리의 다른 글
  • 오픈서치(엘라스틱서치) 인덱스와 매핑, 그리고 리인덱싱
  • MongoDB로 동시성과 상태 관리하기
g-hyeong
g-hyeong
  • g-hyeong
    Ghyeong
    g-hyeong
  • 전체
    오늘
    어제
  • 인기 글

    • 전체보기 (9)
      • Productivity (1)
        • Task Managemant (1)
        • AI utilization (0)
      • Projects (2)
        • MCP (2)
      • Study (3)
        • MCP (2)
        • LLM (1)
      • Personal (0)
      • Learnings (3)
  • 반응형
  • hELLO· Designed By정상우.v4.10.4
g-hyeong
GraphQL Federation 직접 부딪히며 배우기
상단으로

티스토리툴바