Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

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が原因?

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
1
Help us understand the problem. What are the problem?