GraphQL 실행
GraphQL 실행 (Execution)
쿼리가 파싱·검증을 통과하면 서버가 그 요청을 실행해요. 실행 결과는 요청했던 쿼리 모양을 그대로 거울처럼 반영하는데, 그 과정을 주도하는 게 각 필드의 리졸버(resolver) 함수예요.
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) → 해석된 값" 형태의 키-값 맵에 담겨요. 이 과정이 리프 필드에서부터 아래서 위로 쌓여 최종 결과가 만들어져요. 요청한 쿼리 모양 그대로, 각 중첩 선택 집합 필드가 스칼라 리프 값으로 해석되는 거예요.
더 알아보기
- 실행 전 단계인 검증이 궁금하다면: Validation
- 루트 타입과 스키마 정의: Schemas and Types