Sinatra + ActiveRecord = APIサーバー
SinatraでActiveRecordを使って簡単なAPIサーバーを作る。
今ではありきたりな組み合わせだが、やってみると案外ハマってしまう箇所もあったのでメモとして残しておく。
環境構築
Rubyのinstallは環境ごとに違うので省略
Rubyは入った前提で進める。Rubyのインストールは、rbenv経由で入れると良い。
なお、Rubyのバージョンは2.2.2以上にすること(ActiveRecordのバージョンの都合上、2.2.1以下では上手く動作しなかった。)
ターミナルにて以下のコマンドを入力
$ mkdir <project-name>
$ cd <project-name>
$ gem install bundler # gemインストール用
$ rbenv rehash # 上のインストール内容を適用する
以下の手順では、上で作成した<project-name>
のディレクトリ内で作業していく
最終的なディレクトリ構造
$ tree
.
├── Gemfile
├── Gemfile.lock
├── Rakefile
├── app.rb
├── db
│ ├── migrate
│ │ └── 20160808141848_create_posts.rb
│ └── schema.rb
└── models
└── post.rb
手順1)必要なgemをインストール
Gemfileを作成
source "https://rubygems.org"
gem "rake"
gem "sinatra"
gem "activerecord"
gem "sinatra-activerecord"
gem "sqlite3"
ターミナルにて以下のコマンドを入力して必要なgemをインストール
$ bundle install
手順2)ActiveRecordのモデルを作成する
Rakefileの作成〜DBのマイグレーション
Rakefileを作成する
require 'sinatra/activerecord'
require 'sinatra/activerecord/rake'
これで、rakeコマンドが使用可能になる。
ターミナルにて以下のコマンドを入力
NAME=~~~~の部分には、作成したいテーブル名(複数形)を記入する。
$ bundle exec rake db:create_migration NAME=create_posts
db/migrate/20160808141848_create_posts.rb
実行すると、db/migrate/20160808141848_create_posts.rb
みたいなファイルが出来ている。
作成されたファイルを開いて以下のように書き込む
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :title
t.string :content
t.timestamps
end
end
end
create_table :table_name
と書くことで新しいDBのテーブルを作成する。table_nameには、複数形の単語で書くこと。
また、t.string :title
のように書くことで、上記のテーブル内にカラムを追加することが出来る。この場合、string型でtitleという名前のカラムを追加することになる。
models/post.rb
というファイルを作って、以下のように書く。
さっき作ったテーブルがposts
なので、モデル名はPost
と単数形になる。
ActiveRecord::Base.establish_connection('sqlite3:///model.db')
class Post < ActiveRecord::Base
end
Rakefileも編集しておく。 models/post.rb
を読み込んで、rakeコマンドでDBと接続できるようにする。
require 'sinatra/activerecord'
require 'sinatra/activerecord/rake'
require './models/post.rb'
これでDBとの接続は完了。
ここまで来たら、ターミナルに戻って以下のコマンドを入力
$ bundle exec rake db:migrate
class CreateUsers < ActiveRecord::Migration[4.2] (called from load at ~/.rbenv/versions/2.3.0/bin/rake:23)
== 20160808141848 CreatePosts: migrating ======================================
-- create_table(:posts, {})
-> 0.0014s
== 20160808141848 CreatePosts: migrated (0.0015s) =============================
なんかうにゃうにゃ出てきたら成功
Sinatraでアプリを作っていく
app.rb
というファイルを作って、以下のように書く。
Sinatraの書き方に関しては説明を割愛する。
ポイントは、それぞれの返り値を .to_json
としてjson形式で終わらせること。
require "sinatra"
require "sinatra/activerecord"
require "./models/post.rb" # さっき作ったモデルを読み込み
get "/posts" do
Post.all.to_json # 全てのPostを返す
end
get "/posts/:id" do
Post.find(params[:id]).to_json # :idのPostを返す
end
post "/posts" do
# sinatraはPOSTメソッドの際デフォルトでjsonを受け取れないので変換
# 参考: http://qiita.com/izumin5210/items/caf66ece1f67a0fd6a4c
json = JSON.parse(request.body.read)
post = Post.new(json)
if post.save
{ result: "success", code: 200 }.to_json
else
{ result: "failure" }.to_json
end
end
ここまで書けたら、ターミナルでSinatraサーバーを起動する
$ ruby app.rb
作ったアプリを試してみる
Sinatraのデフォルトポートは4567なので、localhost:4567に対してcurlでアクセスしてみる。
$ curl http://localhost:4567/posts
[]
$ curl -XPOST -d '{"title": "dummy title", "content": "dummy content"}' http://localhost:4567/posts
{"result":"success","code":200}
$ curl http://localhost:4567/posts
[{"id":1,"title":"dummy title","content":"dummy content","created_at":"2016-08-08T14:52:07.086Z","updated_at":"2016-08-08T14:52:07.086Z"}]
$ curl http://localhost:4567/posts/1
{"id":1,"title":"dummy title","content":"dummy content","created_at":"2016-08-08T14:52:07.086Z","updated_at":"2016-08-08T14:52:07.086Z"}
正常に動作していることを確認。お疲れさまでした。
終わりに
今回作成したプロジェクトはこちら。
https://github.com/litmon/sinatra-api
rubyのバージョンが2.2.1以下だと、ActiveRecordのバージョン5.0.0が導入できない。
そのせいで、モデルのデータをDBから引っ張ってくるときにエラーになって何十分かハマってしまった。
ActiveRecordのバージョンをもう少し下げれば上手くいくかもしれないな……要調査。