🔷 GraphQL9. 실전 사례02 — GitHub Public API v4

02 — GitHub Public API v4

한 줄 답: GitHub은 2016년 9월 v4를 GraphQL로 공개하면서 cost-based rate limitschema previews를 함께 발표했다. 이 한 묶음이 그 뒤 모든 공개 GraphQL API의 청사진이 되었다. Facebook이 만든 도구외부에서도 운영 가능하다는 첫 증명이었다.


Why — 왜 GitHub 사례가 결정적인가

2015년 GraphQL이 공개됐을 때, 외부 개발자들의 첫 반응은 *“Facebook이니까 되는 거 아닌가”*였다. 외부에서 GraphQL을 공개 API로 운영한 회사가 없었으니, 공개 API 특유의 문제(rate limit, 인증, 버전 관리, 악의적 쿼리)를 GraphQL로 어떻게 풀지 아무도 몰랐다.

2016년 9월 14일, GitHub은 정확히 1년 전 같은 날에 공개된 spec을 그대로 받아 공개 API v4를 GraphQL로 발표한다. 동시에 어떻게 운영하는지를 문서로 풀어 공개했다. 이게 결정적이었다.

흔한 오해현실
”GitHub은 REST v3를 버리고 v4로 갔다”둘은 공존한다 — 같은 데이터를 두 API가 다른 방식으로 노출
”GraphQL이면 rate limit이 자동으로 해결된다”전혀 아니다 — GitHub이 직접 cost 알고리즘을 발명해서 풀었다
”공개 API GraphQL은 GitHub이 처음이자 거의 유일하다”2016년엔 그랬다. 지금은 Shopify·Atlassian·Yelp·Contentful 등 다수

GitHub의 문서·블로그·SDK·rate limit 알고리즘 공개 한 묶음이 외부 GraphQL API의 사실상 표준이 되었다.


How — 어떻게 운영하나

1) REST v3와 GraphQL v4의 공존

공존은 의도된 선택이다. GitHub이 v3를 deprecate하지 않는 이유:

  • 외부 통합(Slack·Jira·CI)이 수만 개다 — 한 번에 끊을 수 없음
  • REST는 예측 가능한 rate limitURL 기반 캐싱에서 여전히 강함
  • GraphQL은 복합 화면 페치에서 강함

→ “같은 데이터·두 API·서로 다른 use case”라는 모델이 그대로 표준이 됐다. Shopify도 같은 패턴(Storefront + Admin), Atlassian도 같은 패턴(REST + GraphQL gateway).

2) Point System Rate Limit

GraphQL은 쿼리 한 번이 REST 수천 번에 해당할 수 있다. “1초에 10번”으로 제한하면 그 한 번이 DB 전체를 긁는다. GitHub이 푼 방법 — 모든 쿼리에 비용 점수를 매기고, 시간당 5,000점을 준다.

핵심 알고리즘 (docs.github.com/en/graphql/overview/rate-limits-and-query-limits-for-the-graphql-api):

  1. Connection 필드마다 first/last 인자에서 요청한 노드 수를 본다.
  2. 부모-자식 connection은 으로 계산 (first: 100 × first: 50 → 5000 노드).
  3. 최종 점수는 노드 수의 제곱근에 비례 — 작은 쿼리는 1점, 큰 쿼리는 수십 점.
  4. 최소값은 1, 즉 어떤 쿼리도 0점은 아니다.

이 알고리즘은 클라이언트가 실제로 가져갈 데이터 크기가 아니라 서버가 계산해야 할 작업의 상한을 기준으로 한다. DoS 방어가 목적.

쿼리 안에서 직접 남은 점수를 조회할 수도 있다.

{
  rateLimit {
    limit       # 5000
    cost        # 이 쿼리의 점수
    remaining   # 남은 점수
    resetAt     # 다음 리셋 시각 (ISO 8601)
  }
}

3) Schema Previews — 버전 없이 베타 필드를 노출

REST는 /v1, /v2로 path를 갈아 끼우며 버전을 관리한다. GraphQL은 URL이 하나라서 그 방법을 못 쓴다. GitHub의 해법 — schema preview.

GET /graphql HTTP/1.1
Accept: application/vnd.github.merge-info-preview+json
  • 베타 단계의 필드는 preview accept 헤더를 보낸 클라이언트에게만 노출된다.
  • GA가 되면 헤더 없이도 보이게 풀린다.
  • 폐기 예정 필드는 @deprecated(reason: "...") 디렉티브로 표시 — 클라이언트가 introspection으로 미리 본다.

버전 없는 진화”라는 GraphQL 격언의 실전 운영 패턴이 여기 있다.

4) Query Complexity / Depth 제한

GitHub은 cost 외에도 정적 한계를 둔다 (docs.github.com 명시).

제한의미
Node limit500,000한 쿼리가 접근 가능한 노드 총합
Maximum aliases30같은 필드를 alias로 30번 이상 못 부름
Maximum directives50한 문서 안 directive 수
Maximum tokens5,120쿼리 문서 토큰 수
Query timeout10초단일 쿼리 실행 시간

이 정적 한계는 cost system을 우회하는 공격(작은 점수로 큰 부하)을 막는다. 두 layer 방어.

5) Naming Conventions

GitHub schema가 정착시킨 명명 관행은 그대로 업계 표준이 됐다.

패턴예시비고
Mutation = verbNouncreateIssue, closePullRequestREST의 동사+자원
Input type = VerbNounInputCreateIssueInput모든 mutation은 단일 input
Payload type = VerbNounPayloadCreateIssuePayload모든 mutation은 단일 payload
Connection = XxxConnectionIssueConnectionRelay Server spec
Edge = XxxEdgeIssueEdgeRelay Server spec
clientMutationId(Mutation input의 필드)Relay 호환

Relay spec을 충실하게 따른다 — 그 결과 Relay 클라이언트가 제로 설정으로 동작한다.


What — 구체 사양

공개된 운영 수치

항목출처
Rate limit (인증 사용자)5,000 points/hourdocs.github.com
Rate limit (GitHub App)12,500 + 50 per repo + 50 per user/hourdocs.github.com/en/apps/.../rate-limits-for-github-apps
Node limit500,000 nodes/querydocs.github.com
Query timeout10 secondsdocs.github.com
Endpointhttps://api.github.com/graphql(POST only)
AuthenticationPersonal access token, OAuth, GitHub App(header Authorization: bearer ...)
Schemaintrospection 가능(__schema)

첫 발표 (2016-09-14)

  • GitHub Universe 2016에서 공식 발표
  • The biggest change in our API since the company was founded” (GitHub 블로그 인용)
  • 동시에 GraphQL Explorer (현재 docs.github.com/en/graphql/overview/explorer) 공개 — 브라우저에서 직접 쿼리

Public API GraphQL이 해결 안 한 것

  • HTTP-level 캐시 (모든 요청 POST → CDN 캐시 불가) — 클라이언트 단 캐시로 의존
  • 페이지네이션 — Relay cursor만 — offset 없음
  • 실시간 — Webhooks에 위임 (subscription 없음, 2024 기준 공개 API)

What-if — 잘못 이해하면

1) “GitHub처럼 5,000 points/hour만 두면 된다”고 믿으면

→ 5,000은 GitHub 규모에 맞춰진 값이다. 점수 알고리즘limit 값은 분리해야 한다. 대응: 알고리즘은 차용하되 값은 부하 테스트로 결정. Shopify는 1,000 points/second (다른 모델).

2) Schema preview를 공식 stable로 오해하면

→ preview 필드는 어느 날 사라질 수 있다. 프로덕션에 쓰면 예고된 깨짐. 대응: preview 헤더가 필요한 필드는 실험 코드로만, GA는 deprecation policy 확인.

3) “GraphQL은 자동으로 안전하다”고 믿으면

→ GitHub은 cost + node limit + timeout + alias limit + token limit 5층 방어를 한다. 하나만 두면 우회당함. 대응: 이 KB의 07-security-governance 챕터 참고 — depth/complexity/cost는 별도 도구.

4) REST v3를 완전히 대체했다고 믿으면

→ webhook, OAuth app, GitHub Actions 메타데이터 일부는 여전히 REST 전용이다. 대응: 두 API의 기능 매트릭스를 확인. docs.github.com에 명시.

5) “Connection pagination 없이도 된다”고 믿으면

→ GitHub 모든 list 필드는 Relay connection이다 — nodes/edges/pageInfo/totalCount. offset pagination이 아예 없다. 대응: 처음부터 cursor 기반으로 클라이언트 작성.


Insight — 흥미로운 이야기

”발표 1년 만에 spec 위원회의 외부 referee가 되다”

GitHub은 2018년 GraphQL Foundation의 founding member로 합류한다. Facebook 외의 회사로서 GraphQL spec에 정식 발언권을 가진 첫 회사 중 하나. 그 발언권의 핵심 근거가 *“우리는 공개 API로 운영해 봤다”*였다. spec에 cursor pagination@deprecated reason이 깔끔히 정리된 데에는 GitHub의 운영 경험이 반영됐다.

”GraphQL Explorer가 만든 학습 경로”

GitHub의 GraphQL Explorer(docs.github.com/en/graphql/overview/explorer)는 로그인하면 자기 데이터로 바로 실험할 수 있다. GraphiQL의 변형인데, “내 repo”가 응답에 뜨는 경험이 너무 강력해서 — 수많은 개발자가 GraphQL을 GitHub에서 처음 만났다. “GitHub에서 처음 써봤다”는 회고가 컨퍼런스에서 흔하다.

”Point system은 사실 MySQL 부하 추정이다”

GitHub 엔지니어 인터뷰들을 종합하면, point 알고리즘은 연결된 connection의 노드 수를 기준으로 MySQL/ElasticSearch/Git에 가해질 부하의 상한을 추정한다. 즉 클라이언트가 받을 데이터 크기가 아니라 서버가 계산할 작업량이 기준. 이건 공개 API에서만 합리적인 모델 — 내부 API라면 실제 측정값으로 가도 된다.

”버전을 없앤 대가는 deprecation 정책의 엄격함

GitHub의 schema는 18~24개월 deprecation period를 둔다. preview에서 GA, GA에서 deprecated, deprecated에서 removal까지 공개 일정. URL 버전을 없앤 대가가 이 deprecation governance다 — 자동으로 되는 게 아니라 정책으로 만든다.


요약 + 다이어그램

GitHub은 v4를 공개 GraphQL의 첫 운영 사례로 만들었고, cost system + schema preview + Relay 명명 컨벤션을 표준으로 굳혔다. REST와의 공존, 5층 방어, deprecation governance 세 패턴이 그 뒤 모든 공개 GraphQL API에 복사됐다.

참고 자료

  • Rate limits and query limits for the GraphQL APIdocs.github.com/en/graphql/overview/rate-limits-and-query-limits-for-the-graphql-api
  • GraphQL API documentationdocs.github.com/en/graphql
  • GraphQL Explorerdocs.github.com/en/graphql/overview/explorer
  • Rate limits for GitHub Appsdocs.github.com/en/apps/creating-github-apps/registering-a-github-app/rate-limits-for-github-apps
  • GitHub Universe 2016 announcement — (github.blog archives)

다음 문서: 03-shopify-storefront-api.mdx — GitHub의 cost system을 e-commerce 트래픽에 맞춰 진화시킨 사례.