Grapeを使ってRESTfulAPIサービスを作成する

#概要

grapeを使用してRESTfulなAPIサービスを作成したのでまとめる。
また作成後はPostmanを使用して挙動を確認した。

##環境

```
ruby 2.6.5

Rails 5.2.4
```

#実施したこと

・任意のUserをSeedsファイルに作成。gemはgrapeを使用。APIモードにて作成する。

・Postmanを使ってクライアントからアクセスし、データの登録、更新、削除。データの取得を行う
・アプリケーションには一般的なCRUD機能とデータの取得をJSONを用いて取得できるよう作成した

まずアプリケーションを作成

```ruby:console
$ rails new sample_app
```


今回はアプリ名「sample_app」とした。

まずはgemをインストール

下記を追記

```ruby:Gemfile

gem ‘grape’　# rails、sinatraなどのRackアプリケーションで、RESTfulAPIを簡単に構築できる
gem 'grape-entity’ # grapeのみだと、値が全て表示されてしまう。grape-entityを使うと、表示項目の制限、整形をすることができる。
gem ‘grape_on_rails_routes’  #使用すると、Grape APIによって作成されたルートを簡単に読み書きできる。
```

続い bundle instalする。

```
$ bundle install --path vendor/bundle
```



#DBの構成

Usermodelを生成する

```ruby:console
$ bundle exec rails g model User name:string email:string age:integer
$ rails db:migrate
```


サンプル用にデータを用意します。

db/seeds.rbを下記の内容で作成します。

```ruby:db/seeds.rb
User.create(name: 'Sony', email: 'sony@sample.com', age: '40')
User.create(name: 'Fredo', email: 'fred@sample.com', age: '38')
User.create(name: 'Tom', email: 'tom@sample.com', age: '35')
User.create(name: 'Michael', email: 'michael@sample.com', age: '33')
User.create(name: 'Connie', email: 'connie@sample.com', age: '30')
```

DBにファイルを読み込ませます。

```
$ bundle exec rake db:seed
```

#ディレクトリ構成

下記のディレクトリ構成にします。

```
~/sample_api/
　　├ app/api/
　　│　　　　└ api.rb
　　│　　　　└ resources/
　　│          └ v1/
　　│            └ root.rb
　　│　　　　　　  └ user.rb
　　│       └ entities/
　　│　　　　　　└ v1/
　　│　　　　　　　 └ root_entity.rb
　　│　　　　　　　 └ user_entity.rb
```


#autoloadの設定

app/apiの下のファイルがautoloadされるようにします。

```ruby:config/application.rb
module SampleApi
  class Application < Rails::Application
    #..  
    # app/api以下のrbファイルをautoload
   + config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
   + config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
  end
end
```

#APIの作成

下記の図のような[親-子-孫-ひ孫]の関係でマウントさせます。

```
config/routes.rb  # [親]ルーティングの設定
  └ app/api/api.rb # [子]API親クラス
      └ app/api/resources/v1/root.rb # [孫]API v1の親クラス
          └ app/api/resources/v1/users.rb # [ひ孫]userAPIのクラス
```

[親] config/routes.rb

ルーティングの設定をします。

```config/routes.rb
Rails.application.routes.draw do
# app/api/api.rbをマウント
+ mount API => ‘/'　#この方法では、基本クラスがクラスの各アクションをポイントするため、各アクションにルートを追加する必要はありません。
end
```

[子] app/api/api.rb

API親クラスを作成します。

```app/api/api.rb
class API < Grape::API
  # urlの第１セグメント名 ex) http://localhost/api/
  prefix 'api'
  # app/api/resources/v1/root.rbをマウント
  mount Resources::V1::Root
end
```

[孫] app/api/resources/v1/root.rb

API v1の親クラスを作成します。

```app/api/resources/v1/root.rb
module Resources
  module V1
    class Root < Grape::API
      version 'v1'
      format :json
      content_type :json, 'application/json'

      # app/api/resources/v1/users.rbをマウント
      mount Resources::V1::Users
    end
  end
end
```

​
続いてuserAPIのクラスを作成する前にEntityファイルを作成します。
これを作成しないとデータ取得を行った際に作成時間や更新時間など、表示したくないデータが表示されてしまいます。
＊全てのデータを取得したい場合は作成不要。


#Entityの親クラスを作成

```app/api/entities/v1/root_entity.rb
module Entities
  module V1
    class RootEntity < Grape::Entity

    end
  end
end
```

#userAPIのEntityファイルを作成

name, email, ageのみ表示するようにします。

(created_at、updated_atは表示させない)

```app/api/entities/v1/user_entity.rb
module Entities
  module V1
    class UserEntity < RootEntity
      # name, email, ageのみ表示する
      expose :name, :email, :age
    end
  end
end
```


userAPIのクラスを作成します。

```app/api/resources/v1/user.rb
module Resources
  module V1
    class Users < Grape::API
      resource :users do
        desc "user list"
        get do
          present User.all, with: Entities::V1::UserEntity 　#　with:〜〜とすることでentityファイルの内容を適用させます
        end

        desc "create new user"
        params do
          requires :name, type: String
          requires :email, type: String
          requires :age, type: Integer
        end
        post do
          User.create!({ name: params[:name], email: params[:email], age: params[:age] })
        end

        desc "Update user"
        route_param :id do 
          put do
            User.find(params[:id]).update({ name: params[:name], email: params[:email], age: params[:age] })
          end
        end

        desc "show user"
        params do
          requires :id, type: Integer, desc: "user id"
        end
        get ":id" do
          present User.find(params[:id]), with: Entities::V1::UserEntity　#　こちらのデータ取得も同様です。
        end

        desc "Delete user"
        route_param :id do
           delete do
             user = User.find(params[:id])
             user.destroy
           end
        end
      end
    end
  end
end
```
```
$ rails grape:routes or rake grape:routes
        GET  |  /api/:version/users(.:format)      |  v1  |  user list      
       POST  |  /api/:version/users(.:format)      |  v1  |  create new user
        PUT  |  /api/:version/users/:id(.:format)  |  v1  |  Update user    
        GET  |  /api/:version/users/:id(.:format)  |  v1  |  user_show      
     DELETE  |  /api/:version/users/:id(.:format)  |  v1  |  Delete user
```

###上記のコマンドを実行すると、グレープAPIルートのリストを確認できます。



ここまででAPIを作成できました。ここからはPostmanを使用することで実際にCRUD機能、データ取得を正しく行えるか確認していきます。

* user情報を全て取得する
    * http://localhost:3000/api/v1/users
* 指定したidのuser情報を1件取得する
    * http://localhost:3000/api/v1/users/{:id}

rails起動後上記URIを入力すれば取得の確認が行える。

#Postmanを使ってリクエスト、レスポンスの確認
PostmanのURL
https://www.postman.com/
![スクリーンショット 2020-09-18 17.38.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599304/8c249fef-f569-48ec-6976-5cffaf61e181.png)

Postmanを起動
登録は指示に従っていけば簡単に行えます。

#ローカルサーバー起動

```
$ rails s
```



#データを作成(Create)

Bodyに登録するデータをJSON形式で設定して、実行する
###メソッド：Post

URL：http://localhost:3000/api/v1/users

Body: raw JSON(application/json)

```ruby:Body
{
  “name”: “サンプルさん”
  “email”: “sample@example.com”
  “age”: 19
}
```

Postmanを上記に設定変更しsendボタンを押す
![スクリーンショット 2020-09-18 16.20.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599304/71e890e2-560a-2c1e-b3e7-98e439ead5cf.png)



下記欄に6番目のidで新たにuserが登録されていることが分かる。

#データの編集(update)

登録した情報を更新する。
Body要素に変更する情報を設定する。
###メソッド：Put

URL：http://localhost:3000/api/v1/users/:id
(:idはdbに登録されているid値　ここでは6を設定)

Body:raw JSON(application/json)

```ruby:Body
{
  “name”: “サンプル”
  “email”: “sample1@example.com”
  “age”: 20
}
```

![スクリーンショット 2020-09-18 16.24.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599304/6a99aeb2-3858-686f-ecd5-080e2748f3bb.png)

updateが行われている。

#データの削除(destroy)

登録している情報を削除する
###メソッド：Delete

URL：http://localhost:3000/api/v1/users/:id

(:idはdbに登録されているid値　ここでは6を設定)


![スクリーンショット 2020-09-18 16.29.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599304/f142d852-a1fa-3f82-a4ab-effe1b36f282.png)

先程作成したデータを削除することに成功した。

###データの取得(index)

登録した情報をすべて取得する。Seedsデータとして登録されている５つのデータを取得してみる。
###メソッド：Get
URL：http://localhost:3000/api/v1/users


![スクリーンショット 2020-09-18 16.20.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599304/081a9633-b7d4-854a-dbcc-91615cc6ebca.png)

下記に登録されているデータが確認できる。


#データをid別に取得(show)

登録した情報からidを指定して、特定の情報のみを取得する(削除される前のid:6のデータ情報を取得しています。)

###メソッド：Get
URL：http://localhost:3000/api/v1/users/:id


![スクリーンショット 2020-09-18 16.24.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599304/83254072-50ba-0714-516b-af03f689f0c6.png)

CRUD機能の挙動については確認することができた。Postmanの機能についてはまだ勉強不足であるので深めていく。

またgrape　gemについてもまだ様々な機能があるのでそこも学習し、使いこなせるようにしていく。


＊参考　　API開発・テスト便利ツール Postmanの使い方メモ
https://qiita.com/zaburo/items/16ac4189d0d1c35e26d1

＊参考　　Postmanを使ってAPIの確認をしてみる
https://qiita.com/me-654393/items/b14824dd9b37de0da163

＊参考　　RESTFUL API USING GRAPE IN RAILS
https://www.nascenia.com/restful-api-using-grape-in-rails/

＊参考　　grapeのgithub
https://github.com/ruby-grape/grape