doridoridoriand’s diary

主に技術的なことを書いていく予定(たぶん)

最速でAPIをつくろう

写真のフランク・シナトラとは関係ないよ(たぶん)

Androidアプリを書いていて、最初はAPIいらないかと持っていたのですが、今後の実装を考えていくうちにどう考えても辛さしかないわって感じになったので速攻で作りました。
個人的にはAWSAPI Gatewayとか試したかったんですけど、今回はあまり時間がなかったので。。
(というか日程的にバックエンド開発に時間を割けないorz)

よって一番慣れているもので作りましたとさ

実際にはクローラーが稼働していて、そいつらが読み取ったデーターがMySQLにたまっている感じを想像していただけるとわかると思います。まあ今流行りのクローラーです

とりあえずgemを入れましょう

gem install sinatra

次にサクッとコードを書きます

例えばDBのテーブルがこんなかんじだったとしまして

create table `hogehoge_items` (
  `id`            int(10)      unsigned not null,
  `hoge_id`       int(10)      unsigned not null,
  `title`         varchar(255) not null,
  `link`          varchar(768) not null,
  `published`     varchar(255) not null,
  `updated`       varchar(255) not null,
  `content`       varchar(255) not null,
  primary key(`id`)
) engine=InnoDB default charset=utf8;

シンタックスハイライトすんじゃん!!びっくり!!

取り乱しました。すみません。出来ないものだとばかり思い込んでいたので。。。

DBスキーマそのまま貼っつけましたが皆さんわかると思うのでこのまま行きます

次に肝心のコードです

require 'active_record'
require 'sinatra'

db_config = YAML.load_file(File.expand_path(File.join(__FILE__, 'config', 'database.yml')))
ActiveRecord::Base.establish_connection(db_config['db']['production'])

set :root, File.expand_path(File.join(__FILE__, '..', 'static'))

get '/' do
  erb :index
end

get '/news/:hoge_id' do
  content_type :json, :charset => 'utf-8'
  entries = GoogleAlertItems.where(hoge_id: params[:hoge_id]).order('updated DESC').limit(10)
  entries.to_json(:root => false)
end

本当をいうと今回実装したのと全然構造違うのですが、説明用に変えて書いています。 とりあえず上から説明していきます

require 'active_record'
require 'sinatra'

大丈夫ですね。普通にimport#includeといった他の言語にもよくあるライブラリの読み込みです

db_config = YAML.load_file(File.expand_path(File.join(__FILE__, 'config', 'database.yml')))
ActiveRecord::Base.establish_connection(db_config['db']['production'])

ActiveRecordを単体で叩けるように設定を読み込んでいます。db_config['db']['production']部分をproductionからdevelopment変えたりすることで開発環境と本番環境を分けたりなど、色々と便利なのですが、とりあえず今回はそこまで凝ったことしなくていいので
あ。ここでdatabase.ymlは既に存在していること前提で話しています(笑)

set :root, File.expand_path(File.join(__FILE__, '..', 'static'))

Sinatraは静的ファイルのディレクトリの場所を変更することが可能です。今回は色々な関係でstaticというフォルダを指定しています

get '/' do
  erb :index
end

get '/news/:hoge_id' do
  content_type :json, :charset => 'utf-8'
  entries = GoogleAlertItems.where(hoge_id: params[:hoge_id]).order('updated DESC').limit(10)
  entries.to_json(:root => false)
end

メインディッシュですね。Sinatraの特徴はMVCアーキテクチャーに則っていないことです。乱暴に言うとCしか持っていません。そしてこれはルーティングを書いているだけです。 ちゃんと設計してあげれば立派なMVCフレームワークになるのですが、ならRails使えよって話で(笑) ちなみにSinatraをベースにMVCアーキテクチャーを持たせた設計にしてあるのがPadrinoってやつです
僕はいまいちRailsに比べての優位な部分を見いだせていないので使ったことないです。すません

get '/' do
  erb :index
end

これはサイトのトップディレクトリに来たらstaticsフォルダーにあるindex.erbrenderする処理を書いています。ちなみにhamlだろうがslimだろうが適切なgemを入れてあげれば対応できます

get '/news/:hoge_id' do
  content_type :json, :charset => 'utf-8'
  entries = GoogleAlertItems.where(hoge_id: params[:hoge_id]).order('updated DESC').limit(10)
  entries.to_json(:root => false)
end

これはなんかややこしそうですね。しかし分解して読み解けば簡単です

get '/news/:hoge_id' doでURLに含まれている/news/以下の文字列を読み取ります。よって

/news/yoshioというURLに対してアクセスが来た場合、 yoshioという文字列がsinatra側に渡されることになります

GoogleAlertItems.where(hoge_id: params[:hoge_id]).order('updated DESC').limit(10)

ここで何をしているかというと、URLから読み取った文字列をActiveRecordに渡して、hoge_idと一致するものを持ってきて更に更新日時が新しい順にし、そして最大10件持ってくるという処理をしています

entries.to_json(:root => false)

説明不要かもですが、みんなだいすきJSONを生成しています。最終的にこいつが結果としてrenderされます

今回はgetしか使っていませんが、もちろんpostupdatedestroyも可能です。 長くなったのでここで終わりにしますが、次回はunicornでデーモン化した話を書きたいです
(ちゃんと次回があればの話だがなっ!)

あ。。。GPUの連載止めてた。。書きます