pile·
백엔드·카카오 스타일 (지그재그)카카오 스타일 (지그재그)·

GraphQL 이해하기: (3) 리졸버의 이해

GraphQL 연재 3편으로, 클라이언트 요청에 맞는 데이터를 실제로 반환하는 리졸버를 다룬다. 리졸버가 모든 필드마다 상위에서 하위 순으로 호출되고, 정의하지 않은 필드는 기본 리졸버가 처리한다는 원리를 이해하면 결과를 원하는 대로 조작할 수 있다는 게 요지다. REST 컨트롤러와 무엇이 다른지도 함께 정리한다.

핵심 포인트
  • 리졸버는 필드 요청이 들어왔을 때 그 값을 제공하는 함수다. Java 진영에서는 데이터 페처라고 부른다.
  • 스키마와 리졸버는 분리하는 편이 유지보수에 낫다. Node.js 는 GraphQL Tools 의 addResolversToSchema, Java 는 GraphQLCodeRegistry 가 그 분리를 돕는다.
  • 리졸버는 요청된 모든 필드에 대해 호출되며 상위 필드부터 하위 필드 순으로 실행된다. 같은 레벨의 순서는 보장되지 않고, 사이드 이펙트가 있는 Mutation 만 순서대로 실행된다.
  • 직접 정의하지 않은 필드는 기본 리졸버가 맡는다. 상위 필드가 반환한 객체에서 같은 이름의 프로퍼티를 꺼내주는 것이 전부다.
  • REST 컨트롤러는 최상위 요청만 처리하지만 GraphQL 은 하위 필드에도 리졸버를 붙일 수 있다. 그 필요가 없다면 굳이 GraphQL 을 쓸 이유가 없다고 못 박는다.
상세 정리
  • 비동기로 데이터를 가져와야 하면 Promise 를 반환하면 된다. graphql 라이브러리가 이행을 기다렸다가 값을 넘긴다.
  • REST 와의 대응 관계: GET 은 Query, POST 와 PUT, DELETE 는 Mutation 에 해당한다.
  • 이름 짓기가 다르다. GraphQL 은 동사가 분리돼 있지 않아 API 이름을 함수명처럼 짓고, REST 는 명사를 신경 써 그룹화하고 컨트롤러도 그에 맞춰 나눈다. GraphQL 은 경로와 네임스페이스 개념이 없어 리졸버를 알아서 나눠야 한다.
  • GraphQL 은 타입 체크가 내장되고 반환 형태가 일정하지만, HTTP 상태 코드를 쓰지 않아 리소스 없음과 권한 없음 같은 구분이 표준화돼 있지 않다.
  • 예시 스키마는 Post 와 User 다. 순수 REST 라면 getPosts 가 author_id 만 주고 별도로 getUser 를 부르는 게 자연스럽지만, 실제로는 효율을 위해 author 도 같이 반환하되 목록에 필요 없는 전화번호는 빼게 된다. 결국 Post.author 의 User 와 Query.getUser 의 User 는 사실상 다른 타입이 된다.
  • GraphQL 에서는 그 두 타입이 자연스럽게 하나로 이어지고, author 가 필요한 클라이언트만 요청해 요청받을 때만 DB 에 접근할 수 있다.
  • 호출 순서 분석: 예시 쿼리 하나에 대해 Query.getPosts 부터 getPosts 각 항목의 author.name 까지 필드마다 리졸버가 불린다. 직접 정의한 것은 그중 5개뿐이고 나머지는 전부 기본 리졸버가 처리한다.
  • 기본 리졸버 구현: GraphQL.js 의 defaultFieldResolver 는 source 가 객체 같거나 함수일 때 해당 필드명의 프로퍼티를 꺼내고, 그 값이 함수면 호출한다. Java 는 PropertyDataFetcher 가 같은 일을 한다.
  • 응용: User 타입에 name 리졸버를 추가해 소문자로 바꾸면 getPosts 결과와 getUser 결과 양쪽에 모두 적용된다.
  • 데이터는 어느 리졸버가 반환해도 된다. Post.author 대신 getPosts 가 author 를 붙여 반환해도 결과는 같지만, Post 를 반환하는 다른 API 가 있으면 그쪽에도 같은 구현을 넣어야 한다.
  • 중복 호출 함정: getPosts 가 이미 author 를 담아 반환하는데 Post.author 리졸버도 정의돼 있으면 그 리졸버가 또 호출된다. author 를 구하며 DB 에 접근한다면 중복 조회가 된다. source.author 가 있으면 그대로 쓰도록 조건을 넣어 막는다.
  • 같은 스키마를 GraphQL Java 로 구현한 예도 함께 실어 표현 방식은 달라도 리졸버 원리가 동일함을 보인다.
왜 읽나GraphQL 을 REST 처럼 얕게 쓰고 있던 백엔드 개발자에게 리졸버 호출 규칙과 중복 조회 함정을 짚어주는 글.
카카오 스타일 (지그재그)
카카오 스타일 (지그재그) 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 백엔드·twilio-engTwilio Engineering·

    Programmable Messaging에서 Verify API로 마이그레이션하기

    Twilio의 Programmable Messaging API로 자체 OTP 솔루션을 운영하던 서비스가 Verify API로 전환하는 방법을 코드 예시와 함께 설명한다. Verify는 OTP 전송·검증을 위한 전용 API로, 전화번호 구매, 토큰 생성, DB 저장·만료 관리를 내부에서 처리해 개발자가 직접 구현할 코드를 크게 줄인다.

    요약 이어보기
    #authentication#twilio#sms+2
  2. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 2부

    포스타입 백엔드 엔지니어가 벡터 기반 개인화 추천 시스템을 실제 운영하며 맞닥뜨린 성능 장애와 용량 문제를 해결한 과정을 담은 2부다. 수백만 개의 벡터 KNN 검색이 피크 시간대에 전체 Elasticsearch 검색 성능을 흔드는 문제부터 클러스터 OOM 사태까지, 쿼리 최적화와 인프라 분리 두 가지 경로로 근본 해결에 이른다.

    요약 이어보기
    #elasticsearch#vector-search#recommendation-system+2
  3. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 1부

    포스타입이 태그 기반 추천의 한계를 극복하고 벡터 임베딩 기반 개인화 추천 시스템을 구축한 과정을 담은 1부다. 유사한 콘텐츠가 다른 용어를 쓰거나 동일한 태그가 전혀 다른 톤의 콘텐츠를 가리키는 문제를 임베딩 벡터로 해결하고, OpenSearch의 HNSW ANN 검색으로 수백만 벡터를 실시간 검색하는 시스템을 구축해 구매율 15% 향상을 달성했다.

    요약 이어보기
    #opensearch#vector-search#recommendation-system+2