初めてのGraphQL with Rails

## この記事の内容
Railsで開発の仕事をしています。**GraphQL is 何？**ぐらいの`GraphQL`初心者だったのですが、とにかくにも業務で急ぎ実装しなければならなかったので、メモをとりながら作成することにしました。

この記事では、Railsアプリに`GraphQL`を取り入れ、データをGETする下準備までを範疇に入れています。
続きはいかに徐々に記していく予定です。

- [初めてのGraphQL with Rails ②（Apollo Client編）](https://qiita.com/tanutanu/items/5fcb905b05d67126394f)
- 順次追加予定...

## GRaphQLとは？グラフって何？？
**[グラフ理論](https://dev.classmethod.jp/articles/graph-theory/)**という理論があるそうです。この理論では、データの構造を点と点を線で繋ぐような形で理解します。この構造を**Graph**と呼びます。`GraphQL`の最後の`QL`はこの`Graph`に**QueryLanguage**（問い合わせ言語）を足して、`GraphQL`と呼んでいるのだと理解しています。

▼Graph理論そのものについてはこちら

https://dev.classmethod.jp/articles/graph-theory/


## なぜGraphQLを使うの？？
これまでデータベースとクライアント側のやりとりとの方法として、`RESTful API`と呼ばれる方法が一般的でした。この`RESTful API`の欠点が、**データの過剰取得**にあったそうです。`GraphQL`はこの弱点を克服し、その時必要なデータを必要なだけ持ってくることができます。

▼`RESTful API`とは何か、その欠点と`GraphQL`の特徴について

https://zenn.dev/yoshii0110/articles/2233e32d276551

▼**データの過剰取得**とはどのようなことか

https://www.webprofessional.jp/rest-2-0-graphql/

## GraphQLのある場所

`GraphQL`を理解する上で、`GraphQL`がアプリの構造上どこにあるのかを理解するのは非常に大切でした。

結論から言うと**データベースとインターフェイスとの間**で、サーバーとクライアントのリクエストの間に入って、色々調整してくれるようです。[公式サイトのトップ](https://graphql.org/)にあった、この図がわかりやすいのではないかと思います。
[![Image from Gyazo](https://i.gyazo.com/4d1df58fcb0b1f748f219e68f06aa64b.png)](https://gyazo.com/4d1df58fcb0b1f748f219e68f06aa64b)
画像引用元：[GraphQL公式サイト](https://graphql.org/)

データベースとディバイスとの間に`GraphQL`が記載されていますね。
## GraphQLでAPIを作るのに必要なもの

GraphQLでAPIを実装をするために必要なものは、以下の3つであると理解しています。

|名前|役割|
|:-----------|:------------|
|クエリ言語     |GraphQLサーバーへの問い合わせ内容を記載した言語| 
|スキーマ言語   |GraphQLサーバーでのデータの型を記載した言語|
|リゾルバ      |問い合わせを実行するメソッド        |

この辺は既存記事に非常に優れた記事があります。特に下記の記事が理解に役立ちましたので貼付をしておきます。

https://qiita.com/shotashimura/items/3f9e04b93e79592030a4

ここでは、`GraphQL`が上記の**「問い合わせ」「データの型」「問い合わせの実行」**の3つのパートで成り立っていることの理解に留めておきます。

## で、Railsでどうやるの？？

上記の内容を`Rails`で表現する場合、[graphql-ruby](https://graphql-ruby.org/)というGemが便利です。今回もそれを利用します。以下、`graphql-ruby`の実装記事です。

本来の`GraphQL`の記載方法を知りたい方は[↑上記の記事](https://qiita.com/shotashimura/items/3f9e04b93e79592030a4)や下記の[公式チュートリアル](https://graphql.org/graphql-js/)など取り組んでみると良いと思います。

https://graphql.org/graphql-js/

### 本記事の参考記事
本記事で実装している内容については主にこちらの記事と[graphql-rubyの公式サイト](https://graphql-ruby.org/)を参考にしました。

https://qiita.com/k-penguin-sato/items/07fef2f26fd6339e0e69

https://graphql-ruby.org/

### 今回表現した内容

今回は以下のような`users`テーブルから**「ユーザー一覧」「ユーザー詳細」**をGETしてくるまでを`GraphQL`で表現したいと思います。

|| users |
|:---:|:--:|
|id|integer|
|name|string|
|email|string|

### はじめに

まずは`graphql-ruby`を使えるようにします。

```
# Gemfile
gem 'graphql'
group :development do
  gem 'graphiql-rails'
end

# ターミナル
$ bundle install
$ rails g graphql:install
```

上記のコマンドで大量のファイルが生成されます。生成されたファイル一覧です。

```sh
create  app/graphql/types
      create  app/graphql/types/.keep
      create  app/graphql/portraits_uploader_schema.rb
      create  app/graphql/types/base_object.rb
      create  app/graphql/types/base_argument.rb
      create  app/graphql/types/base_field.rb
      create  app/graphql/types/base_enum.rb
      create  app/graphql/types/base_input_object.rb
      create  app/graphql/types/base_interface.rb
      create  app/graphql/types/base_scalar.rb
      create  app/graphql/types/base_union.rb
      create  app/graphql/types/query_type.rb
add_root_type  query
      create  app/graphql/mutations
      create  app/graphql/mutations/.keep
      create  app/graphql/mutations/base_mutation.rb
      create  app/graphql/types/mutation_type.rb
add_root_type  mutation
      create  app/controllers/graphql_controller.rb
       route  post "/graphql", to: "graphql#execute"
      create  app/graphql/types/node_type.rb
      insert  app/graphql/types/query_type.rb
      create  app/graphql/types/base_connection.rb
      create  app/graphql/types/base_edge.rb
      insert  app/graphql/types/base_object.rb
      insert  app/graphql/types/base_object.rb
      insert  app/graphql/types/base_union.rb
      insert  app/graphql/types/base_union.rb
      insert  app/graphql/types/base_interface.rb
      insert  app/graphql/types/base_interface.rb
      insert  app/graphql/アプリ名_schema.rb
```
生成されたファイルの中で、この２ファイルは`graphql-ruby`の構造を理解する上で特に重要だったと思います。

```sh
app/graphql/types/query_type.rb
app/graphql/アプリ名_schema.rb
```

### 全体のステップ
[graphql-ruby公式サイトのチュートリアル](https://graphql-ruby.org/getting_started)によると、RailsでGraphQLによるサーバーへの問い合わせをするのに必要なステップは次の3つだそうです。

- 型を決める
- それらの型とスキーマをつなぐ
- クエリをスキーマで実行

一つ一つ見ていきます。

### 型を決める（型ファイルの作成）

RailsではコマンドでGraphQLの型ファイルが生成できます。

```sh
$ rails g graphql:object User

create  app/graphql/types/user_type.rb
```

生成されたファイルの中身がこちら。

```ruby:app/graphql/types/user_type.rb
module Types
  class UserType < Types::BaseObject
    field :id, ID, null: false
    field :name, String, null: false
    field :email, String, null: false
    field :created_at, GraphQL::Types::ISO8601DateTime, null: false
    field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
  end
end
```
既に`User`モデルがある場合には、それに合わせて型を生成してくれるようです。初めは

```sh
$ rails g graphql:object User name:String email:String
```
のように書いていたのですが、既に`User`モデルがあったため、`name`カラムと`User`カラムが2つずつできてしまいました。

### スキーマファイル

上記で定義した内容を実行するためのファイルが必要です。
作成したスキーマファイルは下記の通りです。

```ruby:app/graphql/types/query_type.rb
module Type
  class QueryType < GraphQL::Schema::Object
  
    # フィールド(:user)の説明と引数を記載します。
    field :user, Types::UserType, null: true do
      description "Find User by ID" #省略可
      argument :id, ID, required: true
    end

    # 実行のコマンド(リゾルバ)を書きます
    def user(id:)
      User.find(id)
    end

    def users(page: nil, items: nil)
      User.all
    end
  end
end
```
初めは既存ソースをコピーしながらすることになると思いますが、ここでわからない単語やメソッドがたくさん出てきます。わからないことは地道に

- [graphql-rubyのガイドページ](https://graphql-ruby.org/guides)

などで調べます。

上記のコードを理解するにあたり、調べたのは下記の通りです。

#### [field](https://graphql-ruby.org/fields/introduction.html)
クラスメソッド。データを（DBから）持ってくるするもの。[object](https://graphql-ruby.org/type_definitions/objects)と[interface](https://graphql-ruby.org/type_definitions/interfaces)がfieldを持っています。（`object`と`interface`がそれぞれ何であるかは、名前の部分のリンク先を見てください。）

fieldは下記のような形で書きます。（他の書き方もあります。詳細は[fieldのドキュメント](https://graphql-ruby.org/fields/introduction.html)を参照のこと）

```ruby
field :name, String, null: true do
  description "The name of this thing"
end
```
ブロックの1行目には`field :フィールド名, 型の場所, nullになる可能性の有無 do`がそれぞれ書かれています。

注意しないといけないのは、フィールドと同名のメソッド（リゾルバ）を定義した場合、**実際に帰ってくるのはリゾルバの値**だということ。
例えば先ほどのコードを少し書き換えて

```ruby
 field :user, Types::UserType, null: true do
   argument :id, ID, required: true
 end

 def user(id:)
   # User.find(id) ここを書き換え
   User.where(name: "山田太郎")
 end
```

にすると、返ってくるのは「山田太郎」さんのデータになります。

#### [Arguments](https://graphql-ruby.org/fields/arguments)

検索やデータの呼び出しに使う引数です。例えば

```ruby
field :user, Types::UserType, null: true do
   argument :id, ID, required: true
end
```

↑この`argument :id`の部分を定義することで、

```graphql
{
  user(id: 1) {
    name
    email
  }
}
```
のような`id: 1`のユーザーを呼び出すクエリがクエリが書けるようになります。
その他、以下のような書き方も載っていましたので、

```graphql
{
  customers(first: 5) {
    name
    outstandingBalance
  }
}

{
  posts(startYear: 2018) {
    id
  }
}
```

Railsにおける`order`や`limit`、検索のキーなどもここで定義できるようです。

#### pageやitemsなど
現段階では不明（すみません）。ただ、`graphql-ruby`は[pagenationに特別なページを割いている](https://graphql-ruby.org/pagination/overview.html)ので、多分それ関係の設定なのではないかと理解。違ったら訂正します。＆わかったら追記します。

▼近そうな実装の記事も貼っておきます

https://qiita.com/nobuo_hirai/items/f9e34d8572a82283538b


### ルートとなる型

[graphql-ruby公式サイトのチュートリアル](https://graphql-ruby.org/getting_started#build-a-schema)には**「スキーマファイルを作る前にエントリーポイント（query root）を決めておいてね」**と書いてあります。

どういうことかというと、全てのスキーマには[rootとなる型](https://graphql-ruby.org/schema/root_types.html)があるようです。

どうやらGraphQLそのものに「ルート型」という概念があり、（GraphQL公式サイトには該当となる用語は見つけられなかったのですが、書籍『[初めてのGraphQL](https://www.amazon.co.jp/dp/487311893X)』にはルート型という言葉で出てきていました）

それが、

```sh
$ rails g graphql:install
```
をした時に生成された、こちらのファイルに記されています。

```sh
app/graphql/アプリ名_schema.rb
```
このファイルにはこのように書かれており、

```ruby
class AppNameSchema < GraphQL::Schema
  # required
  query Types::QueryType
  # optional
  mutation Types::MutationType
  subscription Types::SubscriptionType
end
```

データの**「呼び出し(query)」「変更(mutation)」「[サブスクリプション(subscription)](https://qiita.com/yoshii0110/items/3d9ec03215537646b65c)」**がそれぞれどこのスキーマで行われるか記載してあります。型の位置（`Types::QueryType`など）は**ルートとなる型ファイルからの相対位置**で記載されていますので、そのために先に「エントリーポイント（ルートとなる位置）」を決めておいてねと言うことなのかと理解しています。

## スキーマの実行

こちらは、[graphql-rubyのクエリの実行に関する記載](https://graphql-ruby.org/getting_started#execute-queries)にも若干の記載はありますが、`graphql-ruby`の外のライブラリを使用して行うのが一般的なようです。

`graphql-ruby`のサイトでも

- Relay
- Apollo Client
- GraphQL.js Client

が例として挙げられています。
業務では[Apollo Client](https://www.apollographql.com/)を利用しましたが、一旦、長文になりそうなので別記事に記載したいと思います。

## ここまでの感想

調べ始めたらとても奥が深かったです。。。。
この記事も中途半端になってしまって恐縮ですが、理解したらとても便利そうなので、もう少し勉強を深めたいと思います。