사전 GraphQL
표준

GraphQL

gabury1

클라이언트가 필요한 데이터의 모양을 적어 보내면 서버가 그 모양 그대로 돌려주는 질의 언어입니다. 그 언어와 실행 방식을 문서 하나가 정해 놓았습니다. 프로그래밍 언어도 저장 시스템도 이 문서는 정하지 않습니다.

쉽고 빠른 이해

GraphQL 은 클라이언트가 원하는 데이터의 모양을 요청에 그대로 적으면, 서버가 그 모양대로만 데이터를 돌려주는 질의 언어입니다. 예를 들어 이름 한 필드만 요청하면 응답에도 이름 하나만 옵니다.

예전 방식은 대부분 서버 쪽이 각 요청의 응답 모양을 정해 두었습니다. GraphQL 은 반대로 클라이언트가 요청한 모양 그대로만 돌려받습니다.

돌아가는 순서는 이렇습니다.

  1. 클라이언트가 원하는 필드를 요청에 적어 보냅니다
  2. 서버가 정해둔 데이터 종류에 맞는 요청인지 확인하고 실행합니다
  3. 요청한 모양 그대로 응답을 돌려줍니다. 값을 못 가져온 자리는 비워 두고 오류도 같이 담습니다

GraphQL 은 무엇이든 계산할 수 있는 프로그래밍 언어가 아니라, 이 규칙을 따르는 서비스에만 요청을 보내는 언어입니다. 그 서비스를 어떤 언어로 만들지·데이터를 어디에 저장할지·요청을 어떻게 주고받을지는 정하지 않으므로, 그 부분은 서비스마다 따로 갖춰야 합니다.

상세

GraphQL 은 클라이언트 애플리케이션을 만들려고 설계된 질의 언어입니다. 데이터 요구사항과 상호작용을 서술하는 문법과 체계를 제공합니다. 예를 들어 id 가 4인 사용자의 이름 하나만 요청에 적으면 응답에도 이름 하나만 돌아옵니다. 임의의 계산을 할 수 있는 프로그래밍 언어는 아닙니다. 이 명세가 정한 능력(타입 시스템이 정의한 필드처럼 클라이언트가 요청해 쓸 수 있는 것)을 갖춘 응용 서비스에 요청을 보내는 데 쓰는 언어입니다.

명세는 구현에 두 가지를 강제하지 않습니다. 프로그래밍 언어와 저장 시스템입니다. 명세를 구현하는 쪽이 바로 응용 서비스입니다. 응용 서비스는 자기 능력을 GraphQL 이 담아낸 하나의 언어와 타입 시스템과 철학에 대응시킵니다. 예를 들어 사용자를 id 로 조회해 이름을 돌려주는 기능이 있다면, 앞서 본 user(id: 4) { name } 요청으로 받을 수 있도록 그 기능을 GraphQL 의 타입과 필드로 정의해 둡니다. 그래서 제품 개발에 친화적인 통일된 인터페이스가 서고, 도구를 만들 기반이 생깁니다.

설계 원칙 다섯

원칙 명세가 적은 것
Product-centric 뷰의 요구와 그것을 짜는 프론트엔드 엔지니어의 요구가 언어와 런타임을 이끕니다
Hierarchical 요청 자체가 계층으로 구조화됩니다. 요청의 모양이 응답 데이터의 모양과 같습니다
Strong-typing 서비스마다 애플리케이션 고유의 타입 시스템을 정의합니다. 실행 전, 즉 개발 시점에 구문과 타입 유효성을 검사할 수 있습니다
Client-specified response 서비스는 타입 시스템으로 클라이언트가 소비해도 되는 능력을 공개합니다. 그것을 어떻게 소비할지는 클라이언트가 필드 단위로 지정합니다
Introspective 타입 시스템 자체를 GraphQL 언어로 질의할 수 있습니다

명세가 정하지 않는 것

명세가 스스로 정하지 않고 위층에 맡긴 것이 둘입니다. 그 얹힌 구조는 이렇습니다.

block-beta
columns 2
  ser["직렬화 형식"]
  http["전송 계층 · GraphQL over HTTP"]
  spec["GraphQL 명세 · 언어 · 타입 시스템 · 실행 · 응답"]:2

맨 아래 층이 이 명세 자신이 정하는 언어·타입 시스템·실행·응답입니다. 그 위에 나란히 놓인 두 자리 — 직렬화 형식과 전송 계층 — 는 둘 사이에 순서 없이 명세가 일부러 비워 둔 자리입니다. 둘 다 이 명세 밖에서 채워집니다.

직렬화 형식이 첫째입니다. §7.2 Serialization Format 은 특정 직렬화 형식을 요구하지 않습니다. 다만 클라이언트는 GraphQL 응답의 주요 원시값을 지원하는 형식을 쓰는 것이 권장됩니다. 형식이 최소한 표현할 수 있어야 하는 원시값은 넷입니다. Map · List · String · Null 입니다.

전송이 둘째입니다. 이 명세에는 전송을 다루는 절이 아예 없습니다. 목차가 §1 Overview · §2 Language · §3 Type System · §4 Introspection · §5 Validation · §6 Execution · §7 Response 와 부록 A · B 로 끝납니다. HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜) 위에서 어떻게 주고받는지는 별도 문서인 GraphQL over HTTP 가 맡습니다. 그 문서는 GraphQL 명세가 전송 계층을 일부러 정하지 않는다고 적습니다.

출처 문서

정본은 GraphQL Specification 의 October2021 Edition 입니다. spec.graphql.org/October2021 에 있습니다. 판을 가리키는 것이 문서 번호가 아니라 이 날짜 이름입니다. 이전 판들은 릴리스 태그와 일치하는 permalink 에 남아 있습니다. 최신 작업 초안은 spec.graphql.org/draft 입니다. 문서는 자신이 지금까지 발전해 왔고 앞으로의 판에서도 계속 발전할 수 있다고 적습니다.

거버넌스와 라이선스

GraphQL Specification Project 는 Joint Development Foundation 이 제공합니다. 현재의 워킹그룹 헌장이 산출물 전체에 걸리는 지식재산권 정책을 담고 있고 technical-charter.graphql.org 에 있습니다.

이 문서는 2017년에 Open Web Foundation Agreement(OWFa) 1.0 으로 라이선스가 걸렸습니다. GraphQL Foundation 은 2019년에 GraphQL 생태계를 지원하는 조직들의 중립 거점으로 결성됐고, 같은 해에 GraphQL Specification Project 도 Joint Development Foundation Projects, LLC 의 GraphQL Series 로 설립됐습니다.

timeline
    title GraphQL 명세의 연혁
    2012 : 페이스북이 질의 언어와 실행 엔진으로 창작
    2015 : 열린 표준화 작업 착수
    2017 : OWFa 1.0 으로 라이선스
    2019 : GraphQL Foundation 결성 · GraphQL Specification Project 설립

현재 산출물에 걸리는 라이선스는 이렇습니다.

산출물 라이선스
Specifications Open Web Foundation Agreement 1.0 Mode (Patent and Copyright)
Source code MIT License
Data sets CC0 1.0

표의 이름은 명세가 적은 그대로입니다.

규범과 비규범

이 문서의 모든 내용은 규범(구현이 반드시 지켜야 하는 부분)입니다. 비규범이라고 명시적으로 선언된 부분만 빠집니다. 빠지는 것이 둘입니다. 예제와 노트입니다. 예제는 도입된 개념과 규범 부분의 동작을 이해하는 데 도움을 주려고 실려 있습니다. 노트는 의도를 밝히고 경계 사례와 함정에 주의를 돌리고 구현 중에 나오는 흔한 질문에 답하려고 실려 있습니다. 아래 「예시」가 옮긴 값들도 명세 안에서는 비규범입니다.

요구 강도

적합한 GraphQL 구현은 모든 규범적 요구를 충족해야 합니다. 적합성 요구는 두 가지 방식으로 적힙니다. 서술형 단언과, 뜻이 분명히 정의된 키워드입니다. 키워드는 MUST · MUST NOT · REQUIRED · SHALL · SHALL NOT · SHOULD · SHOULD NOT · RECOMMENDED · MAY · OPTIONAL 이고, IETF(Internet Engineering Task Force, 국제 인터넷 표준화 기구)의 RFC(Request for Comments, 의견 요청서) 2119 가 서술한 대로 해석합니다. MUST 는 어기면 표준을 안 지킨 것이고 SHOULD 는 이유가 있으면 어겨도 됩니다.

단서가 하나 붙습니다. 이 키워드들은 소문자로 나타나도 뜻을 유지합니다. 비규범이라고 명시적으로 선언된 경우만 예외입니다. 그리고 적합한 구현은 추가 기능을 제공해도 됩니다. 다만 명세가 명시적으로 금지한 자리이거나 그 추가 기능이 적합성 요건을 어기게 되는 자리라면 넣으면 안 됩니다.

전송을 맡는 다른 문서

GraphQL over HTTP 는 Stage 2: Draft 입니다. 공식이 아직 아니지만 이제 온전히 형태를 갖춘 해법이라고 스스로 적습니다. 초안은 계속 바뀔 수 있고 때로는 크게 바뀝니다. 받아들여진다는 보장도 없습니다. 그래서 프로덕션 GraphQL 서비스에서 초안에 기대는 것은 현명하지 않다고 적혀 있습니다. 이 문서는 GraphQL 명세를 무시하거나 대체하지 않습니다. 두 문서가 충돌해 보이면 GraphQL 명세가 서술한 동작을 씁니다.

예시

요청과 응답 한 벌

§1 Overview 의 Example №3 이 id 가 4인 사용자의 이름을 GraphQL 의 페이스북 구현에서 받아오는 요청입니다.

graphql
{
  user(id: 4) {
    name
  }
}

이 요청이 만들어 내는 데이터를 JSON(JavaScript Object Notation, 자바스크립트 객체 표기법)으로 적으면 Example №4 입니다.

JSON
{
  "user": {
    "name": "Mark Zuckerberg"
  }
}

요청에 적은 필드 이름이 그대로 응답의 키가 됩니다. name 하나만 적었으므로 돌아온 것도 name 하나입니다.

응답 맵과 오류 항목

§7.1 Response Format 은 GraphQL 요청에 대한 응답이 맵이어야 한다고 정합니다. 최상위 맵이 가질 수 있는 키는 셋뿐입니다.

키 언제 들어가나
errors 요청이 오류를 일으켰을 때. 오류 없이 끝났으면 이 항목이 있으면 안 됩니다
data 요청이 실행을 포함했을 때. 구문 오류·정보 누락·검증 오류로 실행 전에 실패했으면 있으면 안 됩니다
extensions 구현자가 프로토콜을 마음대로 확장하는 자리. 값은 맵이어야 하고 내용에는 제약이 없습니다

최상위 응답 맵은 이 셋 말고 다른 항목을 담으면 안 됩니다. 앞으로 프로토콜이 바뀌어도 기존 서비스와 클라이언트가 깨지지 않게 하려는 것입니다.

§7.1.2 Errors 의 Example №197 이 오류와 데이터가 함께 온 응답입니다. 친구 목록 가운데 한 명의 이름을 가져오는 데 실패한 경우입니다.

JSON
{
  "errors": [
    {
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [ { "line": 6, "column": 7 } ],
      "path": [ "hero", "heroFriends", 1, "name" ]
    }
  ],
  "data": {
    "hero": {
      "name": "R2-D2",
      "heroFriends": [
        { "id": "1000", "name": "Luke Skywalker" },
        { "id": "1002", "name": null },
        { "id": "1003", "name": "Leia Organa" }
      ]
    }
  }
}

이 응답에서는 실패한 name 이 null 로 오고 나머지 필드는 그대로 왔습니다. 오류 하나하나는 맵이고 message 가 반드시 들어갑니다. 개발자가 오류를 이해하고 고치도록 안내하는 문자열입니다. 이 응답의 locations 는 줄 6, 칸 7 을 가리키고 path 는 hero → heroFriends → 1 → name 을 가리킵니다.

배경

GraphQL 없이 쓴 클라이언트-서버 애플리케이션은 대부분 서비스 쪽이 데이터의 모양을 정합니다. 여러 엔드포인트가 각각 무엇을 돌려줄지를 서비스가 결정합니다. GraphQL 응답은 반대입니다. 클라이언트가 요청한 것을 정확히 담고 그 이상은 담지 않습니다.

명세는 이 방향을 설계 원칙 첫 줄에 못 박습니다. 뷰의 요구와 그것을 짜는 프론트엔드 엔지니어의 요구가 언어와 런타임을 이끈다는 것입니다. 그래서 클라이언트가 무엇을 소비할지 필드 단위로 지정하고, 서비스는 타입 시스템으로 소비해도 되는 능력을 공개합니다.

관련 항목

명세가 §2 Language 부터 §7 Response 까지에서 이름을 붙인 것들입니다.

타입 시스템을 이루는 구성 요소

스키마 · 타입 시스템 · 스칼라 · 인터페이스 · 유니온 · 열거형 · 인트로스펙션

질의 문서를 이루는 구성 요소

쿼리 · 뮤테이션 · 구독 · 프래그먼트 · 변수 · 지시어

요청이 응답이 되기까지

검증 · 실행 · 리졸버 · 직렬화

전송과 직렬화를 맡는 규격

HTTP · POST · GET · JSON

다른 이름: GraphQL Specification · October2021 Edition