この記事は自分のブログをqiitaにも投稿した形の記事ですです。
皆さんこんにちは。Ruby on Railsもversion5.2.0がリリースされたのを知って何か作りたくなったので作ってみた
最寄のバス停のバス時間がわかるオレオレAPI(時間しか書いて無くて他の人が見ても得しない)だ
なんで作ったの
別にサイトとかで確認するなり、もしくはエンジニアらしくスクレイピングしたアプリケーションでも作ればいいじゃない、と思うだろう。だが、私の乗るバスの公式サイトはとにかく重い、重すぎるんだ。マジでどんな実装してるのか信じられない。そしてUIがわかりづらくて探しづらいのだ
だからAPIを作ってみた。
作っていく
まず、Railsのupdateをしてなかったのでする
gem update rails
そしてrails new(APIモードにしてもよかったけど忘れて作ってた)
rails new mybus_api
DBモデルを作る
とりあえず、平日、土、日祝で別れてるのでモデルを3つ作ろうと考えたが、平日は本数が当たり前だがかなり多いので朝、昼、夕分のモデルを作った
時間だけだと物足りないので料金のカラムも追加してみた(駅まで行くバスだから全部同じ値段なんだけどね)
平日のモデル(朝、昼、夕)
rails g model morning time:string money:string
rails g model noon time:string money:string
rails g model afternoon time:string money:string
土曜日のモデル
rails g model sat time:string money:string
日祝のモデル
rails g model sun time:string money:string
モデルを作り終えたらマイグレーションしよう
rake db:migrate // もしくはrails db:migrate
APIのコントローラーを書く
apiだと認識できるように、且つバージョニングをしたいので以下のようにする
cd app/controllers
mkdir -p api/v1
平日はその中でもモデルを3つ持つのでweekdayという名前のディレクトリを作ることにした
cd api/v1
mkdir weekday
そしてコントローラーは今回ビューを使わないので、touchコマンドで新規ファイル作成をした。
~/api/v1$ touch sat_controller.rb
~/api/v1$ touch sun_controller.rb
// 平日はweekdayの下で
~/api/v1/weekday$ touch morning_controller.rb
~/api/v1/weekday$ touch noon_controller.rb
~/api/v1/weekday$ touch afternoon_controller.rb
コントローラーの書き方
平日
class Api::V1::Weekday::MorningController < ApplicationController
def index
time = Morning.all
render json: time
end
def show
time = Morning.where(id:params[:id])
render json: time
end
end
土曜日
class Api::V1::SatController < ApplicationController
def index
time = Sat.all
render json: time
end
def show
time = Sat.where(id:params[:id])
render json: time
end
end
以上のような感じで他の曜日や時間帯のものも書く
例外処理
404と500に対応した。例外のクラスを扱って手軽にできるのでいいね
class ApplicationController < ActionController::Base
# protect_from_forgery with: :null_session
rescue_from ActiveRecord::RecordNotFound, with: :render_404
rescue_from ActionController::RoutingError, with: :render_404
rescue_from Exception, with: :render_500
def render_404
render :json => { message:'This page is not found', status:404 }
end
def render_500
render :json =>{ message:'Internal server error', status:500 }
end
end
ルーティング
作ったディレクトリに合わせてnamespaceを使って普通に書いてみた。もっといい方法があるかも(?)
specifyルーティングはid指定用のものだ。
Rails.application.routes.draw do
namespace :api, { format: 'json'} do
namespace :v1 do
# Weekday has many time of bus. so divide to three time zone
namespace :weekday do
namespace :morning do
get "/", :action => "index"
get "/specify", :action =>"show"
end
namespace :noon do
get "/", :action => "index"
get "/specify", :action =>"show"
end
namespace :afternoon do
get "/", :action => "index"
get "/specify", :action =>"show"
end
end
# saturday
namespace :sat do
get "/", :action => "index"
get "/specify", :action =>"show"
end
# sunday or holiday
namespace :sun do
get "/", :action => "index"
get "/specify", :action =>"show"
end
end
end
# 404だった場合の書き方 *pathで存在しないルーティングになるみたいだ
get '*path', controller: 'application', action: 'render_404'
root 'home#index'
end
リソースの作成
今回は取得(GETリクエスト)のみをするAPIなので、新たに作成する(POSTリクエスト)データはない。あらかじめ時間と料金のデータを作る。
mkdir data
cd data
touch sunholiday.json
touch saturday.json
touch morning.json
touch noon.json
touch afternoon.json
dataディレクトリに以下のようなjsonを作成した。あまり頭のいいやり方じゃないけど本数が少ない田舎なので手打ちしてしまった。
[
{
"time":"11:31",
"money":"330JPY"
},
{
"time":"12:04",
"money":"330JPY"
},
{
"time":"12:46",
"money":"330JPY"
},
{
"time":"13:36",
"money":"330JPY"
},
{
"time":"14:06",
"money":"330JPY"
},
{
"time":"14:36",
"money":"330JPY"
},
{
"time":"15:01",
"money":"330JPY"
},....もっと続く
db/seed.rbを使って初期データをモデルに投下する
以下リンクを参考にした
[https://www.rubylife.jp/rails/model/index10.html:embed:cite]
簡単にjsonをパースして保存するスクリプトを書いてみた。
def make_data(file_name,model)
File.open("data/#{file_name}") do |file|
json = JSON.load(file)
json.each do |get_object|
time = get_object['time']
money = get_object['money']
data = model.new({time:time,money:money})
data.save
end
end
end
make_data('sunholiday.json',Sun)
make_data('saturday.json',Sat)
make_data('morning.json',Morning)
make_data('noon.json',Noon)
make_data('afternoon.json',Afternoon)
コマンドを実行してseedする
rake db:seed
動かしてみよう
ローカルサーバーを立ち上げてGETリクエストを送ってみる
rails s
curlで普通に叩く
curl http://localhost:3000/api/v1/sat/specify.json?id=2
結果
[{"id":2,"time":"07:34","money":"330yen","created_at":"2018-04-17T12:37:44.052Z","updated_at":"2018-04-17T12:37:44.052Z"}]
うまくいった。作りかたをここまで書いただけだが、丁寧にやるならこまめに動作させたり、railsコンソールでデバッグ、ユニットテストを書くことをしたりするといいだろう。
コードはGitHubにあげておいた。APIの仕様もここのREADMEに書いてある。
反省
もっと良い方法があると思った。とりあえず気になってる点はあるので気が向いたら直すかな。