GraphQLとRailsでAPIを構築する方法

この記事では、**GraphQL**と**Rails**を使って、クエリを使ってデータベースからToDoを送り返す**API**を構築します。

*本ブログは英語版からの翻訳です。オリジナルは[こちら](https://www.alibabacloud.com/blog/buildi)からご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。*

[アリババクラウドコミュニティブログ](https://www.alibabacloud.com/blog?spm=a2c65.11461447.0.0.4cf2be33cr7xHR)執筆者 ダニエル・ショトンワ氏

この記事では、クエリを使ってデータベースからTodoを送信するAPIをAlibaba Cloud上でGraphQLとRailsを使って構築する方法を紹介します。さて、始める前にいくつかのことをクリアにしておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/72c8a2f8-dace-82cb-1ce5-e5e45cfc41d2.png)

>出典：[fiver.com](https://www.fiverr.com/sa_kader/expose-your-web-services-with-rest-api-using-ruby-on-rails?spm=a2c65.11461447.0.0.4cf2be33cr7xHR)

まず第一に、あなたはすでに知っているはずです - 特にあなたが最初の場所でここをクリックしたという事実を考えると - [Rails](https://guides.rubyonrails.org/getting_started.html?spm=a2c65.11461447.0.0.4cf2be33cr7xHR)は、短時間でWebアプリケーションを作成するための非常に人気のあるフレームワークです。開発者はバックエンド用のAPIを作成することでアプリケーションのプロセスやメカニズムを分離し、好みのライブラリを使用する傾向があります。私たち自身もこの傾向に従うことになるでしょう。

次に、おそらく、ご存知の方も多いと思いますが、GraphQLもあります。GraphQLとは何かについては、[https://graphql.org/](https://graphql.org/?spm=a2c65.11461447.0.0.4cf2be33cr7xHR) からのこの定義がよく説明してくれています。

>GraphQLはAPI用のクエリ言語であり、既存のデータを使ってクエリを実行するためのランタイムです。GraphQLは、API内のデータを完全かつ理解しやすい形で記述し、クライアントが必要とするものを正確に求めることができるようにします。

GraphOLとRailsを使用するだけでなく、このチュートリアルではUbuntu 16.04でインストールされた[Elastic Compute Service (ECS)](https://www.alibabacloud.com/ja/product/ecs)インスタンスを使用してアプリケーションをデプロイします。そのため、先に進む前に[Alibaba Cloud](https://www.alibabacloud.com/ja)のアカウントでサインアップしていることを確認してください。

#前提条件
始める前に、[ECS](https://www.alibabacloud.com/ja/product/ecs)インスタンスがすでにセットアップされていることを確認してください。まだ設定していない場合は、Alibaba Cloud の関連[ドキュメント](https://www.alibabacloud.com/help/ja/doc-detail/25424.htm)をチェックして、簡単に設定できるようにしてください。

次に、ローカルマシンにrubyのバージョン2.2以降、およびrailsのバージョン5以降がインストールされていることを確認してください。

ruby のバージョンが最新でない場合は、[rvm](https://rvm.io/?spm=a2c65.11461447.0.0.4cf2be33cr7xHR) や [rbenv](https://github.com/rbenv/rbenv?spm=a2c65.11461447.0.0.4cf2be33cr7xHR) などの ruby バージョンマネージャを使ってアップデートすることができます。また、rubyのバージョンを更新するには、以下の対応するコマンドのいずれかを呼び出すことができます。

```
    $ rvm install "ruby-2.4.6"  
    or  
    $ rbenv install 2.4.6

```

あるいはこのように実行して rails をアップデートすることもできます。

```
    $ gem update rails
```

そして...必要なのはこれだけです! これで、RailsでシンプルなGraphQL APIを構築する準備が整いました。

#手順
###データベースとテキストエディタの作成
このチュートリアルの一環として、以下のツールを持っていることも期待されています。

- Postgres データベース
- テキストエディタ
- 
そのためには、コマンドラインでrailsを実行して、Postgresデータベースを使用した基本的なRailsアプリケーションに必要なすべてのファイルとフォルダを作成します。

```
$ rails new todo-app `--database=postgresql`  
$ cd todo-app
```

###Gemの設定
その間に、次のようにしましょう。 Railsでgraphqlアプリケーションを作成するには、[graphql]()というgemを追加する必要があります。そして、このgemをGemfileに追加します。

`gem’graphql'`コマンドで行うことができます。そして、$ `bundle install`コマンドを実行してgemをインストールします。これでgemがインストールされているはずです。次に、GraphQL APIに必要なすべてのファイルとフォルダを作成するために、以下のコマンドを実行します。

```
$ rails generate graphql:install
```

これを実行すると、gemfileに`graphiql-rails` gemが追加されます。このgemを使用することで、APIとの対話が可能になります。

###データベースの設定
アプリケーションをPostgresデータベースに接続するには、`config/database.yml`ファイルにアクセスし、テスト環境と開発環境の両方にPostgresのユーザ名とパスワードを追加します。

```
    development:  
      <<: *default  
      database: todo_app_development  
      username: YOUR_POSTGRES_USERNAME  
      password: YOUR_POSTGRES_PASSWORD
    
    test:  
      <<: *default  
      database: todo_app_development  
      username: YOUR_POSTGRES_USERNAME  
      password: YOUR_POSTGRES_PASSWORD
```

`$ rails db:create `コマンドを実行してデータベースを作成し、`$ rails server`コマンドでサーバを実行します。

このルート `localhost:3000/graphiql` にアクセスすると、graphql クライアントが表示され、これを使って graphql サーバにリクエストを送ることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/02439c9b-aaec-65a1-4e80-7001e2268f30.png)

###モデルの作成
このtodoアプリケーションでは、`title `と`description`の2つのフィールドを持つtodoテーブルを作成します。実行してモデルを作成します。

```
   $ rails generate model Todo title:string description:text
```

データベースに入力する前に、タイトルと説明フィールドが常に指定されていることを確認することで、検証を行うことができます。`models/todos.rb`に移動し、rails validationを追加します。

```
    class Todo < ApplicationRecord  
        validates :title, presence: true  
        validates :description, presence: true  
    end
```

`$ rails db:migrate` コマンドを実行してマイグレーションを実行し、rails consoleを使用してデータベースにデータを追加します。

```
    $ rails console  

    >- Todo.create(title: 'Sample title', description: 'Sample Description')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/304b1dae-6f64-e875-282d-14a05059b258.png)

GraphQLスキーマには3つの特別な_ルート型があり、これらは`Query`, `Mutation`、`Subscription`と呼ばれています。

- Query`: データベースからデータを取得できるようにするグラフQL機能です。Rest APIのGETコールのように動作します。
- `Mutation`: クライアントがデータベースにデータを送信できるようにするグラフQL機能です。REST APIの`POST`、`PUT`、`DELETE`操作のように動作します。
- `Subscription`:サブスクリプションは、特定のイベントが発生したときにサーバーがクライアントにデータを送信することができるようにするグラフQL機能です。サブスクリプションは通常 [WebSocket](https://en.wikipedia.org/wiki/WebSocket?spm=a2c65.11461447.0.0.4cf2be33cr7xHR) で実装されます。[アクション ケーブル](https://guides.rubyonrails.org/action_cable_overview.html?spm=a2c65.11461447.0.0.4cf2be33cr7xHR)

###クエリの作成
それでは、データベースからすべてのTODOを取得するための最初のクエリを作成してみましょう。新しいファイル `app/graphql/types/todo_type.rb` を作成して todos 用の新しいタイプを作成します。


```
    #app/graphql/types/todo_type.rb
    
    module Types  
      class TodoType < Types::BaseObject  
        field :title, String, null: false  
        field :description, String, null: false  
      end  
    end
```

`BaseObject`を継承しているので、`app/graphql/types/base_object.rb`を参照してください。`GraphQL::Schema::Object`を書く代わりにGraphqlのSchema typeを継承しているので、`BaseObject`を継承するだけでオブジェクトSchemaを作成するのに必要な属性が全て得られます。

次のステップは、すべてのTodoを取得するために使用するquery typeを作成することです。`app/graphql/types/query_type.rb`に移動します。すべてのTodoを取得するために、クエリタイプに `:all_todos` という新しいフィールドを追加します。

```
    # app/graphql/types/query_type

    field :all_todos, [TodoType], null: false,  
        description: "Returns all todos"  
    def all_todos  
        Todo.all  
    end
```

`[TodoType]`の部分を追加したのは、Todoのリストを期待しているからです。さて、ブラウザに向かい、このようなクエリを書きます。

```
    query {  
      allTodos {  
        title  
        description  
      }  
    }
```

これで、データベース内のすべてのTodoを返してくれるので、タイトルを省略して説明を求めることもできますし、その逆もできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/5aff00fa-30c3-7a0f-a942-e07028b27a86.png)

###Mutationの追加
次はTodoを作成するための変異を追加します。その前に、`GraphQL::Schema::Mutation`を継承した`BaseMutation`クラスを作成してみましょう。これで今後は`BaseMutation`を継承できるようになります。

次に、`apps/graphql/mutations`フォルダ内に`base_mutation.rb`というファイルを新規作成し、このコードを追加します。

```
       # app/graphql/mutations/base_mutation.rb
        module Mutations  
          class BaseMutation < GraphQL::Schema::Mutation  
            null false  
          end  
        end
```

では、todoを追加するための変異を作成してみましょう。そのために、mutationフォルダ内に`add_todo.rb`というファイルを作成し、このコードを追加します。

```
    #app/graphql/mutations/add_todo.rb  
    module Mutations  
      class AddTodo < BaseMutation  
        argument :title, String, required: true  
        argument :description, String, required: true  
      
        type Types::TodoType  
      
        def resolve(title: nil, description: nil)  
          Todo.create!(title: title, description: description)  
        rescue ActiveRecord::RecordInvalid => e  
          GraphQL::ExecutionError.new(e.record.errors.full_messages.  
    join(','))  
        end  
      end  
    end
```

このコードは、必要な引数と返される型を指定して `AddTodo` Mutationsを追加します。

変異のコードにはレスキューブロックがあります。railsのGraphQLには、`GraphQL::Execution.new(error_messages)`というエラー処理ブロックがあります。

作成したmutationをmutation typeに追加して、クライアントからアクセスできるようにします。

```
# app/graphql/types/mutation_type.rb  
module Types  
  class MutationType < Types::BaseObject  
     field :add_todo, mutation: Mutations::AddTodo  
  end  
end
```

このクエリを使っていくつかのTodoを作成して、ブラウザ上でテストしてみてください。

```
mutation {  
  addTodo(title: "New Todo", description: "I will eat rice") {  
    title  
    description  
  }  
 }
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/f5100601-a298-0eff-e031-7db83ee02b72.png)

#GraphQLの導入
すでに持っているはずのAlibaba [ECS](https://www.alibabacloud.com/help/doc-detail/25424.htm?spm=a2c65.11461447.0.0.4cf2be33cr7xHR)インスタンスを使ってGraphQL APIをデプロイします。PassengerとNginxを使ってRailsアプリケーションを簡単にデプロイする方法は、この[チュートリアル](https://www.alibabacloud.com/blog/how-to-deploy-ruby-on-rails-with-passenger-and-nginx-on-ubuntu-16-04_593707?spm=a2c65.11461447.0.0.4cf2be33cr7xHR)に従ってください。

そしてそれをデプロイした状態で。これでいくつかのTODOSを作成し、クエリを使ってデータベースからTODOSを取得する方法もわかりました。ユーザーがログインしたり、削除したり、ToDoを更新したりできるようにするための認可と認証を行うための別の記事を書く予定です。

Alibaba Cloudのアカウントを持っていない？アカウントにサインアップして、最大1200ドル相当の[40以上の製品を無料](https://www.alibabacloud.com/ja/campaign/free-trial)でお試しください。詳細は、[Alibaba Cloudの利用開始](https://www.alibabacloud.com/ja/getting-started)をご覧ください。

*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*