GraphQL

**GraphQL**（グラフQL）はAPI向けに作られたクエリ言語およびランタイムである。 ベンダーフリーな GraphQL財団の支援を受け、開発が進められている。

ウェブAPIの開発に、RESTやその他のWebサービスと比較して、効率的で堅牢、かつ柔軟なアプローチを提供する。GraphQLでは、クライアントが必要なデータの構造を定義することができ、サーバーからは定義したのと同じ構造のデータが返される。したがって、必要以上に大きなデータが返されるのを防ぐことができクエリの効率が良い。また、柔軟性と豊かな表現が可能なクエリ言語は複雑さを加えるため、シンプルなAPIには適さない可能性もある。GraphQLは、型システム、クエリ言語、実行セマンティクス、静的な検証、型チェックから構成される。

GraphQLは、データの問い合わせ (query)、書き換え (mutation)、購読 (subscription) をサポートする。

## 概要
GraphQLでは、クライアントがクエリ内容を記した***document***を送信し、GraphQLサービスがクエリを実行し結果を返信する。*document*はDSLである***GraphQL query language***を用いて記述される。以下の例は明日の天気を取得するクエリの*document*とGraphQLサービスから返されたクエリ結果のJSONである。

```graphql
// document
{
  tomorrow {
    weather
    rainyPercent
  }
}
```


```json
{
  "tomorrow": {
    "weather": "cloudy",
    "rainyPercent": 30
  }
}
```

リソースをURLパスで表現するREST APIと異なり、GraphQLはリソースを*document*で表現する。GraphQL WebAPIの場合、単一のAPIエンドポイントへこの*document*をPOSTする（例:``エンドポイントへ*document*をBodyとしてPOSTする）ことでクエリが実行される（参考: アプリケーションプログラミングインタフェース#様式 ）。

*Document*を受け取ったGraphQLサービスは*Document*中の***field*** (例: `tomorrow`) をトップレベルから1つずつ***resolver***により値へ解決する。クライアントが受け取りたい値はすべてfieldとして過不足なく*Document*に記載されているので、*resolver*群により全ての*field*を解決すれば過不足ないデータが1回のクエリで得られる。GraphQLサービス処理系はこのfieldからなるグラフ構造を上からresolverを用いて解決する役割を果たす。resolverはサービス実装者により実装される。

構造が事前に決められたリソースへアクセスするREST APIと異なり、GraphQLではその場でdocumentから与えられた構造に対しresolver群を連続適用して解決する。ゆえにREST APIでは定められたリソースしか1度のアクセスでは取得できないが、GraphQLではschema-validな任意のリソースを1度のアクセスで得られる。例えばRESTful APIでは「ある人の友人リスト」APIがあっても「ある人の友人の友人リスト」を得るためには1度友人リストを得たのちにクライアントからもう一度APIを叩く（クライアントで自前の再帰を行う）必要がある。一方GraphQLでは「Persion.friends field」resolverさえあれば`{personA {friends {friends {name} } } }`*Document*をPOSTするだけでresolverが連続適用されて「友人の友人リスト」が1度に得られる。

このようにGraphQLはクライアントからクエリ構造を渡せる**柔軟性**を持ち、また1度のクエリで必要十分な値のみを得られる**効率性**を持つ。

GraphQLサービスが受け入れられる型を、IDLである"type system definition language" (schema definition languageとも) で書かれたSchemaで記述する。

GraphQLはあくまでAPI仕様であり、通信方式の実装とは独立している。例えばGraphQL WebAPIを実装する際、*document*をURLクエリ文字列に載せることも可能である（例:`GET `）。

## 機能

### ''Arguments''
GraphQLでは***argument***を用いたクエリの制御が可能である。GraphQLオブジェクトの各field（例: `tomorrow`）は0個以上の*arguments*を持てる。GraphQLサービスではクエリをトップレベルのfieldから***resolver***によって解決していくが、*arguments*はその時に*resolver*へ渡され*resolver*の振る舞いを制御する。次の例では"都道府県名/name" *argument*と"天気/weather" *argument*を用い、都道府県-街リストから東京/tokyoに含まれる晴れ/sunnyの街を取得する。

```graphql
// document
{
  prefecture(name: "Tokyo") {
    prefName
    cities(weather: "sunny") {
      cityName
      rainyPercent
}}}
```


```json
{
  "prefecture": {
    {
      "prefName": "Tokyo",
      "cities": [
        {
          "cityName": "Shinjuku",
          "rainyPercent": 10
        },{
          "cityName": "Ikebukuro",
          "rainyPercent": 0
}]}}}
```


### directives
GraphQLでは***directives***を用いたクエリの制御が可能である。GraphQLオブジェクトの各field（例: `tomorrow`）は*directive*を持てる。*directives*は処理系に依存したあらゆる処理を指定するアノテーションである。全ての処理系に実装される*directive*の例としてfieldの無視を指定する`@include(if: Boolean)`がある。

```graphql
{
  sinjuku {
    weather
  }
  ikebukuro @include(if: false) {
    weather
    rainyPercent
}}
```


```json
{
  "sinjuku": {
    "weather": "cloudy"
}}
```

全ての*resolver*に`@include`相当の引数を用意すれば同等の機能を提供できるが、*directives*を用いることで*resolver*に手を加えずかつ*directive*処理系1箇所での実装のみでこの機能を提供できる。

directivesはGraphQLサービス処理系以外にも利用されうる。例えばAWS AmplifyはSchema上の*directivesに基づいたクラウドリソースプロビジョニングコード生成*（"GraphQL Transform"）を実装している。`@model`が付与されたfieldは*resolver*が自動で生成されかつDynamoDBにリソースが準備される。これはGraphQLサービス処理系ではなく、Amplify CLIによっておこなわれる。

## 形式

### ''Document''
*Document*は1つ以上の*OperationDefinition*からなる。1つのみの場合Nameが省略可能であり、さらに*OperationType*がqueryならこれも省略できる。

```
// document
OpType Name [VarDef][Directives] {
  ...
}
OpType Name [VarDef][Directives] {
  ...
}
// e.g.
query ExampleQuery1 {
  resource
}
query ExampleQuery2 ($var: S) @skip(if: false) {
  time
}
```


### ''Field''
*Field*はNameからなっており、Alias, Arguments, Directivesを利用できる。さらにサブFieldを持つことができる。

```
// document
{
  [Alias] Name [Arguments][Directives] [SelectionSet]
}
// e.g.1 - simple
{  resource  }
// e.g.2 - full
{  time: resource (arg1: "arg") @skip(if:false) {  subResource  }  }
```


## 処理系

### 値解決
値解決（Value Resolution）はFieldの値を算出するステップである。`ResolveFieldValue`関数インターフェスに該当し、[オブジェクト型, オブジェクト値, field名, arguments]からfieldの値を生成する（例: `Person`型, `Obama`オブジェクト, `job` fieldName, no argument = `president`field value)。擬似JavaScriptコードで以下になる。

```javascript
function ResolveFieldValue(objectType, objectValue, fieldName, argumentValues){
  const resolver = getExternalResolver(ojectType, fieldName);
  return resolver(objectValue, argumentValues);
}
```


## 歴史
GraphQLは、2012年にFacebookの内部で開発され、2015年に公開された。2018年11月7日、GraphQLプロジェクトは、Facebookから非営利のLinux Foundationがホストする新たに設立されたGraphQL Foundationに移譲された。2012年以来、GraphQLの利用数は、GraphQLの作者のLee Byronが想定したとおりのスケジュールに正確に従って増加している 。Byronの目標は、GraphQLをWebプラットフォーム全体で利用されるようにすることである。

2018年2月9日、GraphQL Schema Definition Language（SDL）が仕様の一部となった。

## 実装

### クライアント
GraphQLクライアントは適切な*document*をGraphQL APIエンドポイントへPOSTするだけでクエリを実行できるため、ライブラリを採用せずとも容易にクエリを実行できる。

より高度な機能を有するGraphQLクライアント実装としては、Apollo ClientとRelayがある。

### サービス/サーバー
GraphQLサーバーは複数の言語で利用可能であり、Haskell、JavaScript、Perl、Python、Ruby、Java、C#、Scala、Go、Elixir、Erlang、PHP、R、Clojureで書かれたものがある。

## 利用例

### GitHub API
GitHubは第4世代のAPIとしてGraphQL API「GitHub GraphQL API v4」を提供している。

GitHubはその選定理由として「more flexibility for our integrators（我々のインテグレータに対する更なる柔軟性）」を挙げている。GitHubではIssueをプロジェクト管理アプリに組み込むシステムインテグレータ、CI/CDパイプラインを管理するエンジニアやライブラリ作者、レポジトリ統計を取り出す個人など、多様なAPI利用者を抱えている。その多様な要求から、全ての利用者に必要かつ十分な（オーバーフェッチもアンダーフェッチもしない）APIを提供することは困難である（無数のREST APIエンドポイント・サーバー実装は管理しきれない）。結果として一部の利用者にとっては柔軟性が足りなく感じられていた。GitHubはレスポンス種に限りがあるREST APIから利用者側がレスポンス（クエリ構造）を指定するGraphQLにAPIを変更し、上記の問題を解決した。

## 関連項目
* Query by Example
* OpenAPI Specification

## 出典

## 外部リンク

*