

### 前提・実現したいこと

Rubyで外部APIを使用し、配達の集荷状況が確認出来るWebアプリを作っています。  
APIを連携出来たものの、Viewだと`無効なAPI`と表示されてしまい、どこをどのように直したら良いのか分かりません。コードの編集方法および外部APIの実装方法が誤っている場合、そちらを教えていただきたいです。

  * 使用している外部API：[Tracking more](https://www.trackingmore.com/ja.html)
  * [コードを書いた上で参考にしたページ](https://www.trackingmore.com/api-ruby.html)

### 発生している問題・エラーメッセージ

![index画面（検索画面）](https://i.stack.imgur.com/nCf1r.png)

![画像の説明をここに入力](https://i.stack.imgur.com/1MTyw.png)

### 該当のソースコード

  * collecting-status_controller.rb

```

[code]

    class CollectingStatusController < ActionController::Base
    class Trackingmore
        require 'uri'
        require 'net/http'
        require 'net/https'
        require 'json'
        def tracker(url,postData,method)
            headers ={'Content-Type' =>'application/json','Trackingmore-Api-Key':'my api key'}
            if postData.empty?
                @toSend =""
            else
                @toSend =postData.to_json
            end
            uri = URI.parse(url)
            https = Net::HTTP.new(uri.host,uri.port)
            if method =="GET"
                req = Net::HTTP::Get.new(uri.path,headers)
            elsif method =="POST"
                req = Net::HTTP::Post.new(uri.path,headers)
            elsif method =="PUT"
                req = Net::HTTP::Put.new(uri.path,headers)
            elsif method =="DELETE"
                req = Net::HTTP::Delete.new(uri.path,headers)
            else
                puts "parameter method is wrong!"
            end
            req.body = "#{@toSend}"
            res = https.request(req)
    
            return res
        end
    end
    end
    
[/code]

```

  * index.html.erb

```

[code]

    <!-- [1] classとactionを変更します -->
    <form class="index" action="https://api.trackingmore.com/v2" method="post">
    
      <div class="container">
        <div class="flex space-between">
          <div class="articlesNews-leftContent">
            <div class="article-MainBlock">
              <form action="/connpass_clients" accept-charset="UTF-8" method="get"><input name="utf8" type="hidden" value="✓">
                <div class="flex">
                  <div class="p-t-b-5">伝票番号</div>
                  <div><input type="text" name="form_words" id="form_words" placeholder="東京都 プログラミング"></div>
                </div>
                <div class="text-10">スペース カンマで複数検索可</div>
                <div class="flex m-t-b-30">
                  <div>配達日時</div>
                  <div><select id="start_date_year" name="start_date[year]">
                      <option value="2017">2017</option>
                      <option value="2018" selected="selected">2018</option>
                      <option value="2019">2019</option>
                    </select>
                    <select id="start_date_month" name="start_date[month]">
                      <option value="1">1</option>
                      <option value="2">2</option>
                      <option value="3">3</option>
                      <option value="4">4</option>
                      <option value="5">5</option>
                      <option value="6">6</option>
                      <option value="7">7</option>
                      <option value="8">8</option>
                      <option value="9" selected="selected">9</option>
                      <option value="10">10</option>
                      <option value="11">11</option>
                      <option value="12">12</option>
                    </select>
                    <input type="hidden" id="start_date_day" name="start_date[day]" value="1">
                  </div>
                  <div>~</div>
                  <div><select id="end_date_year" name="end_date[year]">
                      <option value="2017">2017</option>
                      <option value="2018" selected="selected">2018</option>
                      <option value="2019">2019</option>
                    </select>
                    <select id="end_date_month" name="end_date[month]">
                      <option value="1">1</option>
                      <option value="2">2</option>
                      <option value="3">3</option>
                      <option value="4">4</option>
                      <option value="5">5</option>
                      <option value="6">6</option>
                      <option value="7">7</option>
                      <option value="8">8</option>
                      <option value="9" selected="selected">9</option>
                      <option value="10">10</option>
                      <option value="11">11</option>
                      <option value="12">12</option>
                    </select>
                    <input type="hidden" id="end_date_day" name="end_date[day]" value="1">
                  </div>
                </div><input type="submit" name="commit" value="Search">
    
[/code]

```

### 補足情報（FW/ツールのバージョンなど）

ruby ver  
2.3.3p222 (2016-11-21 revision 56859)

Rails ver  
Rails 5.1.6


CC BY-SA 4.0
2018-09-22T09:01:02.463
48641
2018-09-23T06:29:16.197
30202
question
ruby-on-rails ruby
Rubyで外部APIを使用し、集荷状況を表示したい。


まだコメントに対する返信がいただけていないのですが、「画像の2枚目、これは上の画像の「Search」ボタンを押したらブラウザ画面に表示された(もしくはダウンロードが始まって、ダウンロード完了したファイルをエディタなどで開いた)もの」と言うことと掲載の
**`index.html.erb`** は、`CollectingStatusController`用のビューであると言うのを仮定しています。

一番の問題点は、 **`index.html.erb`** のこの行です。

[code]

    <form class="index" action="https://api.trackingmore.com/v2" method="post">
    
[/code]

これではブラウザから直接APIサーバにリクエストが送られることになりますが、ブラウザはpostリクエストをJSONに変換してくれたりはしませんし、HTTPヘッダーにAPIキーを入れたりもしてくれません。APIキーの入っていないリクエストを送っているので、APIサーバの側が`{"code":4001,"type":"Unauthorized","message":"Invalid
API key"}`というメタ情報の応答をブラウザに返しているものと思われます。

(ご使用中のブラウザのURL窓に直接`https://api.trackingmore.com/v2`と入力しても、同じ応答が見られるはずです。)

あちこち動きを確かめながら、少しずつコードを書いていっておられるのでしょうが、今のコードではRuby版のAPI呼び出しが動くかどうかを試すには足りなさすぎます。Ruby側のコードとしてAPI呼び出しクラス(`Trackingmore`)を使用するようなコードを書いてやらないといけません。

先の1行を次のように置き換えて見てください。

### **`index.html.erb`**

[code]

    ...
    <form class="index" action="<%= url_for :controller => 'collection_status', :action => 'search' %>" method="post">
    ...
    
[/code]

(コントローラ名やアクション名は実際のWebアプリの構成によっては書き換えないといけないでしょうが、以下はこの内容を仮定しています。実際の構成によっては適宜読み替える必要があります。)

これで、ブラウザからは`CollectingStatusController`にリクエストが送られるので、それを処理するメソッドが必要になります。

ただ、 **`collecting_status_controller.rb`**
をいじる前に`Trackingmore`クラスが`CollectingStatusController`の内側にネストして定義されているのは改めた方が良いでしょう。

Railsであれば必ず **`app`** ディレクトリがあると思いますが、その下に **`lib`**
ディレクトリを作り(似た目的のディレクトリが既にあるならそこでも良いです)そこに公式サイトからダウンロードした **`trackingmore.rb`**
を以下の1行のみ修正した上で置いてください。

### **`app/lib/trackingmore.rb`**

[code]

    ...
        headers ={'Content-Type' =>'application/json','Trackingmore-Api-Key'=>'実際のAPIキー'}
    ...
    
[/code]

これが終わったら、 **`collecting_status_controller.rb`**
には`search`メソッドを追加する必要があります。(もちろん`Trackingmore`クラスの定義部分は全部削除。)

全体はこんな雰囲気になるでしょう。

### **`collecting_status_controller.rb`**

[code]

    ...
    
    class CollectingStatusController < ActionController::Base
    
      def search
        #params内のパラメータを取り出してpostDataを作成する(必要なら検証してエラー処理)
        #post_data = ...
        #利用したいサービスのURLを文字列として用意しておく
        url = 'https://api.trackingmore.com/v2/trackings/updatemore'
        #参考ページに書いてある呼び出し方ほぼそのまま
        tracker = Trackingmore.new
        res = tracker.tracker(url, post_data, 'POST')
        #res.codeなんかも調べて、エラーがなければ、res.bodyをJSONとして解析する
        #json = ...
        #jsonの中身がエラーじゃないかのチェックも必要かも
        #...
        #解析したJSONからviewへ渡すデータを作成
        #@search_results = ...
        #結果表示用のviewを表示
      end
    
    end
    
[/code]

`post_data`をリクエストパラメータを作るのは結構大変でしょうが、APIがうまく呼べているかどうかの確認だけなら、とりあえずダミーのデータを作ってやれば良いでしょう。結果確認用のビュー(
**`search.html.erb`** )も作成する必要があるでしょうが、それはどんな結果を見たいのかによるので、ここでは置いておきます。

* * *

色々不明な点もあるのと、実際に動かして確かめたわけではないこともあって何かと不完全な部分があるでしょうが、修正の方向性は一通り盛り込んだつもりです。参考にしていただければ幸いです。


CC BY-SA 4.0
2018-09-23T06:16:30.023
48652
2018-09-23T06:29:16.197
2018-09-23T06:29:16.197
13972
13972
48641
answer