GraphQL 실행

GraphQL 실행 (Execution)

쿼리가 파싱·검증을 통과하면 서버가 그 요청을 실행해요. 실행 결과는 요청했던 쿼리 모양을 그대로 거울처럼 반영하는데, 그 과정을 주도하는 게 각 필드의 리졸버(resolver) 함수예요.

출처: https://graphql.org/learn/execution/

GraphQL의 핵심 질문은 "필드마다 value를 어떻게 주지?"인데, 답은 "각 타입의 각 필드에 리졸버 함수를 두고 거기서 데이터를 채운다"예요. 실행은 최상위 Query(또는 Mutation/Subscription) 필드부터 시작해서, 필드가 스칼라를 내면 그 자리에서 끝나고 객체를 내면 그 아래 선택 집합을 계속 내려가요. 쿼리는 항상 스칼라·이늄 리프에서 끝나요.

type Query {
  human(id: ID!): Human
}

type Human {
  name: String
  starships: [Starship]
}

human 필드의 리졸버는 흔히 데이터베이스를 조회해서 Human 객체를 만들어 돌려줘요. 리졸버는 (obj, args, context, info) 형식의 인자를 받아요.

  • obj: 이전 객체 (루트 Query 필드에서는 거의 안 씀)
  • args: 쿼리에서 해당 필드로 넘어온 인자
  • context: 모든 리졸버가 공유하는 컨텍스트
  • info: 해당 필드·스키마에 대한 메타정보 (고급 용도)

데이터베이스 로딩은 비동기라서 리졸버는 종종 Promise를 돌려줘요. 리스트 필드라면 Promise의 리스트를 돌려주는 식이에요.

function resolveHumanStarships(obj, args, context, info) {
  return Promise.all(
    obj.starshipIDs.map(id =>
      context.db.loadStarshipByID(id).then(shipData => new Starship(shipData))
    )
  );
}

각 필드가 해석되면 그 값은 "필드 이름(또는 alias) → 해석된 값" 형태의 키-값 맵에 담겨요. 이 과정이 리프 필드에서부터 아래서 위로 쌓여 최종 결과가 만들어져요. 요청한 쿼리 모양 그대로, 각 중첩 선택 집합 필드가 스칼라 리프 값으로 해석되는 거예요.

더 알아보기