GraphQL 요청은 문자열을 그대로 실행하는 것이 아닙니다. 서버는 문서를 토큰과 추상 구문 트리(AST)로 파싱하고, 스키마에 맞는지 검증한 뒤 작업을 실행합니다. GraphQL 명세는 언어와 실행 규칙을, 별도의 GraphQL over HTTP 작업 초안은 HTTP로 주고받는 방법을 설명합니다.

AST는 문서의 구조를 보존한다

예를 들어 query { user(id: "7") { name posts { title } } }는 텍스트 안의 필드, 인자, 중첩 선택을 구조화합니다. 파서는 문법을 확인하고 AST를 만들며, 검증기는 user 필드가 스키마에 있는지, 인자 타입이 맞는지, 필요한 하위 필드가 선택되었는지 검사합니다. 문법적으로 파싱되었다고 실행 가능한 요청이라는 뜻은 아닙니다. AST 자체도 데이터베이스 질의나 최적화된 실행 계획을 자동으로 보장하지 않습니다. 실제 resolver 호출 방식은 서버 구현에 달려 있습니다.

검증을 통과한 뒤 필드 resolver가 동작한다

서버는 요청된 작업과 변수 값을 정하고, 각 선택 필드에 연결된 resolver를 통해 값을 얻어 응답 형태로 완성합니다. 쿼리의 최상위 선택은 병렬화가 허용되지만, mutation의 최상위 필드는 부작용 간 순서를 지키도록 직렬 실행해야 합니다. 이는 같은 문서 안의 mutation 순서에 관한 규칙이지, 여러 클라이언트 요청 전체를 순서대로 처리한다는 보장은 아닙니다.

예를 들어 user와 posts를 함께 조회하는 요청에서 각 post의 author를 따로 불러오면 데이터베이스 왕복이 반복될 수 있습니다. DataLoader의 batch loader는 같은 실행 구간의 여러 키를 모아 한 번의 조회로 줄일 수 있습니다. 배치 함수가 요청받은 키 순서에 맞는 결과 배열을 반환하는지도 확인해야 합니다. 이 방법은 GraphQL 명세의 필수 실행 기능이 아니라 데이터 접근 계층의 최적화입니다.

POST만 가능한가? GET도 쓸 수 있다

GraphQL 언어 명세는 HTTP를 전송 방식으로 강제하지 않습니다. GraphQL over HTTP의 현재 작업 초안은 서버가 POST를 지원해야 하며 GET도 지원할 수 있다고 규정합니다. GET에서는 문서와 변수를 URL query에 인코딩할 수 있지만 mutation 실행에는 GET을 사용하면 안 됩니다. URL 길이 제한이나 민감한 변수가 주소·로그에 남는 점도 고려하세요. 실제 API가 어떤 전송 방식을 지원하는지 서버 문서를 확인합니다.

타입과 introspection은 권한 검사가 아니다

스키마 타입은 데이터 모양과 입력 제약을 표현하지만, 사용자가 특정 레코드나 필드를 볼 권한까지 자동으로 부여하지 않습니다. resolver나 서비스 계층에서 인증된 주체와 대상 리소스의 관계를 검사해야 합니다. Apollo GraphOS Router의 authorization 지시자는 해당 제품의 기능 예시이지 GraphQL 언어 자체의 보편적 지시자가 아닙니다.

Introspection은 스키마 구조를 살펴보는 표준 기능입니다. 운영환경에서 끄는 구성도 흔하지만 모든 서버가 반드시 비활성화해야 한다는 명세 규칙은 아닙니다. GraphQL 공식 학습 자료도 introspection 제한을 인증·인가, operation safelist, 복잡도·깊이 제한 등과 함께 고려하라고 설명합니다. 노출 여부 하나만으로 API 보안을 판단하지 마세요.

실행 지연과 데이터 노출을 함께 점검하기

요청이 깊거나 같은 필드를 반복 확장하면 resolver 호출이 커질 수 있으므로 실제 스키마에서 query depth, alias 수, 복잡도, timeout을 측정해 제한을 설계합니다. 사용자별 데이터를 캐시하는 DataLoader는 요청마다 만들어 컨텍스트에 연결해야 다른 사용자의 캐시 결과가 섞일 위험을 줄입니다. 이는 DataLoader 운영 지침이며 모든 GraphQL 구현의 자동 보안 기능은 아닙니다.

참고 자료