LoginSignup
5
3

More than 5 years have passed since last update.

JSONを返すWeb APIチックなものをRubyで作る

Last updated at Posted at 2017-01-06

はじめに

同じような処理をするWebアプリケーションとモバイルアプリケーションを作ることが増えたので、データを扱う処理をなるべく共通化したくて、JSONを返すWebAPIを作ってみたので、作り方をまとめてみました。

なお、作ったものはもう少し複雑ですが、ここで紹介するのは簡易版であることをご理解下さい。

開発環境

サーバー:さくらのVPS
Webサーバ:Apache
データベース:SQLite3

まずはgemをインストール。

$ sudo gem install sqlite3

データベース生成

とりあえず、サンプルとしてidとnameという列を持つデータベースを利用します。

sample.sql
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":[]}

できた!

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3