apiのrspecを記載する時のjsonの記載方法

apiのrspecを記載する時のjsonの記載方法を備忘録としてまとめます。

rspecでapiをリクエストする際に以下の記載にするとidの数値が文字列になってしまう。

spec/requests/〇〇_spec.rb

    let(:headers){ { 'Authorization' => "Token token=\"#{admin.authentication_token}\"", 'Accept' => 'application/json' } }
    let(:api_url){ "/api/v2/admin/test.json" }

    context '時間を更新する場合' do
      let(:params) do
        {
          order: {
            time_id: 1
          }
        }
      end
      subject!{ put api_url, params: params, headers: headers }

上記specを実行してコントローラー側でデバッグすると以下のよう[time_id]が文字列の"1"になってしまう。

app/controllers/〇〇/api/v2/admin/〇〇_controller.rb

def update
  binding.pry
end

[1] pry> params
=> <ActionController::Parameters {"order"=><ActionController::Parameters {"time_id"=>"1"} permitted: false>

これは、パラメーターとして[time_id]が送られているが、json形式で送られていないので、文字列になってしまう。 integerとしてパラメーターを送るためには、json形式でパラメーターを送らなければいけない。 params はリクエスト(HTTP)を通して入ってくるので、全ての値は基本的に文字列(String)として扱われるため。

以下のようにパラメーターに[to_json]を記載することで、パラメーターをjson形式にする

spec/requests/〇〇_spec.rb

    let(:headers){ { 'Authorization' => "Token token=\"#{admin.authentication_token}\"", 'Accept' => 'application/json' } }
    let(:api_url){ "/api/v2/admin/test.json" }

    context '時間を更新する場合' do
      let(:params) do
        {
          order: {
            time_id: 1
          }
        }.to_json
      end
      subject!{ put api_url, params: params, headers: headers }

上記specを実行してコントローラー側でデバッグすると以下のようパラメーターの形式が通常と違う形になってしまう。

app/controllers/〇〇/api/v2/admin/〇〇_controller.rb

def update
  binding.pry
end

[1] pry> params
=> <ActionController::Parameters {"{\"order\":{\"time_id\":1}}"=>nil, "controller"=>"〇〇/api/v2/admin/〇〇", "action"=>"update", "id"=>"1381", "format"=>"json"} permitted: false>

これは、パラメーターとして[time_id]をjson形式で送っているが、headersに[Content-Type]として[application/json]を記載しないと、json形式で送れないし、受け取ることもできない為である。

以下のようにパラメーター記載することで、パラメーターをjson形式で送れるようになる

spec/requests/〇〇_spec.rb

    let(:headers){ { 'Authorization' => "Token token=\"#{admin.authentication_token}\"", 'Accept' => 'application/json' } }
    let(:api_url){ "/api/v2/admin/test.json" }

    context '時間を更新する場合' do
      let(:params) do
        {
          order: {
            time_id: 1
          }
        }.to_json
      end
      subject!{ put api_url, params: params, headers: headers.merge({ 'Content-Type' => 'application/json' }) }

上記specを実行してコントローラー側でデバッグすると以下のよう形式になっており、正しくパラメーターが送られている。

app/controllers/〇〇/api/v2/admin/〇〇_controller.rb

def update
  binding.pry
end

[1] pry> params
=> <ActionController::Parameters {"order"=>{"time_id"=>1}, "controller"=>"〇〇/api/v2/admin/〇〇", "action"=>"update", "id"=>"1382", "format"=>"json", "order"=><ActionController::Parameters {} permitted: false>} permitted: false>