GraphQLって何？

> **まだクエリとミューテーションしか書けていないので他は参考文献よりどうぞ**
(時間かかるから徐々に追記します)
(下書きでもいいけどモチベ下がりそう)

# はじめに
この記事はできるだけ簡潔に記述することを目的にしています。
詳しいことを知りたい方は他をどうぞ

この記事内では見やすくなるように多少データを整形しています

# GraphQLとは
GraphQLはAPI向けの言語です。データの形式のみの定義のため, 言語やデータを保存する方法は依存しません。(要するにDBでもテキストでもいい)
GraphQLの定義に従ってクエリを書き, サーバーと通信を取ることでJSONになって戻ってきます。

# クエリとミューテーション
GraphQLには様々なデータの取得や編集に関するものがあります。

## Fields
最も簡単なのはこのFieldです。

```text:request
{
  hero {
    name
  }
}
```

```text:response
{
  "data": {
    "hero": {
      "name": "R2-D2"
    }
  }
}
```

このようにリクエストしたクエリと同じ形でJsonが帰ってきます。
これがGraphQLでは重要です。(すぐに欲しいデータが受け取れる)

Stringやintといった単一のものだけでなくObjectも受け取れます。
また, コメントは先頭に#をつけて表します。

```text:request
{
  hero {
    name
    # Queries can have comments!
    friends {
      name
    }
  }
}
```

```text:response
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        { "name": "Luke Skywalker" },
        { "name": "Han Solo" },
        { "name": "Leia Organa" }
      ]
    }
  }
}
```

上の例では`friends`は配列のオブジェクトを返します。

## Arguments
上のFieldだけでは決まったデータを受け取ることしか出来ません。
そこでArgumentsを追加することでいろいろなデータを柔軟に指定, 取得できます。

```text:request
{
  human(id: "1000") {
    name
    height
  }
}
```

```text:response
{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "height": 1.72
    }
  }
}
```

これまでAPIデザインとして一般的だったRESTはURLクエリなどでしかArgumentsを送れませんでした。
が、GraphQLではそれぞれのFieldなどに対してもArgumentsをつけることが出来ます。

```text:request
{
  human(id: "1000") {
    name
    height(unit: cm)
  }
}
```

```text:request
{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "height": 172
    }
  }
}
```

この引数には様々な型があります。また自分で宣言することも可能です。
(型についてはこの先の[スキーマとタイプ](#スキーマとタイプ)を参照してください)

## Aliases
例えば`hero(episode: EMPIRE)`と`hero(episode: JEDI)`を同じクエリで参照しようとした場合, 同じ`hero`フィールドになってしまい参照できません。そこでエイリアスを利用します。

```text:request
{
  empireHero: hero(episode: EMPIRE) {
    name
  }
  jediHero: hero(episode: JEDI) {
    name
  }
}
```

```text:response
{
  "data": {
    "empireHero": {
      "name": "Luke Skywalker"
    },
    "jediHero": {
      "name": "R2-D2"
    }
  }
}
```

エイリアスを使うことで両方の結果を受け取れます。

## Fragments
同じデータを受け取るのに同じものを何回も宣言するのは冗長です

```text:ex
{
  leftComparison: hero(episode: EMPIRE) {
    name
    appearsIn
    friends {
      name
    }
  }
  rightComparison: hero(episode: JEDI) {
    name
    appearsIn
    friends {
      name
    }
  }
}
```

フラグメンツを使うことで上の例が下のように簡単に宣言できます

```text:request
{
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

fragment comparisonFields on Character {
  name
  appearsIn
  friends {
    name
  }
}
```

```text:response
{
  "data": {
    "leftComparison": {
      "name": "Luke Skywalker",
      "appearsIn": [ "NEWHOPE", "EMPIRE", "JEDI" ],
      "friends": [
        { "name": "Han Solo" },
        { "name": "Leia Organa" },
        { "name": "C-3PO" },
        { "name": "R2-D2" }
      ]
    },
    "rightComparison": {
      "name": "R2-D2",
      "appearsIn": [ "NEWHOPE", "EMPIRE", "JEDI" ],
      "friends": [
        { "name": "Luke Skywalker" },
        { "name": "Han Solo" },
        { "name": "Leia Organa" }
      ]
    }
  }
}
```

同じ形式の多くのデータを取得する際に便利に使いやすいです。
複数のフラグメントを使うことも可能です。

## Variables
ほとんどのアプリではArgumentsに指定するものは変化します。
GraphQLでは内部で固有の形式に変換するため変化するArgumentsを直接書くことはすすめられていません。
なので変数を使いましょう。

まずは変数を使うクエリを`$変数名`のように宣言します。(1行目)
その変数を使うクエリを今まで通り記述します(2行目)

```text:request
query HeroNameAndFriends($episode: Episode) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}
```

`変数名: 値`のように記述し,変数辞書を作成します。(Jsonのことが多い)

```json:veriablesJson
{
  "episode": "JEDI"
}
```

```text:response
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        { "name": "Luke Skywalker" },
        { "name": "Han Solo" },
        { "name": "Leia Organa" }
      ]
    }
  }
}
```

クライアント側では新しくクエリを作る必要はなく, ただ単に変数(Json)を渡すだけです。
変数を使わず, クエリを文字列結合で作ることはするべきではありません。

### 変数定義について
変数定義は`($episode: Episode)`のように宣言され, $を先頭に変数名, その後ろに型が宣言されます。関数宣言に似ています。

上の例では`$episode`は必須ではありません。
必須にするには`($episode: Episode!)`のように宣言します。
(詳しくはこの先の[スキーマとタイプ](#スキーマとタイプ)を参照してください)

デフォルトの値を宣言することも可能です。
`($episode: Episode = JEDI)`のように宣言します。
もちろん変数(Json)を渡された場合にはJsonを優先します。

##Operation name
上の例では`query HeroNameAndFriends { ... }`のように書いていますが今まで通りこれらを省略し`{ ... }`のように記述することも出来ます。

これらを書くことに寄ってサーバーとクライアント側で要求を識別することが簡単になります。

##Directives
Variablesを使うことでクエリへの引数を変更できるようにナリましたが、引数だけでなく変数によって取得するデータを変更しなければならないかもしれません。

```text:request
query Hero($episode: Episode, $withAppearsIn: Boolean!, $withFriends: Boolean!) {
  hero(episode: $episode) {
    name
    appearsIn @skip(if: $withAppearsIn)
    friends @include(if: $withFriends) {
      name
    }
  }
}
```

```json:veriablesJson
{
  "episode": "JEDI",
  "withAppearsIn": true,
  "withFriends": true
}
```

```text:response
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        { "name": "Luke Skywalker" },
        { "name": "Han Solo" },
        { "name": "Leia Organa" }
      ]
    }
  }
}
```

上の例で`$with----`の変数によって変化することが分かると思います。

`@include(if: Boolean)` `true`のときは表示されます
`@skip(if: Boolean)` `false`のときは表示されます

##Mutations
今まではデータ取得についてでしたが今回は編集や追加についてです
GraphQLではデータの取得に重点を置いていますがもちろんサーバー側ではデータの編集も重要です。

RESTでも`GET`ではデータを変更することは推奨されないように, GraphQLでもクエリでデータを変更することは推奨されません。
RESTでは`POST, PUT`などでしたがGraphQLではmutationsが推奨されています。

```text:request
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}
```

```json:variablesJson
{
  "ep": "JEDI",
  "review": {
    "stars": 5,
    "commentary": "This is a great movie!"
  }
}
```

```text:response
{
  "data": {
    "createReview": {
      "stars": 5,
      "commentary": "This is a great movie!"
    }
  }
}
```

リクエストされたデータに対して, 更新されたデータがレスポンスで返却されます。
`createReview`の`review`引数が単一の値ではなくオブジェクトなことに気づくと思います。これについてはこの先の[スキーマとタイプ](#スキーマとタイプ)を参照してください

**またqueryは並列して実行されますがmutationsは順番に実行されます。**
これは1リクエストで複数のmutationsを実行しても必ず最初のものが終了してから2番目が実行されることが保証され, データが競合しないことが保証されます。

##Inline Fragments
GraphQLでは型をインターフェースを用いて表現することも出来ます。(詳しくはこの先の[スキーマとタイプ](#スキーマとタイプ)を参照してください)

型に応じて取得するデータを変更できます

```text:request
query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    name
    ... on Droid {
      primaryFunction
    }
    ... on Human {
      height
    }
  }
}
```

```json:variablesJson
{
  "ep": "JEDI"
}
```

```text:response
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "primaryFunction": "Astromech"
    }
  }
}
```
heroではDroidかHumanが返却され(インターフェースであるCharactorが返却されます), それに応じて変化します。

##特殊なフィールド
リクエストに`__typename`を含めることで返された型を参照することが出来ます。

```text:request
{
  search(text: "an") {
    __typename
    ... on Human {
      name
    }
    ... on Droid {
      name
    }
    ... on Starship {
      name
    }
  }
}
```

```text:response
{
  "data": {
    "search": [
      {
        "__typename": "Human",
        "name": "Han Solo"
      },
      {
        "__typename": "Human",
        "name": "Leia Organa"
      },
      {
        "__typename": "Starship",
        "name": "TIE Advanced x1"
      }
    ]
  }
}
```

またこのような特殊なものはこの先の[Introspection](#Introspection)を参照してください。

# スキーマとタイプ
GraphQLは実装された言語に依存しないよう, GraphQL独自の型概念が存在します。

## Object types and fields
GraphQLスキーマの最も基本的なコンポーネントはオブジェクト型です。
これは, サービスから取得できるオブジェクトの種類とフィールドを表します。
スキーマでは以下のように書きます。

```text:type
type Character {
  name: String!
  appearsIn: [Episode]!
}
```

- `Character`はGraphQLのオブジェクト型です. 複数のフィールドを持ちます. GraphQLのスキーマはほとんどこのオブジェクト型です.
- `name`と`appearsIn`は`Character`型のフィールドです. これらはQueryから参照することが出来ます.
- `String`は実装されたスカラー型の一つです. 詳しくはあとで.
- `String!`はフィールドがnullでないことを保証します. つまり, このフィールドを参照すると常に値が返ってきます.
- `[Episode!]`は`Episode`オブジェクトの配列を表します.またnullで無いので, 常に配列を返します.(配列の大きさが0を含む)

## Arguments 
GraphQLのフィールドには引数をつけることが出来ます。

```text:ex
type Starship {
  id: ID!
  name: String!
  length(unit: LengthUnit = METER): Float
}
```

上の例では`length`フィールドに一つのフィールドを定義しています.
引数は必須ではなくデフォルトを設定することもでき, 上の例ではデフォルトに`METER`が指定されています.

##The Query and Mutation types
スキーマは通常オブジェクト型ですが, 特別な2つのスキーマがあります.

```text:schema
schema {
  query: Query
  mutation: Mutation
}
```

すべてのGraphQLのサービスには`query`型があり, `mutation`型もあるかもしれません.
これらはすべて, クエリのエントリーポイントとして定義されます.

たとえば

```text:request
query {
  hero {
    name
  }
  droid(id: "2000") {
    name
  }
}
```

```text:response
{
  "data": {
    "hero": {
      "name": "R2-D2"
    },
    "droid": {
      "name": "C-3PO"
    }
  }
}
```

のようなクエリが実行された場合, `Query`型が以下のような`hero`, `droid`フィールドを定義されている必要があります.

```text:type
type Query {
  hero(episode: Episode): Character
  droid(id: ID!): Droid
}
```

Mutationsも同様に`Mutation`型のフィールドに定義されている必要があります.
スキーマへのエントリーポイントであるという点以外はオブジェクト型と同じで,フィールドも同じように動作します.

## Scalar types
オブジェクト型には名前とフィールドが定義されますが, どこかでそのフィールドを具体的なデータに解決しなければなりません.
これがスカラー型です. GraphQLにはデフォルトで以下のスカラ型のセットが用意されています.

|スカラー型名|内容|
|:--|:--|
|Int|符号付き32ビット整数|
|Float|符号付き倍精度浮動小数点値|
|String|UTF-8文字シーケンス|
|Boolean|trueまたはfalse|
|ID|ユニークな値が定義され, 再取得時等にデータを検証する|

もちろん自分でスカラー型を定義することもできます.

```text
scalar Date
```

この型をシリアライズ, デシリアライズ, バリデートするのは内部実装に依存します.

## Enumeration types
列挙型は決められた値の要素を定義しますが, その中に重複した値を宣言することは許可されません.

```text:enum
enum Episode {
  NEWHOPE
  EMPIRE
  JEDI
}
```

上の例は`Episode`列挙型を定義し, `NEWHOPE`, `EMPIRE`, `JEDI`という値を宣言します.

> 様々な言語のGraphQL実装では, 言語に存在するEnumを利用することや, Javascriptの様にEnumが存在しないものは独自に実装するかもしれませんが, それはクライアント側には関係がなく, GraphQLとしてのenumとして完全に動作します.

## Lists and Non-Null
オブジェクト型, スカラー型および列挙型はGraphQLで定義できる型です.
しかし実際に使用する場合にはこれらの他に追加の型修飾子を適用できます.

```text:type
type Character {
  name: String!
  appearsIn: [Episode]!
}
```

上の例では`String`型に`!`をつけ, null非許容型とします.

```text:ex
query searchWord($word: String!)
```
```json:variableJson
{
  "word": null
}
```

例えば上記の様に宣言し, 実行すると以下のような検証エラーを出力します.

```text:error
{
  "errors": [
    {
      "message": "Variable \"$word\" of required type \"String!\" was not provided.",
      "locations": [
        {
          "line": 1,
          "column": 18
        }
      ]
    }
  ]
}
```

リストも同じように動作します. 例えば`[String]`のようにすると, String型の配列を返します.
`!`と`[]`は組み合わせる事もでき

```text:ex
fieldName: [String!]
```

とすると, リスト自体はnullでも良いですが, null要素は存在できません.
以下のような対応になります

|fieldの中身|エラーの有無|
|:--|:--|
|null|無|
|[]|無|
|["a", "b"]|無|
|["a", null, "b"]|有|

非null非許容型リストを定義すると

```text:ex
fieldName: [String]!
```

|fieldの中身|エラーの有無|
|:--|:--|
|null|有|
|[]|無|
|["a", "b"]|無|
|["a", null, "b"]|無|

のようになります.

## Interfaces
他の言語と同様にGraphQLもインターフェースをサポートしています.
インターフェースはそのインターフェースを実装するために含まなければならないフィールドを定義する抽象型です.

たとえば`Character`インターフェースなら以下のようになります.

```text:ICharacter
interface Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
}
```

つまりCharacterを実装するすべての型はこれらを実装する必要があります.

```text:ex
type Human implements Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
  starships: [Starship]
  totalCredits: Int
}

type Droid implements Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
  primaryFunction: String
}
```

`Character`インターフェースに定義されたフィールドだけでなく`totalCredits`, `starships`, `primaryFunction`のようにその型独自のフィールドも宣言できます.

インターフェースは便利ですが使い方に注意してください.

```text:request
query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    name
    primaryFunction
  }
}
```

```json:veriablesJson
{
  "ep": "JEDI"
}
```

```text:response
{
  "errors": [
    {
      "message": "Cannot query field \"primaryFunction\" on type \"Character\". Did you mean to use an inline fragment on \"Droid\"?",
      "locations": [
        {
          "line": 4,
          "column": 5
        }
      ]
    }
  ]
}
```

`primaryFunction`フィールドは`Droid`型にしか宣言されていないためエラーになります.

## conditional fragment
これを回避するためにインラインフラグメントを使えば`Droid`型の場合のみ取得するようにできます.

```text:requestFix
query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    name
    ... on Droid {
      primaryFunction
    }
  }
}
```

```text:newResponse
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "primaryFunction": "Astromech"
    }
  }
}
```

インラインフラグメントに関しては[こちら](#inline-fragments)を参照して下さい.

## union types
共用体はインターフェースと非常に似ていますが, それぞれで同じフィールドを定義する必要はありません.

```text:union
union SearchResult = Human | Droid | Starship
```

`SearchResult`は`Human`, `Droid`, `Starship`のいずれかを返します.

共用体は具体的なオブジェクト型を指定する必要があり, インターフェースや他の共用体は指定できません.

上記`SearchResult`共用体を返すフィールド参照する場合は[条件付きフラグメント](#conditional-fragment)を使用して参照します.

```text:request
{
  search(text: "an") {
    ... on Human {
      name
      height
    }
    ... on Droid {
      name
      primaryFunction
    }
    ... on Starship {
      name
      length
    }
  }
}
```

```text:response
{
  "data": {
    "search": [
      {
        "name": "Han Solo",
        "height": 1.8
      },
      {
        "name": "Leia Organa",
        "height": 1.5
      },
      {
        "name": "TIE Advanced x1",
        "length": 9.2
      }
    ]
  }
}
```

## Input types
これまではenumやstringと言ったスカラー型を引数としてフィールドに渡す方法を説明しました.
GraphQLではそれだけでなく, オブジェクト型を簡単に渡すこともできます.(特にmutationsでよく使います)
オブジェクト型と同じように見えますが`type`ではなく`input`キーワードを使用します.

```text:input
input ReviewInput {
  stars: Int!
  commentary: String
}
```

以下のように使います

```text:mutation
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}
```

```json:variablesJson
{
  "ep": "JEDI",
  "review": {
    "stars": 5,
    "commentary": "This is a great movie!"
  }
}
```

```text:response
{
  "data": {
    "createReview": {
      "stars": 5,
      "commentary": "This is a great movie!"
    }
  }
}
```

input型のフィールドにinput型を指定することはできますが, 出力はinput型と同じ形で出力されるとは限りません.
またinput型はフィールドに引数をつけることはできません.

# Validation
まだとちゅう

# Execution
まだとちゅう

# Introspection
まだとちゅう

# 参考文献
[Introduction to GraphQL](http://graphql.org/learn/)