はじめに
同じような処理をするWebアプリケーションとモバイルアプリケーションを作ることが増えたので、データを扱う処理をなるべく共通化したくて、JSONを返すWebAPIを作ってみたので、作り方をまとめてみました。
なお、作ったものはもう少し複雑ですが、ここで紹介するのは簡易版であることをご理解下さい。
開発環境
サーバー:さくらのVPS
Webサーバ:Apache
データベース:SQLite3
まずはgemをインストール。
$ sudo gem install sqlite3
データベース生成
とりあえず、サンプルとしてidとnameという列を持つデータベースを利用します。
CREATE TABLE `sample`(
id integer primary key,
name text
);
上記ファイルを保存して、Webアプリケーションのルートフォルダに保存します。
その後、以下のコマンドでデータベースを生成します。
$ sqlite3 sample.db < sample.sql
ライブラリの読込
CGIを利用するためのライブラリとSQLiteのライブラリを利用します。
ライブラリを読み込んだ後に、それぞれのインスタンスを生成します。
require 'cgi'
require 'sqlite3'
$cgi = CGI.new()
$db = SQLite3::Database.new("sample.db")
GETのパラメータを取得
ここではAPIを操作するのにGETメソッドを利用することにして、GETのパラメータを取得します。
$_GET = {}
CGI::parse($cgi.query_string).each {|key, val|
$_GET[key] = val[0].gsub("'","''")
}
処理の分岐
よくある処理は、追加、編集、削除、一覧かなと思うので、それぞれをmodeというパラメータを参照して処理を分岐します。
mode = $_GET["mode"]
case mode
when "add"
# 追加用の処理
when "edit"
# 編集用の処理
when "delete"
# 削除用の処理
when "list"
# 一覧用の処理
end
SQL文処理の作成
SQL(SELECT文)で取得したデータを配列に入れ、JSONに変換して出力するとうようなことができるように関数を作ります。
# SQL(SELECT文)を実行して戻り値を配列に変換
def sql2array(sql)
begin
rs = $db.execute2(sql)
rescue
sleep 10
retry
end
i = 0
flg = true
fields = []
values = []
rs.each do |row|
if flg then
fields = row
flg = false
else
j = 0
val = {}
row.each do |wk|
val[fields[j]] = wk
j += 1
end
values[i] = val
i += 1
end
end
return values
end
# 配列をJSONに変換
def json(vals)
result = <<EOF
{
"name": "sample",
"count": #{vals.length},
"result":[
EOF
i = 0
vals.each do |row|
if i > 0 then
result += ","
end
j = 0
result += "{"
row.each do |key, val|
if j > 0 then
result += ","
end
result += <<EOF
"#{key}":"#{val}"
EOF
j += 1
end
result += "}"
i += 1
end
result += <<EOF
]
}
EOF
return result
end
一覧用の処理
全データを取得してJSONを返す。
def list()
sql = "SELECT * FROM sample"
vals = sql2array(sql)
return json(vals)
end
追加用の処理
def add()
# SQL文の生成
cols = ["name"]
vals = {}
sql = "INSERT INTO sample VALUES ((SELECT MAX(id)+1 AS id FROM sample)"
cols.each do |col|
sql += ",'#{vals[col]}'"
end
sql += ")"
$db.exec(sql)
return list()
end
編集用の処理
def edit()
# SQL文の生成
cols = ["name"]
vals = {}
sql = "UPDATE sample SET "
cols.each do |col|
sql += (col == cols[0]) ? "" : ","
sql += "#{col} = '#{vals[col]}'"
end
sql += " WHERE id='#{$_GET["id"]}'"
$db.exec(sql)
return list()
end
削除用の処理
def delete()
sql = "DELETE FROM sample WHERE id='#{$_GET["id"]}'"
$db.exec(sql)
return list()
end
処理の分岐(完成版)
先ほど作ったmodeというパラメータを参照して処理を分岐する部分を修正します。
mode = $_GET["mode"]
case mode
when "add"
json = add()
when "edit"
json = edit()
when "delete"
json = delete()
else
json = list()
end
JSONの出力
生成したJSONを出力します。
puts $cgi.header()
puts json
全ソースコード
sample.rbという名前で以下のコードを保存します。
require 'cgi'
require 'sqlite3'
$cgi = CGI.new()
$db = SQLite3::Database.new("sample.db")
$_GET = {}
CGI::parse($cgi.query_string).each {|key, val|
$_GET[key] = val[0].gsub("'","''")
}
# SQL(SELECT文)を実行して配列に変換
def sql2array(sql)
begin
rs = $db.execute2(sql)
rescue
sleep 10
retry
end
i = 0
flg = true
fields = []
values = []
rs.each do |row|
if flg then
fields = row
flg = false
else
j = 0
val = {}
row.each do |wk|
val[fields[j]] = wk
j += 1
end
values[i] = val
i += 1
end
end
return values
end
# 配列をJSONに変換
def json(vals)
result = <<EOF
{
"name": "sample",
"count": #{vals.length},
"result":[
EOF
i = 0
vals.each do |row|
if i > 0 then
result += ","
end
j = 0
result += "{"
row.each do |key, val|
if j > 0 then
result += ","
end
result += <<EOF
"#{key}":"#{val}"
EOF
j += 1
end
result += "}"
i += 1
end
result += <<EOF
]
}
EOF
return result
end
def list()
sql = "SELECT * FROM sample"
vals = sql2array(sql)
return json(vals)
end
def add()
# SQL文の生成
cols = ["name"]
vals = {}
sql = "INSERT INTO sample VALUES ((SELECT MAX(id)+1 AS id FROM sample)"
cols.each do |col|
sql += ",'#{vals[col]}'"
end
sql += ")"
$db.exec(sql)
return list()
end
def edit()
# SQL文の生成
cols = ["name"]
vals = {}
sql = "UPDATE sample SET "
cols.each do |col|
sql += (col == cols[0]) ? "" : ","
sql += "#{col} = '#{vals[col]}'"
end
sql += " WHERE id='#{$_GET["id"]}'"
$db.exec(sql)
return list()
end
def delete()
sql = "DELETE FROM sample WHERE id='#{$_GET["id"]}'"
$db.exec(sql)
return list()
end
mode = $_GET["mode"]
case mode
when "add"
json = add()
when "edit"
json = edit()
when "delete"
json = delete()
else
json = list()
end
puts $cgi.header()
puts json
テスト
以下のコードで動作を確認します。
一覧
$ curl localhost/sample.rb
{"name":"sample","count":0,"result":[]}
追加
$ curl localhost/sample.rb?mode=add&name=テスト
{"name":"sample","count":1,"result":[{"id":"1","name":"テスト"}]}
編集
$ curl localhost/sample.rb?mode=edit&id=1&name=サンプル
{"name":"sample","count":1,"result":[{"id":"1","name":"サンプル"}]}
削除
$ curl localhost/sample.rb?mode=delete&id=1
{"name":"sample","count":0,"result":[]}
できた!