Ruby + SinatraでLINE Botを作ろう – Part 2

2020年9月13日Webサービス開発

こんにちは。
この連載では、複数回に渡りRubyとSinatraを使って

  • 本の裏にあるISBNコードを送信すると検索して本の画像を表示してくれる
  • その本を記録しておいて、あとから参照できる

という機能を搭載した「ほんめも!」というLINE Botを作ってみたいと思います。

この記事はPart 1の続編です。まだ読んでいない方はぜひ読んでみてください!

Sponsored Links

この記事で作るもの

この記事では、実際に書籍の情報を返してくれるAPIを利用して検索結果を返信するというプログラムを書いていきます。
プログラムの流れは下記の通りです。

書籍検索APIの紹介

今回は「openBD」を利用します。openBDは株式会社カーリル及び版元ドットコムによって運営されているAPIで、書籍の基本的な情報や書影(表紙の写真)等が取得出来ます。

https://api.openbd.jp/v1/get?isbn=9784873113944

といった感じでisbnを渡すと、書籍データの配列がJSON形式で返ってきます。カンマで区切ることで複数の書籍を指定することも出来ます。
詳しいAPIの仕様はOpenBD 書誌APIデータ仕様 (v1)に記載されています。

基本的にはsummaryの中を見れば良いです。

豆知識: ISBNって何?

ISBNとは国際標準図書番号の略で、任意の図書に一意に付けられる10桁あるいは13桁の数字です。ほとんどの書籍の裏表紙に記載されていて、バーコードにもなっています。古い本であれば奥付にのみ記載されている場合もあります。
書籍に2段のバーコードがあるのは、ISBNコードと書籍JANコード(商品コード)で分かれてるからなんです。

openBD APIを呼び出す

以下のように取得する関数を作ります(コメントは移さなくて大丈夫ですよ)。

def getBookByISBN(isbn)
  return nil if !isbn.match(/^(\d{10}|978\d{10})$/) # ISBNの形式じゃなかったらnilを返す
  uri = URI.parse("https://api.openbd.jp/v1/get?isbn=" + isbn)
  res = Net::HTTP.get_response(uri) # APIを呼び出す
  return nil if res.code != "200" # エラーが発生したらnilを返す
  books = JSON.parse(res.body) # APIの結果をJSON形式として読み出す
  return nil if books.length == 0 # 該当した書籍が0件の場合はnilを返す
  return books[0] # APIの結果のうち1件目を返す
end

書籍検索の結果をWebで表示してみよう

前回作った

get '/' do
  "Hello wolrd!"
end

を流用しましょう。
今回は、/?isbn=978xxxxxxxxxxにアクセスされたら書籍名を返すという仕様にしてみたいと思います。

get '/' do
  book = getBookByISBN(params['isbn'])
  return book['summary']['title']
end

さて、ここまで書けたらhttp://localhost:{PORT}/?isbn={好きな本のISBN}アクセスしてみましょう。
本の名前が出てきたら成功です!

LINE Botに書籍の名前を返す機能をつけよう

前回書いたLINE Botのコードを思い出してみましょう。

post '/callback' do
  body = request.body.read
  signature = request.env['HTTP_X_LINE_SIGNATURE']
  unless client.validate_signature(body, signature)
    error 400 do 'Bad Request' end
  end
  events = client.parse_events_from(body)
  events.each do |event|
    if event.is_a?(Line::Bot::Event::Message)
      if event.type === Line::Bot::Event::MessageType::Text
        message = {
          type: 'text',
          text: event.message['text']
        }
        client.reply_message(event['replyToken'], message)
      end
    end
  end
  "OK"
end

この中でも特に重要なのは

message = {
  type: 'text',
  text: event.message['text']
}
client.reply_message(event['replyToken'], message)

の部分です。
ここは、ユーザーから「テキストのメッセージ」が届いたときにする処理です。
event.message['text']で送信されたテキストデータを取得することができます。
client.reply_message(event['replyToken'], message)で返信を送信することができます。

このコードを少し改良して書籍を検索出来るようにしてみましょう。
if event.type === Line::Bot::Event::MessageType::Textからendまでの中身を以下のように書き換えてください。

book = getBookByISBN(event.message['text']) # ISBNを検索して書籍情報を変数に代入する
messages = [] # 返信するメッセージ用の変数
if book.nil?
  # 書籍が空だった場合
  messages.push({
    type: 'text',
    text: '書籍が見つかりませんでした'
  })
else
  # 書籍が見つかった場合
  messages.push({
    type: 'text',
    text: book['summary']['title']
  })
end
client.reply_message(event['replyToken'], messages)

今まで、client.reply_messageにはmessageというtypetextが入ったオブジェクトを渡していましたが、今回はmessageオブジェクトが入った配列を渡すようにしてみました。
こうすることによって、複数のメッセージを返信出来るようになります。次の章で登場する表紙画像を返信する機能を作る時に使用します!

デプロイしよう

さて、LINE Botの機能追加が完了しました!
早速試してみたい所ですが、前回にも解説した通りデプロイしないとテストが出来ません。
下記コマンドを入力してデプロイしてみましょう。

$ git add -A
$ git commit -m "add search book"
$ git push heroku master

デプロイが完了したら、LINE BotにISBNを送信してみましょう。
下のスクリーンショットの様に書籍名が返ってきたら成功です!

LINE Botに書籍の画像を返す機能をつけよう

続いて、書籍の表紙画像を返す機能を付けていきましょう。

表紙画像はbook['summary']['cover']で取得することができます。
ただし、全ての書籍に画像がある訳ではないので、存在するかチェックする必要があります。

というわけで、下記の様に書いてみましょう。

book = getBookByISBN(event.message['text']) # ISBNを検索して書籍情報を変数に代入する
messages = [] # 返信するメッセージ用の変数
if book.nil?
  # 書籍が空だった場合
  messages.push({
    type: 'text',
    text: '書籍が見つかりませんでした'
  })
else
  # 書籍が見つかった場合
  if !book['summary']['cover'].empty? 
    # 表紙画像があった場合
    messages.push({
      type: 'image',
      originalContentUrl: book['summary']['cover'],
      previewImageUrl: book['summary']['cover'],
    })
  end
  messages.push({
    type: 'text',
    text: book['summary']['title']
  })
end
client.reply_message(event['replyToken'], messages)

デプロイしよう

これで表紙画像の返信機能は完成です!
下記コマンドを入力してデプロイしてみましょう。

$ git add -A
$ git commit -m "add cover image"
$ git push heroku master

デプロイが完了したら、LINE BotにISBNを送信してみましょう。
下のスクリーンショットの様に表紙画像と書籍名が返ってきたら成功です!

余談

簡単なエラーチェックもしているので、存在しないISBNを送信すると、きちんとエラーが返ってきます。

また、表紙画像が無い書籍の場合はこのようにタイトルのみが返ってくるようになっているはずです。

まとめ

この記事では送られてきたISBNを元に書籍のタイトルと画像を返すBotを作りました!
複数のメッセージを送信する所など、Bot作りに便利な部分を含んでいるので、覚えておくと便利だと思います!

連載記事一覧

  1. Ruby + SinatraでLINE Botを作ろう - Part 1 - オウム返しするBotを作ろう ← イマココ
  2. Ruby + SinatraでLINE Botを作ろう - Part 2 - 書籍を検索して情報を返そう
  3. Ruby + SinatraでLINE Botを作ろう - Part 3 - 検索した書籍を記録しよう