LoginSignup
3
0

More than 3 years have passed since last update.

今更ながらGraphQLについてまとめてみた

Last updated at Posted at 2020-07-19
1 / 25

はじめに

GraphQLについてのオライリー本を読んだり、AppSyncを趣味で触ったりしたので今更ながらGraphQLについて社内勉強会用にまとめてみました。


GraphQLとは

GraphQLを一言で説明するとWEB APIのためのクエリ・スキーマ言語である。
クライアントアプリケーションのデータモデルの機能と要件を記述することを目的にFacebookの開発チームによって作成された。1


クエリ言語とスキーマ言語

ここで扱うクエリ言語スキーマ言語については以下のようなイメージとなっている。

  • クエリ言語
    • クライアントアプリがGraphQLサーバーにリクエストを送信するための構文
  • スキーマ言語
    • GraphQLサーバーのデータ型の集合を定義するための構文

GraphQLの立ち位置

アプリケーション開発に用いられるGraphQLのイメージ。

GraphQLについて.jpg


GraphQLサーバーが実際に行うこと

  • APIサーバーとの通信を行う
    • もしくは直接データベースの操作を行う
  • クエリ構文を解析する
    • 解釈した構文に基づいて処理(リゾルバ)が実行される

GraphQLの動作.jpg


WEB APIとしてのクエリ

GraphQLサーバーへ送るクエリはHTTPリクエストのPOSTメソッドを用いて送信される。以下はcURLでの例。

curl --location --request POST 'http://snowtooth.moonhighway.com/' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"query {\r\n  allLifts {\r\n    name\r\n  }\r\n}","variables":{}}

クエリのリクエストを試す場合は、GraphiQLGraphQL PlaygroundなどのツールもしくはPostmanのGraphQL機能を使用することができる。


クエリの種類

クライアントアプリケーションが用いるクエリの構文では、3つのオペレーションを用いることができる。

  1. query
  2. mutation
  3. subscription

query

データを取得するためのオペレーション。実際に取得したいデータをfieldに指定する。以下はスノートゥースで、すべてのLiftnamestatusの情報をとってくる例。

query getAllLifts {
  allLifts {
    name
    status
  }
}

mutation

データの書き込み操作を担当する。基本的に構文はqueryと変わらない。以下は前ページで用いたスノートゥースでとあるLiftstatusを更新する例。

mutation openLift {
  setLiftStatus(id:"astra-express" status: OPEN) {
    name
    status
  }
}

subscription

サーバーからリアルタイムでデータを受信することができる。例えばmutationで更新したstatusを毎回受け取りに行くために、一々queryを叩かずともsubscriptionを用いればWebSocketを通じてリアルタイムにデータを受け取ることができる。以下はその構文の例。

subscription listenStatusChange {
  liftStatusChange {
    name
    status
  }
}

ここで省略した話

  • フラグメント
    • 冗長な構文を共通化させる仕組み
  • ユニオン型
    • 2つの異なるオブジェクト型をまとめる仕組み
  • インタフェース
    • 実装すべきフィールドのリストを指定する抽象型

スキーマの設計

実際にGraphQLサーバーを実装するために、まずはデータ型の集合であるスキーマを設計する。実装例については過去の記事の内容を使いまわしてみる。

enum Category {
    HOGEHOGE
    HUGAHUGA
}

type Item {
    id: String!
    data: String!
    category: Category!
}

type Query {
    allItem: [Item]
    allItemOnCategory(category: Category): [Item]
}

input ItemInput {
    data: String!
    category: Category!
}

type Mutation {
    addItem(item: ItemInput!): Item
}

はスキーマの核になるもの。それぞれの型には対応するフィールドが存在する。QueryMutationもそれぞれ使用可能なクエリがフィールドとして定義されている型となる。

type Item {
    id: String!
    data: String!
    category: Category!
}

type Query {
    allItem: [Item]
    allItemOnCategory(category: Category): [Item]
}

type Mutation {
    addItem(item: ItemInput!): Item
}

スカラー型とリスト

それぞれのフィールドが固有の型のデータを持っていて、その組み込みの型をスカラー型という。例えばidにはStringというスカラー型で定義されている。ちなみにString!!を付与することでそのフィールドがnullにならないことを示すことができる。
また、型を[]で囲むことでフィールドに型のリストを指定することができる。例えば[Item]Itemという型のリストであることを示している。


Enum

Enumは限られた選択肢の文字列が入力・出力されることをフィールドに定義したいときに用いる

enum Category {
    HOGEHOGE
    HUGAHUGA
}

ここで作成したCategoryはフィールドの型として用いることができる。


入力型

引数に対して使用する型。多数の引数をまとめるために用いる。

input ItemInput {
    data: String!
    category: Category!
}

ここで作成されたItemInputは引数にのみ用いることができる。


ここで省略した話

  • カスタムスカラー型
    • 独自で定義されたスカラー型。
  • ユニオン型
    • 複数の型のうち一つを返す型。
  • インタフェース
    • 型の中で必ず存在するフィールドを定義する抽象型。

リゾルバ

リゾルバは特定のフィールドを返す関数。クエリで指定されたフィールドに対して発行される。以下は過去の記事で書いたAppSyncとCDKの実装例。

...
    itemDS.createResolver({
      typeName: 'Query',
      fieldName: 'allItem',
      requestMappingTemplate: MappingTemplate.dynamoDbScanTable(),
      responseMappingTemplate: MappingTemplate.dynamoDbResultList(),
    })
    itemDS.createResolver({
      typeName: 'Mutation',
      fieldName: 'addItem',
      requestMappingTemplate: MappingTemplate.dynamoDbPutItem(
          PrimaryKey.partition('id').auto(),
          Values.projecting('item')),
      responseMappingTemplate: MappingTemplate.dynamoDbResultItem(),
    })
...

直感的な理解としては、リゾルバはリクエストとレスポンスのボディに対するマッピング・そのための内部的な処理を実装するものである。


さいごに

  • GraphQLを用いた開発では、スキーマとクエリの2つの言語を書くことになる
    • スキーマはAPIの仕様となるもの
    • クエリはクライアントアプリからのリクエスト
  • 基本的にライブラリを用いた開発となる
    • 手で実装するのはおそらく難解
    • GraphQL用のライブラリについては公式ページで紹介されている。

GraphQLについて気になった問題などを取り上げた記事などの紹介


N+1問題

N+1問題とは「1つのSQLでN件のレコードをフェッチしたあと、それぞれ対して関連するレコードを個別にフェッチするのにNつのSQLを発行している」状態を指す問題です。GraphQLのリゾルバでSQLを用いる場合このが引き起こされやすくなります。
この問題についてはこの記事が参考になりました。


REST APIの代替技術となるのか

こちらの記事にある通り、GraphQLにも欠点があります。

  • フルスクラッチでの実装が難しい(基本はライブラリ依存)
  • 画像や動画などの大容量バイナリの扱いが難しい(JSONなので)

Redux vs GraphQL

この話題についてとあるスライドの28ページ目の表がわかりやすくまとまっていました。
こういった記事にもあるように基本的にはapollo-clientReduxとの対比でよく議論されているようです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0