02 — GitHub Public API v4
한 줄 답: GitHub은 2016년 9월 v4를 GraphQL로 공개하면서 cost-based rate limit과 schema 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 limit과 URL 기반 캐싱에서 여전히 강함
- 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):
- Connection 필드마다
first/last인자에서 요청한 노드 수를 본다. - 부모-자식 connection은 곱으로 계산 (
first: 100×first: 50→ 5000 노드). - 최종 점수는 노드 수의 제곱근에 비례 — 작은 쿼리는 1점, 큰 쿼리는 수십 점.
- 최소값은 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 limit | 500,000 | 한 쿼리가 접근 가능한 노드 총합 |
| Maximum aliases | 30 | 같은 필드를 alias로 30번 이상 못 부름 |
| Maximum directives | 50 | 한 문서 안 directive 수 |
| Maximum tokens | 5,120 | 쿼리 문서 토큰 수 |
| Query timeout | 10초 | 단일 쿼리 실행 시간 |
이 정적 한계는 cost system을 우회하는 공격(작은 점수로 큰 부하)을 막는다. 두 layer 방어.
5) Naming Conventions
GitHub schema가 정착시킨 명명 관행은 그대로 업계 표준이 됐다.
| 패턴 | 예시 | 비고 |
|---|---|---|
Mutation = verbNoun | createIssue, closePullRequest | REST의 동사+자원 |
Input type = VerbNounInput | CreateIssueInput | 모든 mutation은 단일 input |
Payload type = VerbNounPayload | CreateIssuePayload | 모든 mutation은 단일 payload |
Connection = XxxConnection | IssueConnection | Relay Server spec |
Edge = XxxEdge | IssueEdge | Relay Server spec |
clientMutationId | (Mutation input의 필드) | Relay 호환 |
Relay spec을 충실하게 따른다 — 그 결과 Relay 클라이언트가 제로 설정으로 동작한다.
What — 구체 사양
공개된 운영 수치
| 항목 | 값 | 출처 |
|---|---|---|
| Rate limit (인증 사용자) | 5,000 points/hour | docs.github.com |
| Rate limit (GitHub App) | 12,500 + 50 per repo + 50 per user/hour | docs.github.com/en/apps/.../rate-limits-for-github-apps |
| Node limit | 500,000 nodes/query | docs.github.com |
| Query timeout | 10 seconds | docs.github.com |
| Endpoint | https://api.github.com/graphql | (POST only) |
| Authentication | Personal access token, OAuth, GitHub App | (header Authorization: bearer ...) |
| Schema | introspection 가능 | (__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 API —
docs.github.com/en/graphql/overview/rate-limits-and-query-limits-for-the-graphql-api - GraphQL API documentation —
docs.github.com/en/graphql - GraphQL Explorer —
docs.github.com/en/graphql/overview/explorer - Rate limits for GitHub Apps —
docs.github.com/en/apps/creating-github-apps/registering-a-github-app/rate-limits-for-github-apps - GitHub Universe 2016 announcement — (
github.blogarchives)
다음 문서:
03-shopify-storefront-api.mdx— GitHub의 cost system을 e-commerce 트래픽에 맞춰 진화시킨 사례.