[Rails]APIを使って仮想通貨の価格を取得する

最近は多くの取引所でAPIが公開されており、APIキーを取得することで仮想通貨の取引をすることが可能です。また、価格を取得するだけならAPIキーを用意しなくても利用が可能です。
ポートフォリオを作成する際にAPIを使って仮想通貨の最新価格を取得することがあったので簡単に紹介します。

## 使用するAPI
今回はbitbankのAPIを使用します。
[bitbank.cc API ドキュメント](https://docs.bitbank.cc/)
現在のビットコインの価格を取得する際には以下のurlにリクエストを送ります。
https://public.bitbank.cc/btc_jpy/ticker

他にも[Zaif](https://techbureau-api-document.readthedocs.io/ja/latest/)や[Cryptowatch](https://cryptowat.ch/docs/api)などがあります。

## 環境

### バージョン
```terminal
$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin18]
$ rails -v
Rails 5.2.3
```

### 導入gem

```ruby
gem 'bootstrap', '~> 4.1.1'
gem 'jquery-rails'
gem 'haml-rails'
```
今回はjQueryを使用してAjax通信をします。また、レイアウトを整えるためにBootstrapを入れています。ビューにはhamlを採用しています。

## ルーティング
### クロスドメイン制約
Ajaxを使ってAPIからデータを取得する時に注意しなければならないのがクロスドメイン制約です。APIサーバーがクロスドメイン制約をかけている場合は、chromeなどのwebブラウザがAccess-Control-Allow-Originのエラーを出すので表示することができません。
詳しくはこちら↓
https://wa3.i-3-i.info/word15224.html

bitbankはクロスドメイン制約がかかっていないのでjsファイルから直接APIにリクエストを送ってもいいのですが、今回はクロスドメイン制約がかかっているAPIにも対処できるようにコントローラー経由でリクエストします。(ZaifやCryptowatchはクロスドメイン制約がかかっています)
リクエストとデータの流れは以下のようになります。
<img width="946" alt="スクリーンショット 2019-07-06 22.02.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400652/7c1eea7a-8dd8-0035-35a8-faac2f39bf0b.png">


なので、今回は名前空間を使って以下のようなルーティングにします。

```ruby:routes.rb
Rails.application.routes.draw do
  root 'money#index'
  resources :money, only: :index
  namespace :api do
    resources :money, only: :show, defaults: { format: 'json' }
  end
end
```

## ビュー

```haml:views/money/index.html.haml
.container.mt-5
  %table.table.table-bordered.col-12
    %thead.bg-warning
      %tr
        %th 仮想通貨
        %th 略称
        %th レート(仲値)
        %th 買値
        %th 売値
    %tbody
      %tr
        %th ビットコイン
        %td BTC
        %td.middle-rate 取得中
        %td.buy-order-value 取得中
        %td.sell-order-value 取得中
```

今回はビットコインの価格を取得してみます。
jsファイルを作る前はこんな感じになります。
<img width="969" alt="スクリーンショット 2019-07-06 15.59.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400652/4b9482bc-4e83-ac45-d4c5-0f314c01f3f0.png">



## コントローラー
controllersフォルダ直下のコントローラーとcontrollers/apiフォルダのコントローラーは以下のようになります。

```ruby:controllers/money_controller.rb
class MoneyController < ApplicationController
  def index
  end
end
```
今回はcontrollersフォルダ直下のコントローラーでは何もしません。適宜処理を追加してください。

```ruby:controllers/api/money_controller.rb
class Api::MoneyController < ApplicationController
  def show
    # 今回の場合 params[:id] => "btc"
    url = URI.parse("https://public.bitbank.cc/#{params[:id]}_jpy/ticker")
    # response_textに返ってきた値が入る
    response_text = Net::HTTP.get(url)
    # response_textは文字列なのでパースしてハッシュに変換する
    response_hash = JSON.parse(response_text)
    # jsファイルに送る
    render json: response_hash
  end
end
```

apiフォルダ直下のコントローラーではjsファイルからのリクエストがあった場合にAPIサーバーにリクエストを送り、json形式で値を送ります。

この時、取得した値の中身は以下のようになっています。

```json
{"success":1,"data":{"sell":"1243454","buy":"1243434","high":"1260896","low":"1173374","last":"1243434","vol":"2853.7095","timestamp":1562397567490}}
```
`buy`に買値、`sell`に売り値が入ってるのでjsファイル中でそれぞれの値を取り出します。

## jsファイル

```javascript:application.js
//= require rails-ujs
//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require_tree .
```

```javascript:ticker.js
$(function() {
  // api/money_controllerに送る
  let requestUrl = '/api/money/btc';
  $.ajax({
    url: requestUrl,
    type: 'get',
    dataType: 'json'
  })
  .done(function(json) {
    // 買値、売値を取り出す
    let sell_order_value = Number(json.data.sell);
    let buy_order_value = Number(json.data.buy);
    // 仲値を計算する
    let middle_rate = (sell_order_value + buy_order_value) / 2;
    middle_rate = Math.round(middle_rate);
    // 買値、売値、仲値のテキストを挿入する
    $(".buy-order-value").text(buy_order_value.toLocaleString() + " 円");
    $(".sell-order-value").text(sell_order_value.toLocaleString() + " 円");
    $(".middle-rate").text(middle_rate.toLocaleString() + " 円");
  })
  .fail(function() {
    alert('error');
  });
})
```

今回はレートして買値と売値から仲値を計算しています。
これで以下のようにビューに価格が表示されるはずです。
<img width="921" alt="スクリーンショット 2019-07-06 16.27.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400652/ff7c05d3-9835-acfe-3892-fd95b1d17b0a.png">

## 最後に
今回はbitbankのAPIを利用してビットコインの価格を取得してみました。
bitbankでは他にもモナコイン、ビットコインキャッシュ、リップル、イーサリアム（ビットコインの価格に対してのみ）の価格が取得できるので、ループ処理をすれば一覧表示することも可能です。
自動更新を入れれば常に最新価格を表示することも可能です。
どこかおかしなところがあればご指摘お願いします。