Edited at
移行Day 13

AdventCalendar Day13 [超Ruby入門]


はじめに

本記事は、超Ruby入門13日目の記事です。

コメント頂ける方は、ガイドラインを読んで頂けると幸いです。


目的

簡易WebAPIの実装を通じて、JSONの使い方をマスターする。


目標

WebAPIについて理解を深める。


ドキュメント

library webrick

module JSON

class WEBrick::CGI


事前知識


WebAPI

WebAPIとはHTTP/HTTPSの仕様に基づき、サービス提供者が内部情報を意識することなく外部から呼び出せるように提供したインターフェースのことである。

JSONやXMLを提供するものだと認識しておけば、おそらく大丈夫。

個人がAPIを公開する機会は主にiosやandroid開発時だ。


JSON

JSONとは、データを表現するフォーマットの一つだ。


準備

下記コードをserver.rbとして実行する。webrickでHTTPサーバーを実装してるが、WebAPIにおいて重要な要素でないため説明は省く。ドキュメントなどを参考にして、解読して下さい。

$ruby server.rb


server.rb

require 'webrick'

module WEBrick::HTTPServlet
FileHandler.add_handler('rb', CGIHandler)
end
server = WEBrick::HTTPServer.new({ :DocumentRoot => './',
:BindAddress => '127.0.0.1',
:Port => 8080})
server.mount('/api', WEBrick::HTTPServlet::CGIHandler, 'api.rb')
server.mount('/api/id/', WEBrick::HTTPServlet::CGIHandler, 'id.rb')
trap("INT"){ server.shutdown }
server.start

api.rbid.rbファイルを作成し、実行権限を与える。

$touch api.rb

$touch id.rb
$chmod 755 api.rb
$chmod 755 id.rb


本題

今回は以下の仕様に基づき実装を行う。

詳しいAPIの設計を知りたい人は、深めたい人の項目を参照して下さい。

URL
役割

http://localhost:8080/api/v1
SQLiteに格納されている全データを返す

http://localhost:8080/api/v1?type=value
カラムtypeの条件を絞る

http://localhost:8080/api/v1/id/:id
指定したidのみ返す

さて、作成したapi.rbに下記コードを実行して、http://localhost:8080/api/v1 にアクセスしてみよう。(Chromeでのみ動作確認)

正しく動作していれば、SQLiteに格納しておいたデータがJSON形式となって表示されているはずだ。


api.rb

class YesCGI < WEBrick::CGI

def do_GET(req, res)
res['content-type'] = "application/json"
result = get_json
res.body = result
end

def get_json
db = SQLite3::Database.new("kaken")
db.results_as_hash = true

json_data = []
db.execute('select * from nlp') do |row|
remove_extra_column = Hash[*row.to_a.shift(row.length / 2 ).flatten!]
json_data << JSON.generate(remove_extra_column)
end
db.close
json_data.join(",")
end
end

YesCGI.new.start()


JSON形式のデータを扱うため、MIMEタイプをapplication/jsonに指定している。

そのため、res.bodyにJSON形式以外のデータを渡してしまうのエラーを吐いてしまう。

試しに、res.body = 1としてみよう。

resは、クライアントへのレスポンスを表すWEBrick::HTTPResponseオブジェクトだ。


次に、クエリパラメータを渡せるようにする。api.rbを修正し

http://localhost:8080/api/v1?type=挑戦的研究 にアクセスしてみよう。

typeカラムに指定した文字が含まれているデータのみが、表示されるはずだ。


api.rb


~~~
class YesCGI < WEBrick::CGI
def do_GET(req, res)
res['content-type'] = "application/json"
type = req.query['type']
if type.nil?
result = get_json
res.body = result
else
result = get_json_with_type(type)
res.body = result
end
end

def get_json
~~~
end

def get_json_with_type(type)
db = SQLite3::Database.new("kaken")
db.results_as_hash = true

json_data = []
sql = "select * from nlp where type like \"%#{type}%\""
# sql = %Q{select * from nlp where type like "%#{type}%"}
db.execute(sql) do |row|
remove_extra_column = Hash[*row.to_a.shift(row.length / 2 ).flatten!]
json_data << JSON.generate(remove_extra_column)
end
db.close
json_data.join(",")
end
end

YesCGI.new.start()



Tips

sql = "select * from nlp where type like \"%#{type}%\""

sql = %Q{select * from nlp where type like "%#{type}%"}

%Q{}を利用すると、ダブルクォートに対して毎度、エスケープ処理を行う必要がなくなる。


最後に、id.rbの実装を行う。基本はapi.rbの同じだ。

大きな違いは、正規表現を用いて、URLのapi/v1/id/ 直後の数値を取得している点がだろう。


id.rb

#!/usr/bin/env ruby

require 'webrick/cgi'
require 'sqlite3'
require 'json'
require 'uri'
class YesCGI < WEBrick::CGI
def do_GET(req, res)
res['content-type'] = "application/json"
id = URI.parse("#{req.request_uri}").path.match(/api\/v1\/id\/([0-9]*)/)[1]
result = get_json_id(id)
res.body = "#{result}"
end

def get_json_id(id)
db = SQLite3::Database.new("kaken")
db.results_as_hash = true

json_data = []
sql = "select * from nlp where id = #{id}"
db.execute(sql) do |row|
remove_extra_column = Hash[*row.to_a.shift(row.length / 2 ).flatten!]
json_data << JSON.generate(remove_extra_column)
end
db.close
json_data.join(",")
end

end

YesCGI.new.start()


簡易WebAPIを実装することで、少しWebAPIへの苦手意識がなくなったのではないだろうか?

明日は、今日作成したWebAPIのテストを行う。


課題

TwitterやGithubのAPIなどを利用して小規模のプログラムを書く。


深めたい人

Web API: The Good Parts


時間がある時にやること

JSONの表示が遅すぎる。webrickが原因?

イライラしない程度の速度にする。