LoginSignup
3
2

More than 5 years have passed since last update.

RailsでGemを使わずにミニマムなAPIサーバーを書いてみる

Last updated at Posted at 2018-04-27

この記事は自分のブログを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に書いてある。

反省

もっと良い方法があると思った。とりあえず気になってる点はあるので気が向いたら直すかな。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2