Rails 初めてのAPIモード

##概要
こんにちは。
今回は始めてRailsでAPIを作成してみたのでその備忘録を残したいと思います。

以下を使いました。

- ツール
 - Postman(レスポンスを確認するためのツール)

- gem
 - active_model_serializers

今回はUserを管理できるAPIを作ります。

事前にこちらの記事を読んで作成しております。
https://qiita.com/Kaki_Shoichi/items/d4adcf0298ed0b4614a2
https://qiita.com/c5meru/items/1c921676de8a5a038f70
https://qiita.com/yyh-gl/items/30bd91c2b33fdfbe49b5

##仕様
- jobテーブルとuserテーブルは1対多の関係にある。


- jobとuserを登録できる。
 - userはjob_idを外部キーに持つ
 - job_nameとusernameというリクエストを送る
 - すでにjob_nameが存在しているときはそのIDを外部キーに、job_nameがない場合は新しくjobを作成しそのidを外部キーとする。

- user一覧を取得できる。
 - リクエストにvalueを含めない場合は全てのuserを表示させる。
 - リクエストにjob_nameを指定した場合は該当するuserのみを表示させる。

以上の仕様で作成したいと思います。


それでは早速始めていきます。

##導入

まずはapiモードでRailsを作成してください。

```
$ rails new testapi --api
```
以下のgemをインストールします。

```
gem 'active_model_serializers'
```



## テーブル作成

以下のようにテーブルとカラムを作成します。


```ruby:db/schema.rb
  create_table "jobs", force: :cascade do |t|
    t.string "name", null: false
    t.index ["name"], name: "index_jobs_on_name", unique: true
  end

  create_table "users", force: :cascade do |t|
    t.text "username", null: false
    t.integer "job_id", null: false
    t.index ["job_id"], name: "index_users_on_job_id"
  end
```

## モデル
モデルのバリデーションは次のようにしました。

```ruby:job.rb
class Job < ApplicationRecord
  has_many :users, dependent: :destroy
  validates :name, uniqueness: true, presence: true
end

```

```ruby:user.rb
class User < ApplicationRecord
  belongs_to :job
  validates :username, presence: true
  validates :job_id, presence: true
end
```

## ルーティング
api作成時はバージョン管理しやすい設計が推奨されているようです。
また今回はusers_contorollerのみを使用して機能実装を行います。

```ruby:config/routes.rb
Rails.application.routes.draw do
  namespace 'api' do
    namespace 'v1' do
      resources :users, only: [:create, :index]
    end
  end
end
```

## コントローラ
users_controllerはこのように作成致しました。

```ruby:users_controller
module Api
  module V1
    class UsersController < ApplicationController
      before_action :set_job

      def create
        @job = Job.create(name: user_params[:job_name]) if @job.blank?
        user = User.new(username: user_params[:username], job_id: @job.id)
        if user.save
          render status: :created, json: { status: 201 }
        else
          render status: :unprocessable_entity, json: { status: 422 }
        end
      end

      def index
        if user_params[:job_name].nil?
          users = User.all
          render json: users
        elsif @job.nil?
          render status: :not_found, json: { status: 404 }
        else
          users = @job.users
          render json: users
        end
      end

      private

      def user_params
        params.permit(:username, :job_name)
      end

      def set_job
        @job = Job.find_by(name: user_params[:job_name])
      end
    end
  end
end

```

##レスポンスを整形
次にjsonで返すレスポンスを整形します。
導入でインストールしたactive_model_serializersを使用します。

※　色々調べたのですが、現在は fast_json_apiというgemの方が推奨されているようです。使い方はほとんど変わらないようですが、レスポンスがシンプルだったので今回はamsを使用しました。

こちらの記事を参考にさせて頂きました。
https://qiita.com/m_nakamura145/items/75fd7c0934daf9bcc21d

使い方は以下の通りです。
まずはコマンドで必要なファイルを作成します。

```
$ rails generate serializer User
```
app/serializers/model_serializer.rbファイルが作成されます。
作成されたファイルを以下のように記述します。

```ruby:serializers/user_serializer.rb
class UserSerializer < ActiveModel::Serializer
  attributes :id, :job, :username
  belongs_to :job
  def job
    object.job.name
  end
end

```
これでjsonレスポンスに独自のパラメータを追加して返すことができます。

##リクエスト

ではPostmanを使用してリクエストし、レスポンスをみてみます。
[Postman](https://www.postman.com/)

まずはルーティングを確認します。

```
$ rake routes

api_v1_ideas GET    /api/v1/users(.:format)   api/v1/users#index
             POST   /api/v1/users(.:format)   api/v1/users#create
```

それではPostmanで上記URLにリクエストを送ってみます。(rails s　してください。）
画像左上をpostに変更してください。

<img width="1124" alt="スクリーンショット 2020-04-30 17.00.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509166/ce015e14-7bdc-8a00-2afe-919b44cd3d70.png">

すると以下のようなレスポンスが得られました。

```
{
    "status": 201
}
```

これでレコードを登録することができました。

次は作成したレコードを取得してみます。
画像左上をgetに変更してください。

<img width="1124" alt="スクリーンショット 2020-04-30 17.05.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509166/19dd9bb1-2434-1ba9-9b34-bb0e772afc8c.png">

```
[
    {
        "id": 1,
        "job": "testjob1",
        "username": "testuser"
    }
]
```

先ほど登録したレスポンスを得られました。

ここでkey,valueを設定しない場合は登録している全てのレコードを取得することができます。


以上です。

APIの記事がそもそも少なかった事と、1対多関係にあるテーブルに独自のパラメータをリクエストする方法がなかなか見つからなかったのでかなり時間がかかりました。

お付き合い頂きありがとうございました。