読者です 読者をやめる 読者になる 読者になる

手取り足取りプログラミング

cloud9、railsについて自分がつまずいた所を詳しく説明します。なぜなら一番読み返すのは自分だから。

【Rails】RESAS APIを使ってみた 後半

前回の記事の続きです。
yonayonaru.hatenablog.com

やること

  1. 今回はRESAS APIを利用して都道府県を取得し、ドロップダウンリストで選択する画面を作成します(前回の記事)
  2. 選択した都道府県の人口構成を表示する画面を作成します(今回の記事)※予定

RESAS APIとは

f:id:yonayonaru:20170205235716p:plain
RESASは地域経済分析システムのことで、そのデータを取得するAPIです。
内閣府 地方創生推進室が提供しています。

バージョン

ruby 2.3.0
Rails 4.2.5

Model

人口構成取得時のパラメータ

前回の都道府県取得にはパラメータは不要でした。
今回はパラメータが3つ(うち2つは必須)となっています。
パラメータは下記の通り

  • prefCode:(必須)都道府県コード。前回の記事で作成したページから選択した都道府県コードを渡す。
  • cityCode:(必須)市町村コード。今回は「すべての市町村」を選択するため「-」を送ります。
  • addArea:(任意)追加エリアコード。任意なので今回は指定しません。

f:id:yonayonaru:20170206221306p:plain

Modelの記述

上記パラメータを踏まえてModelに人口構成を取得する関数を作成します。
都道府県コードを引数で受け取って、RESAS APIにパラメータとして渡しています。
赤字部分(self.get_populationCompositionPerYear)が前回からの追加箇所です。

app/Models/resas_api.rb

class ResasApi < ActiveResource::Base
  self.site = "https://opendata.resas-portal.go.jp/"
  self.format = :json
  HEADER_API = 'X-API-KEY'
  API_KEY = 'ここに取得したAPIキーを入力してね'
    
  def self.get_prefectures()
    self.headers[HEADER_API] = API_KEY
    self.find(:one, from: '/api/v1/prefectures')
  end
  
  def self.get_populationCompositionPerYear(prefCode)
    self.headers[HEADER_API] = API_KEY
    self.find(:one, from: '/api/v1/population/composition/perYear',
      params: {prefCode: prefCode, cityCode: '-'})
  end
end

Controller

赤字部分(populations)が前回からの追加箇所です。
prefecturesとほとんど同じですが、prefecturesで選択した都道府県コードをパラメータから取得して人口構成取得の関数に渡しています。

app/controller/home_controller.rb

>

class HomeController < ApplicationController

def prefectures
get = ResasApi.get_prefectures()
@statuscode = get.attributes['statusCode']
@message = get.attributes['message']
@result = get.attributes['result']
end

def populations
prefCode = params['prefCode']
get = ResasApi.get_populationCompositionPerYear(prefCode)
@statuscode = get.attributes['statusCode']
@message = get.attributes['message']
@result = get.attributes['result']
end

end

View

人口構成取得時のレスポンス

都道府県取得の時より複雑になっています。
総人口、年少人口、生産年齢人口、老年人口をまとめて取得しているからです。
/result/data の中にdataが4つあってそれが上の4項目です。
さらに/result/data/data/rateは総人口には存在しません。
(なぜ項目毎に別々にしなかったのか)
f:id:yonayonaru:20170206223342p:plain

Viewの記述

以上を踏まえて少し面倒くさい書き方になりました。
総人口でrateを取得しようとするとエラーになるので、1回目のループ(総人口)ではrateを取得しないようにしています。
(なぜ項目毎に別々にしなかったのか、マジで)

<h1>人口構成</h1>
<% if @message %>
    <%= @statuscode %>
    <%= @message %>
<% else %>
    <% @result.data.each_with_index do |result, i| %>
      <h2><%= result.label %></h2>
        <table class=table %>
            <thead>
                <tr>
                    <th>年</th>
                    <th>人口</th>
                    <th>割合</th>
                </tr>
            </thead>
            <tbody>
                <% result.data.each do |data| %>
                    <tr>
                        <td><%= data.year %></td>
                        <td><%= data.value %></td>
                        <td>
                            <% if i > 0 %>
                                <%= data.rate %>
                            <% end %>
                        </td>
                    </tr>
                <% end %>
            </tbody>
        </table>
    <% end %>
<% end %>

エラーについて

エラーが起きた場合は下図のようにステータスコードとメッセージを表示されます。
f:id:yonayonaru:20170206230056p:plain

403 Forbidden

APIキーが正しく設定されていない場合などで発生します。
Modelの各関数内でヘッダをしてしていますが、self.siteと同じ箇所で指定するとこのエラーが出ます。

404 Not Found

URLが間違っていた場合などに発生します。
この時の@messageにはステータスコードが入ってきません。が、404の@messageにはステータスコードが入ってきます。
そのため今回の実装だと、404エラーの時には@statuscodeにも@messageにも404が入ってくるので、表示としては「404 404. That's an error.」となります。
なぜ統一しないのか?

429 Too Many Requests

このAPIは利用回数が決まっています。
以下のいずれかを超えた時にこのエラーが出るようです。

  • 1秒あたりのリクエスト平均数:5
  • リクエスト数/日:1000

ちょっと回数制限が少なすぎるような気がします。
毎日更新されるようなデータではないので、利用者のアクセス毎に毎回問い合わせるのではなく、バッチとして1日1回取得してDBに保存して使うことを想定しているのかな。

完成

一応完成しました。一部分のスクショです。
f:id:yonayonaru:20170206225815p:plain

ソース

Cloud9で作成し公開しています。
https://ide.c9.io/yonayonaru/sample-resas-api