GraphQL 쿼리 깊이 제한을 올바르게 하는 방법

발행: (2026년 1월 16일 오전 04:20 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

graphql‑safe‑depth 소개

GraphQL은 강력하고 유연하며 표현력이 풍부하지만, 쿼리가 적절히 제한되지 않으면 그 유연성이 오히려 위험 요소가 될 수 있습니다.
너무 깊은 쿼리는 과도한 리졸버 실행, 높은 메모리 사용량, 혹은 서비스 거부(DoS) 상황을 초래할 수 있습니다.

이 글에서 배우게 될 내용:

  • 깊은 GraphQL 쿼리가 실제로 문제가 되는 이유
  • 기존의 많은 깊이 제한 솔루션이 부족한 이유
  • graphql‑safe‑depth가 문제에 접근하는 차별화된 방법
  • Apollo Server와 NestJS에서 사용하는 방법
  • 다른 보안 조치와 결합하는 시점 및 방법

🚨 문제: 깊은 GraphQL 쿼리

query {
  user {
    posts {
      comments {
        author {
          profile {
            avatar {
              url
            }
          }
        }
      }
    }
  }
}

첫눈에 보기에는 무해해 보이지만, 다음과 같은 문제를 일으킬 수 있습니다:

  • N+1 쿼리 폭발을 유발함
  • CPU와 메모리를 크게 소비함
  • 의도적이든 아니든 DoS 벡터가 될 수 있음

GraphQL은 기본 깊이 또는 복잡도 제한을 설정하지 않습니다.

🤔 기존 솔루션이 부족한 이유

IssueDescription
❌ Counting fields instead of execution depth일부 라이브러리는 전체 필드 수를 세어 가장 깊은 실행 경로를 파악하지 않아 오탐이나 혼란스러운 동작을 일으킵니다.
❌ Breaking introspectionintrospection 쿼리(__schema, __type, __typename)는 본질적으로 깊을 수 있으며 차단되어서는 안 됩니다.
❌ Hard to reason about특정 구현은 커스터마이징, 디버깅, 팀에 설명하기가 어렵습니다.

✅ 접근 방식: graphql‑safe‑depth

graphql‑safe‑depth는 한 가지에 집중한 가벼운 GraphQL 검증 규칙입니다:

  • 🧠 가장 깊은 리졸버 경로 측정
  • 🔍 기본적으로 introspection 필드 무시
  • 🧩 프래그먼트 완전 지원
  • ⚡ 런타임 의존성 제로
  • 🛠 TypeScript‑first, JavaScript‑friendly

작동 원리

  1. 라이브러리가 GraphQL의 validation phase에 훅을 겁니다.
  2. 쿼리 AST를 순회합니다.
  3. 중첩된 필드 선택을 기반으로 깊이를 계산합니다.
  4. 최대 실행 깊이를 추적합니다.
  5. 깊이가 maxDepth를 초과하면 실행 전에 쿼리를 거부합니다.

깊이 계산 예시

✅ 유효한 쿼리 (깊이 = 3)

query {
  user {
    profile {
      name
    }
  }
}

❌ 유효하지 않은 쿼리 (깊이 = 4)

query {
  user {
    profile {
      address {
        city
      }
    }
  }
}

가장 깊은 실행 경로만 중요합니다 — 전체 필드 수는 중요하지 않습니다.

🚀 사용 예시

Apollo Server (Node.js)

import { ApolloServer } from "apollo-server";
import { createDepthLimitRule } from "graphql-safe-depth";

const server = new ApolloServer({
  typeDefs,
  resolvers,
  validationRules: [
    createDepthLimitRule({ maxDepth: 3 }),
  ],
});

Apollo Server (NestJS)

import { createDepthLimitRule } from "graphql-safe-depth";

GraphQLModule.forRoot({
  autoSchemaFile: true,
  validationRules: [
    createDepthLimitRule({ maxDepth: 3 }),
  ],
});

⚙️ 설정 옵션

createDepthLimitRule({
  maxDepth: number;               // required
  ignoreIntrospection?: boolean; // default: true
  message?: (depth: number, maxDepth: number) => string; // optional
});
  • maxDepth – 허용되는 최대 실행 깊이.

    createDepthLimitRule({ maxDepth: 3 });
  • ignoreIntrospectiontrue인 경우 introspection 필드가 무시됩니다.

    createDepthLimitRule({
      maxDepth: 3,
      ignoreIntrospection: false,
    });
  • message – 사용자 정의 검증 오류 메시지.

    createDepthLimitRule({
      maxDepth: 3,
      message: (depth, max) =>
        `Query depth ${depth} exceeds the allowed maximum of ${max}`,
    });

🔐 보안 고려 사항

Depth limiting은 만능 해결책은 아니지만, 다음과 함께 사용하면 효과적입니다:

  • ✅ Query complexity limits
  • ✅ Proper authentication & authorization
  • ✅ Rate limiting
  • ✅ Caching and batching (e.g., DataLoader)

graphql‑safe‑depth는 한 가지를 잘 수행하는 데 집중합니다 — 예측 가능한 방식으로 위험하게 깊은 쿼리를 방지합니다.

📦 설치

npm i graphql-safe-depth

🔗 링크

  • GitHub 저장소:
  • npm 패키지:

🧠 최종 생각

이 라이브러리는 학습용 연습으로 시작했으며, 안정적인 v1.0.0 릴리스를 갖춘 프로덕션‑준비 도구로 발전했습니다. 프로덕션 환경에서 GraphQL을 사용하고 간단하고 예측 가능한 깊이 제한이 필요하다면 graphql‑safe‑depth가 좋은 선택이 될 수 있습니다.

피드백, 이슈, 그리고 기여를 언제든 환영합니다! 🙌

Back to Blog

관련 글

더 보기 »

2025년 나의 Node.js API 모범 사례

Node.js는 이제 10년 넘게 프로덕션 API를 구동해 왔으며, 2025년이 되면서 더 이상 “새롭다”거나 실험적인 것이 아니라 인프라가 되었습니다. 그 성숙도는 c...

2015년처럼 API를 작성하지 마세요

우리는 2025년에 살고 있으며, 많은 코드베이스가 여전히 API를 단순히 “JSON을 반환하는 엔드포인트”로만 취급합니다. API 설계가 기본 CRUD 라우트를 넘어 발전하지 않았다면, 당신은 sacr…