Sinatra+ActiveRecord+MySQLで、簡単APIサーバ構築


サーバを使ったiPhoneアプリを作りたかったので、簡単にサーバ側作れないか調べてみました。結論として結構簡単に出来る事が分かったのでメモメモ。

##参考にした記事
[Sinatra＋ActiveRecord＋SQLite3で，軽量なWeb-DB連携例 | tamo's blog](http://tamosblog.wordpress.com/2012/10/26/sinatra/)

大分参考にさせて頂きました。ありがとうございます！
仕事ではMySQLを使う事が多いので、SQLite3ではなくMySQLを使う事にしました。

##手順
1. Ruby,MySQLをインストール
2. データベースを作成
3. Gemfileを作成とインストール
4. database.ymlを作成
5. Rubyファイルを作成
6. 実行
7. 動作確認


## 1. Ruby,MySQLをインストール
結構な量になったので別記事にまとめました。ここが一番面倒(´Д｀)
- [Ruby,MySQLの環境を構築する(Mac版) #MySQL #Mac #Ruby #homebrew - Qiita](http://qiita.com/items/e2cf0fa27f9763d3bdd4)
- [Ruby,MySQLの環境を構築する(Linux版) #MySQL #Ruby #Linux - Qiita](http://qiita.com/items/c9f3d8ca69a4ab0b27cb)


##2. データベースを作成
MySQLの初歩的なコマンドを知っていれば、ここは問題ないと思います。
ActiveRecordの流儀で、テーブル名は複数形にする必要がある事だけ注意！
サンプルとして、タイトル, 詳細文, 作成日時, 更新日時を持つ、topicsテーブルを生成してみます。

```mysql:
mysql> create database hoge;
Query OK, 1 row affected (0.00 sec)

mysql> use hoge
Database changed

mysql> create table topics ( 
    ->  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    ->  title VARCHAR(255) NOT NULL,
    ->  description VARCHAR(255) NOT NULL,
    ->  created_at DATETIME NOT NULL,
    ->  updated_at DATETIME NOT NULL,
    ->  PRIMARY KEY(id)
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql> desc topics;
+-------------+------------------+------+-----+---------+----------------+
| Field       | Type             | Null | Key | Default | Extra          |
+-------------+------------------+------+-----+---------+----------------+
| id          | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| title       | varchar(255)     | NO   |     | NULL    |                |
| description | varchar(255)     | NO   |     | NULL    |                |
| created_at  | datetime         | NO   |     | NULL    |                |
| updated_at  | datetime         | NO   |     | NULL    |                |
+-------------+------------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
```

###サンプルデータを登録
動作確認をする為のサンプルデータを入れておきます。

```mysql:
mysql> insert into topics values(1, "title1", "description1", now(), now());
Query OK, 1 row affected (0.00 sec)

mysql> insert into topics values(2, "title2", "description2", now(), now());
Query OK, 1 row affected (0.01 sec)

mysql> insert into topics values(3, "title3", "description3", now(), now());
Query OK, 1 row affected (0.00 sec)

mysql> select * from topics;
+----+--------+--------------+---------------------+---------------------+
| id | title  | description  | created_at          | updated_at          |
+----+--------+--------------+---------------------+---------------------+
|  1 | title1 | description1 | 2013-05-19 21:29:21 | 2013-05-19 21:29:21 |
|  2 | title2 | description2 | 2013-05-19 21:29:29 | 2013-05-19 21:29:29 |
|  3 | title3 | description3 | 2013-05-19 21:29:38 | 2013-05-19 21:29:38 |
+----+--------+--------------+---------------------+---------------------+
3 rows in set (0.01 sec)
```


##3. Gemfileを作成とインストール
次に、使用するgemファイルを管理するファイルを作ります。

```bash:
# ひな形ファイルの作成
$ bundle init
Writing new Gemfile to /home/u1/hoge/Gemfile

# 編集
$ vi Gemfile
source "https://rubygems.org"

gem "activerecord"
gem "mysql2"
gem "sinatra"

# 必要なGemのインストール
$ bundle install --path vendor/bundle
```

ActiveRecordとMySQLを使うのでそれぞれのgemを記入。
RubyからMySQLを使いたい時はmysql2というのを使うようです。

参考：[RubyでMySQLに繋ぐためのruby-mysqlとmysql2 - tagomorisのメモ置き場](http://d.hatena.ne.jp/tagomoris/20111210/1323502295)


##4. database.ymlを作成
プログラムからDBにアクセスする為に、DB情報を書いた設定ファイルを作ります。
各値は、自分の環境に合わせて設定して下さい。

```
development:
  adapter: mysql2
  database: hoge
  host: localhost
  username: root
  password: xxxxxx
  encoding: utf8
```


##5. Rubyファイルを作成
ようやくコードを書きます。長かった。。
使うのはタイトルにある通りSinatraです。

```ruby:
# coding:utf-8
require 'active_record'
require 'mysql2'
require 'sinatra'

# DB設定ファイルの読み込み
ActiveRecord::Base.configurations = YAML.load_file('database.yml')
ActiveRecord::Base.establish_connection('development')

class Topic < ActiveRecord::Base
end

# 最新トピック10件分を取得
get '/topics.json' do
  content_type :json, :charset => 'utf-8'
  topics = Topic.order("created_at DESC").limit(10)
  topics.to_json(:root => false)
end

# トピック投稿
post '/topic' do
  # リクエスト解析
  reqData = JSON.parse(request.body.read.to_s) 
  title = reqData['title']
  description = reqData['description']
  
  # データ保存
  topic = Topic.new
  topic.title = title
  topic.description = description
  topic.save

  # レスポンスコード
  status 202  
end
```

基礎的な機能として、

- 最新トピック10件分を取得する GET /topics.json
- トピックを登録する POST /topic

を作ってみました。


##6. 実行
書いたコードを動かします。ここでもちょっとはまった事があったので注意！（参考：[Sinatraがデフォルトでは外部から繋がらなくなってたよ #Sinatra #Ruby - Qiita [キータ]](http://qiita.com/items/b86b21f6ed39f4c10d5d)）

```bash:
$ bundle exec ruby hoge.rb -o 0.0.0.0
[2013-05-19 21:37:56] INFO  WEBrick 1.3.1
[2013-05-19 21:37:56] INFO  ruby 1.9.3 (2013-02-06) [x86_64-linux]
== Sinatra/1.4.2 has taken the stage on 4567 for development with backup from WEBrick
[2013-05-19 21:37:56] INFO  WEBrick::HTTPServer#start: pid=10667 port=4567
```


##7. 動作確認
###最新のトピックを取得
プログラムを動かしてるサーバの /topics.json にリクエストを送って動作確認をします。仮にlocalhostで動かした場合は、http://localhost:4567/topics.json
GETリクエストを送ると、以下のようなJSON形式のレスポンスが返ってきます。これをベースに変更を加えていけば使えそう。

```javascript:
[
    {
        "created_at": "2013-05-19T21:29:38+09:00", 
        "description": "description3", 
        "id": 3, 
        "title": "title3", 
        "updated_at": "2013-05-19T21:29:38+09:00"
    }, 
    {
        "created_at": "2013-05-19T21:29:29+09:00", 
        "description": "description2", 
        "id": 2, 
        "title": "title2", 
        "updated_at": "2013-05-19T21:29:29+09:00"
    }, 
    {
        "created_at": "2013-05-19T21:29:21+09:00", 
        "description": "description1", 
        "id": 1, 
        "title": "title1", 
        "updated_at": "2013-05-19T21:29:21+09:00"
    }
]
```

###トピックの登録
http://localhost:4567/topic に、以下のようなBodyのPOSTリクエストを送ります。すると202レスポンスが返ってきます。
ちなみにPOSTリクエストを送るのは、[Chrome拡張機能のDevHTTPClient](https://chrome.google.com/webstore/detail/dev-http-client/aejoelaoggembcahagimdiliamlcdmfm)を使ってます。

```javascript:
{
  "title": "title4",
  "description": "description4"
}
```

ちゃんと登録されてるかを、GET /topics.json で確認。

```javascript:
[
    {
        "created_at": "2013-05-19T21:48:56+09:00", 
        "description": "description4", 
        "id": 4, 
        "title": "title4", 
        "updated_at": "2013-05-19T21:48:56+09:00"
    }, 
    {
        "created_at": "2013-05-19T21:29:38+09:00", 
        "description": "description3", 
        "id": 3, 
        "title": "title3", 
        "updated_at": "2013-05-19T21:29:38+09:00"
    }, 
    {
        "created_at": "2013-05-19T21:29:29+09:00", 
        "description": "description2", 
        "id": 2, 
        "title": "title2", 
        "updated_at": "2013-05-19T21:29:29+09:00"
    }, 
    {
        "created_at": "2013-05-19T21:29:21+09:00", 
        "description": "description1", 
        "id": 1, 
        "title": "title1", 
        "updated_at": "2013-05-19T21:29:21+09:00"
    }
]
```


##おわり
いやーほんとに簡単に書けますね。
あとは、Sinatra と ActiveRecord を勉強しながらちゃんと実装していこうと思います。あと色々自動化していきたいなー。

何か間違ってる所とかありましたらご指摘お願いしますm(_ _)m