FLINTERS Engineer's Blog

FLINTERSのエンジニアによる技術ブログ

ChefとRailsでVM内にREST APIっぽいものを作る

はじめまして。今年中途入社しました関と申します。
UFCと映画が好きです。
ということで、おすすめの映画はWarriorです。

すみません、本題です。
入社以来、主に外部APIを使ったシステムを構築しています。
普段はAPIを使わせて頂いている側なのですが、今回試しに自分でもそれっぽいものを作ってみました。
(正確にはそういう環境を用意しただけでアプリ側のコードはほぼ書いてません。)

はじめに

以下のような流れになっております。

VMに実行環境作成

railsアプリの作成

curlで叩いてみる

ではさっそくまいりましょう。

実行環境構築

Chefを使ってCentOS6.5の環境を作ります。
※Chefの使い方を示しているわけではありません。結構適当です。

chef関連インストール

gem install chef
knife configure
gem install knife-solo
gem install berkshelf

centos6.5のboxでVagrantFileを作成

vagrant box add centos6.5 https://dl.dropbox.com/s/3fgr7lbvcpn51py/centos_6-5_i386.box
vagrant init centos6.5

ローカルからアクセスする為のprivate_networkを設定(IPは好きなものに変更してください)

vim Vagrantfile
config.vm.network :private_network, ip: "192.168.33.10"

起動し、sshショートカットを設定。

vagrant up
vagrant ssh-config --host centos6.5 >> ~/.ssh/config

chefリポジトリの作成

knife solo init chef-repo

ここでchef-repoというフォルダが作成されます。
ここから先は、そのフォルダ内での作業となります。

Berksfileの編集

cd chef-repo
vim Berksfile
source "https://supermarket.getchef.com"
cookbook "yum"
cookbook "git"
cookbook "ruby_build"
cookbook "rbenv", github: "fnichol/chef-rbenv"
cookbook "vim"
cookbook "mysql", "~>; 5.3.6"

Berkshelfの実行

berks vendor cookbooks

自分でもちょっとだけrecipeを作る

今回はローカルに立てるVMなので、iptablesを切ります(実際のサーバーではやっちゃダメですよ)。
ついでにbundlerのrecipeも書いておきます。

knife cookbook create iptables -o site-cookbooks
vim site-cookbooks/iptables/recipes/default.rb
service 'iptables' do
  action [:disable, :stop]
end
knife cookbook create bundler -o site-cookbooks
vim site-cookbooks/bundler/recipes/default.rb
gem_package "bundler" do
  gem_binary "/home/vagrant/.rbenv/shims/gem"
  action :install
end

実行するrecipeを定義する

vim nodes/centos6.5.json
{
  "run_list": [
    "recipe[yum]",
    "recipe[yum-epel]",
    "recipe[git]",
    "recipe[ruby_build]",
    "recipe[rbenv::user]",
    "recipe[vim]",
    "recipe[mysql::server]",
    "recipe[mysql::client]",
    "recipe[iptables]",
    "recipe[bundler]"
  ],
  "mysql":{
    "service_name":"default",
    "version":"5.6",
    "port":"3306",
    "server_root_password":"******",
    "remove_anonymous_users":true,
    "remove_test_database":true
  },
  "rbenv": {
    "user_installs": [
        {
          "user": "vagrant",
          "rubies": ["2.2.0"],
          "global": "2.2.0"
      }
    ]
  }
}

chef実行

knife solo prepare centos6.5
knife solo cook centos6.5

これで実行環境ができました。
次に、VM内でrailsアプリを作ります。

ssh centos6.5

アプリ作成

railsのインストール

bundle init
vim Gemfile

railsコメントアウトを外す

gem "rails"

インストール

bundle install --path vendor/bundle

railsプロジェクトの作成

bundle exec rails new apitest -d=mysql --skip-bundle

プロジェクトに必要なgemのインストール

cd apitest
vim Gemfile

therubyracerのコメントアウトを外す

gem 'therubyracer', platforms: :ruby

インストール

bundle install --path vendor/bundle

DB設定

DBのuser, passwordを変更

vim config/database.yml

DBの作成

bundle exec rake db:create

railsにはscaffoldingという非常に便利な機能があり、
以下の様に実行するだけでRestfulなファイル構成を自動構築してくれます。
(ここでは、sampleというモデルを作成し、同時に使うカラムを定義しています。)

bundle exec rails generate scaffold sample sample_type:string sample_value:string sample_flag:boolean

すると、db/migrateの下に*****_create_samples.rbのようなファイルが作成されます。
定義をさらに変更したい場合はこのファイルを直接弄っちゃいましょう。
(本当は新たに変更用のmigrationファイルを作るんですが、今回は直接)
僕はこんな感じにしました。

t.string :sample_type, null: false
t.string :sample_value, null: false
t.boolean :sample_flag, null: false, default: false

マイグレーションを実行

bundle exec rake db:migrate

controllerを修正

rails4以降は、デフォルト状態だとブラウザアクセス以外はCSRF対策でTokenエラーが起きるみたいなので、解除します。
app/controllers/application_controller.rbを以下のように変更します。

protect_from_forgery with: :exception

protect_from_forgery with: :null_session

rails serverの実行(今回はnginxやunicornは使いません)

bundle exec rails server -b 0.0.0.0

設定は以上です。あとはローカルから実行するだけです。

REST APIっぽく実行

ブラウザからもアクセスできるようになっているんですが、
せっかくなんでREST APIっぽく全部curlでいきます。
jqとは、jsonを読みやすくしてくれるライブラリです。

postでデータ登録してみます。

curl http://192.168.33.10:3000/samples.json -X POST -d "sample[sample_type]=type1" -d "sample[sample_value]=value1" | jq .

f:id:s_hayase:20150722154415p:plain

きたー!

GETするとこんな感じ(先にもう一個POSTしてます)。

curl http://192.168.33.10:3000/samples.json | jq .

f:id:s_hayase:20150722154445p:plain

PUTやDELETEもできます。

curl http://192.168.33.10:3000/samples/2.json -X PUT -d "sample[sample_type]=type2_updated" -d "sample[sample_value]=value2_updated" | jq .

f:id:s_hayase:20150722154526p:plain
更新されました。

curl http://192.168.33.10:3000/samples/2.json -X DELETE
curl http://192.168.33.10:3000/samples.json | jq .

f:id:s_hayase:20150722154545p:plain
ちゃんと消えております。

おわりに

いかがだったでしょうか。
長くてすみません!読んでいただきありがとうございました!