Files
llm-wiki/raw/company-tech-blogs/github-graphql-global-node-id.md
T

104 lines
9.6 KiB
Markdown

---
title: company-tech-blog / GitHub GraphQL Global Node IDs — Relay-style base64 opaque ID 패턴
source_type: company-tech-blog
url: https://docs.github.com/en/graphql/guides/using-global-node-ids
archive_url:
vendor: GitHub
related_branches: [feature-resource-identifier-contract]
related_projects: [ca-skeleton]
tags: [company-tech-blog, ca-skeleton, api-design, api-contract]
created: 2026-05-31
---
# GitHub GraphQL Global Node IDs — Relay-style base64 opaque ID 패턴
> Layer: `raw/company-tech-blogs/` — GitHub GraphQL API 가이드 원문 발췌 + migration blog 발췌.
> 공식 API 문서이나 *GitHub 특유의 구현 관례*를 다루는 가이드 페이지이므로 `company-tech-blog` 분류.
> 검증된 요약은 `/ingest` 후 `wiki/concepts/` 에 별도 작성.
## Parent / 활용 branch
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| [[raw/branch-notes/feature-resource-identifier-contract]] | D6 (prefix 정책) — base64 인코딩으로 type 정보를 ID 안에 인코딩하는 사례; D11 (Public ID vs Internal Sequence) — external = base64(type:internal_id), internal = numeric; D13 (multi-tenancy / type encoding) — ID 내부에 type 정보 포함 패턴 |
## 출처 / Source
- 원본 URL: https://docs.github.com/en/graphql/guides/using-global-node-ids
- 보조 URL (migration blog): https://github.blog/2020-10-27-graphql-global-id-migration-update/
- 아카이브 URL: (미확보)
- 저자 / 조직: GitHub (migration blog 저자: Andrew Hoglund @ahoglund)
- 발행일: 공식 docs — 미명시 (지속 업데이트); migration blog — 2021-11-16 (2024-07-23 업데이트)
- 마지막 확인일: 2026-05-31
## 왜 저장했는지 / Why archived
GitHub GraphQL API 는 모든 객체에 `node_id` (= base64 인코딩된 `type:numeric_id`) 를 부여하는 Relay-style global ID 패턴을 사용한다. 이 자료는 ca-skeleton 의 Public ID vs Internal Sequence 분리(D11), ID 내 type 인코딩(D6/D13), opaque ID 취급 정책의 실무 선례로 저장된다. 단, GitHub 의 legacy base64 인코딩은 현재 deprecated(새 opaque 포맷으로 교체 중)이므로, *구체 포맷* 이 아닌 *패턴의 사례* 로만 활용해야 한다.
## 핵심 인용 / Key quotes (verbatim)
> [§ Using global node IDs — intro] "You can get global node IDs of objects via the REST API and use them in GraphQL operations."
> (line 8 in /tmp/source-fetch-1780197188.txt)
> [§ Note] "In REST, the global node ID field is named node_id . In GraphQL, it's an id field on the node interface. For a refresher on what "node" means in GraphQL, see Introduction to GraphQL ."
> (line 13 in /tmp/source-fetch-1780197188.txt)
> [§ Step 1 — REST response example] `"node_id" : "MDQ6VXNlcjU4MzIzMQ=="` — 이 값을 base64 decode 하면 `04:User583231` (format: `<version_byte>:<TypeName><numeric_id>`)
> (line 75 in /tmp/source-fetch-1780197188.txt)
> [§ Step 3 — Using global node IDs in migrations] "When building integrations that use either the REST API or the GraphQL API, it's best practice to persist the global node ID so you can easily reference objects across API versions."
> (line 108 in /tmp/source-fetch-1780197188.txt)
> [§ Migration blog — Do I need to do anything?] "If you currently decode IDs, your service may break as the underlying data format of the IDs has changed. We suggest you migrate your service to treat these IDs as opaque strings. We guarantee the IDs will be unique, therefore you can rely on them directly as references."
> (line 131 in /tmp/source-fetch-1780197188.txt)
## Claims Extracted / 추출된 주장
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| GITHUB-NODE-ID-C1 | GitHub GraphQL 은 모든 객체에 global node ID 를 부여하며, REST API 의 `node_id` 필드와 GraphQL 의 `id` 필드가 동일 값이다 | "In REST, the global node ID field is named node_id . In GraphQL, it's an id field on the node interface." (line 13) | `company-case-study` | GitHub GraphQL API 사용 시 | REST-GraphQL 간 ID 일치가 *모든* 플랫폼의 요건임을 증명하지 않음 |
| GITHUB-NODE-ID-C2 | GitHub 의 legacy node ID 는 base64 인코딩된 값이며, decode 하면 `<version>:<TypeName><numeric_id>` 형식이다 (예: `MDQ6VXNlcjU4MzIzMQ==``04:User583231`) | `"node_id" : "MDQ6VXNlcjU4MzIzMQ=="` (line 75) + base64 decode 결과 `04:User583231` (터미널 검증) | `company-case-study` | GitHub legacy global node ID 포맷 설명 | 이 포맷이 현재 신규 객체에도 적용됨을 증명하지 않음 (새 포맷은 다름 — `U_kgDOADP9xw` 같은 opaque 형식) |
| GITHUB-NODE-ID-C3 | GitHub 는 global node ID 를 *opaque string* 으로 취급할 것을 권고하며, 클라이언트가 ID 를 decode 하면 포맷 변경 시 서비스가 깨질 수 있다고 명시적으로 경고한다 | "If you currently decode IDs, your service may break as the underlying data format of the IDs has changed. We suggest you migrate your service to treat these IDs as opaque strings. We guarantee the IDs will be unique, therefore you can rely on them directly as references." (line 131) | `company-case-study` | API 소비자(integration 개발자) 관점 | ID 내부 구조가 *완전히* 무의미해야 한다는 범용 원칙을 증명하지 않음 |
| GITHUB-NODE-ID-C4 | GitHub GraphQL 은 `node(id: "...")` query 로 ID 만으로 임의 객체를 직접 조회하는 Relay-style "direct node lookup" 패턴을 지원한다 | "This type of query—that is, finding the node by ID—is known as a 'direct node lookup.'" (line 89) + `node ( id : "MDQ6VXNlcjU4MzIzMQ==" )` query (line 84) | `company-case-study` | GitHub GraphQL `node` interface 를 구현한 모든 타입 | 이 패턴이 모든 GraphQL API 의 표준임을 증명하지 않음 (Relay spec 의 관례이지 GraphQL spec 의 강제 사항이 아님) |
| GITHUB-NODE-ID-C5 | GitHub 는 global node ID 를 버전 간에 영속(persist)할 것을 권장하며, API 버전 전환 시 ID 를 안정적인 참조로 사용하도록 best practice 를 명시한다 | "it's best practice to persist the global node ID so you can easily reference objects across API versions." (line 108) | `company-case-study` | REST-GraphQL 마이그레이션, API 버전 관리 | ID 의 영구 불변(immutability)을 보증하지는 않음; GitHub 자체도 legacy ID 를 deprecated 처리하고 있음 |
### Strength 설명
모든 Claim 이 `company-case-study`: GitHub 는 대규모 플랫폼의 실무 사례이나, 이 가이드 페이지는 *공식 API 표준 문서가 아닌 가이드*이며, ID 포맷 자체는 GitHub 의 Relay 구현 방식에 종속됨.
## Usage Boundaries / 적용 경계
### 이 자료가 직접 증명하는 것
- `GITHUB-NODE-ID-C1`: REST 와 GraphQL 사이의 ID 필드 매핑 패턴 (node_id ↔ id)
- `GITHUB-NODE-ID-C2`: base64(type:numeric_id) 포맷이 type 정보를 ID 에 인코딩하는 *한 가지 구현 방식*의 사례
- `GITHUB-NODE-ID-C3`: 클라이언트가 ID 구조에 의존(decode)하면 안 된다는 실무 권고 — opaque string 원칙
- `GITHUB-NODE-ID-C4`: `node(id: ...)` GraphQL 쿼리를 통한 type-agnostic object lookup 패턴
- `GITHUB-NODE-ID-C5`: global node ID 를 API 버전 경계를 넘어 안정적인 참조로 유지하는 best practice
### 이 자료가 증명하지 않는 것
- GitHub 의 *새 포맷* (`U_kgDOADP9xw` 형식) 의 인코딩 방식 — 본 문서는 legacy 포맷 기준. 신규 포맷은 opaque 하며 decode 불가
- base64(type:numeric_id) 가 *모든 API* 에 권장되는 ID 포맷임 — GitHub 자신도 이 포맷을 deprecated 처리함
- Relay Node Interface 가 GraphQL 표준 spec 의 일부임 — Relay 의 관례이며 GraphQL spec 자체에는 없음
- Public ID vs Internal Sequence 분리를 *반드시* 해야 한다는 근거 — GitHub 는 외부 ID 가 내부 numeric_id 를 포함하는 구조였고 이것이 보안 문제의 원인이 되어 포맷을 변경함
### ca-skeleton 에 적용하려면 추가 확인이 필요한 것
- D6 (prefix 정책): GitHub 식 base64(type:numeric_id) 는 현재 deprecated. ca-skeleton 이 채택할 포맷은 Stripe-style `tk_<random>` 또는 flat 방식과 비교해 별도 결정 필요
- D11 (Public vs Internal): GitHub 패턴이 *external = base64(type:internal_id)* 였고 internal numeric_id 가 외부에 노출된 것이 문제였음. ca-skeleton 의 Dual 전략에서 internal numeric ID 의 외부 노출을 방지하는 설계 별도 검토 필요
- D13 (multi-tenancy): GitHub 의 type 인코딩은 tenant 격리가 아닌 object type 식별 목적. ca-skeleton 의 tenant 격리 요건과 다름
## 메모 / Notes
- base64 decode 검증: `echo "MDQ6VXNlcjU4MzIzMQ==" | base64 -d``04:User583231` (터미널에서 직접 확인, 2026-05-31)
- legacy 포맷 (`MDQ6...` — base64 encoded) vs 새 포맷 (`U_kgDO...` — opaque, not base64 of type:id): GitHub 는 2021년부터 새 포맷으로 전환 중. 이 문서가 다루는 legacy 포맷은 deprecated 이나, *type 인코딩 패턴의 사례 연구* 로서는 유효함
- Relay Node Interface: GitHub GraphQL 이 Relay spec 을 따름은 이 문서에서 직접 언급되지 않음. Relay spec 을 명시적 근거로 사용하려면 별도 공식 Relay spec 문서 필요
- 본 자료만으로 D6 (prefix 정책) 결정을 내리는 것은 `UNSUPPORTED_DECISION` — GitHub 가 해당 패턴을 deprecated 처리했으므로, 단독 근거로 불충분
## Related / 관련
- 같은 주제 다른 자료 (예정): [[raw/company-tech-blogs/api-versioning-stripe-date-based]] — Stripe 의 외부 ID 관례
- 연관 branch: [[raw/branch-notes/feature-resource-identifier-contract]]
- 이 자료를 인용한 wiki 요약: (생성 시 추가)