teratail Report vol.13

2018/8/28

LINE API Experts4人で富士通Playgroundを使ってオジサンほいほいなLINE BOTを作ってみた

こんにちは、teratailエキスパートユーザーの菅原のびすけです。
この度、LINE API Expertsに選出されました。
僕以外にも4名選出され、日本国内で5人のAPI Expertsが選出されています。
(執筆当時は国内5名、現在は追加選出があり国内10名となっています。)
今回、なんとその中の4人(僕を含む)に協力いただき、みんなでLINE BOTを作ってみました。
teratail Reportで、その様子をお届けしたいと思います。

富士通からの企画の打診

のびすけ富士通からPlaygroundってツールを使って欲しいという打診がきてます!

LINE BOTをみんなで作ってみましょう。

若狭富士通といえば蒲田。蒲田と言えば羽根つきギョウザなので、みんなでギョウザでも食べながら考えましょう。

小林いいですね。とりあえずギョウザいきますか。

富士榮蒲田遠いですし、蒲田で有名なお店の支店が田町にあるので田町にいきましょ。

ということで富士通とはなんの関係もない田町に舞い降りました。

企画会議(飲み会)スタート

早速乾杯をして、企画会議スタートです!

簡単に今日のメンバーを紹介します。

若狭 正生氏

わかさ まさお若狭 正生

LINE BOT AWARDS でGEEK部門賞を受賞した「写クレ」を発表して以降、Code IQなどの媒体でLINE Bot開発の魅力を独特のマシンガントークで展開。Mashup Awards 2017に向けては地域課題を解決するサービスとして「ひぐまっぷbot」を開発。技術力もさることながら、独特のキャラクターでファンが多いインフルエンサーで、クリエイター層にLINE Bot開発の可能性や楽しさを伝え続けています。

富士榮 尚寛氏

ふじえ なおひろ富士榮 尚寛

LINE Loginを活用したソリューションを開発されているCTCの富士榮さんはアイデンティティ技術の専門家として、長年にわたりMicrosoft MVPとして活躍されています。その知見を生かしてMicrosoft Azure Active Directory B2CとLINE Loginを連携させたソリューションによりLINE Loginの普及に貢献、LINE Login開発チームへのフィードバックを通じて機能改善に協力されています。

  • Twitterアカウント
  • Facebookアカウント
小林 寛忠 氏

こばやし ひろただ小林 寛忠

最初のコミュニティSDKとしてLINE Developersに公開された LINE Messaging APIのC# SDK のレポジトリオーナーであり、Microsoft所属の中村さんと協力し、公式SDKとして提供されてなかったC#向けのSDKを開発。さらに Visual Studio用の拡張プロジェクトも公開されています。他の言語や開発ツール、フレームワークでも開発コミュニティによる独自の拡張を期待されているエキスパートです。

  • Twitterアカウント
  • Facebookアカウント
菅原のびすけ 氏

すがわら のびすけ菅原のびすけ

LINE BOT AWARDSの立役者の一人。事務局、運営サイドでイベントを成功に導きました。自身が主催している IoT縛りの勉強会IoTLT は7,000名を超えるメンバーを抱え、エンジニアが気軽に楽しめるコミュニティ運営をされています。Node学園祭2017でのセッション「1時間でLINE BOTを作るハンズオン」の資料は、簡単にbotをつくりたいというニーズにこたえる完成度の高い資料で、多くの開発者に参照されています。

  • Twitterアカウント
  • Facebookアカウント

という4人でお送りします。

Playgroundとは

若狭そもそもPlaygroundってどんなことができるんですか?

のびすけPlaygroundは GUI画面で簡単な操作を行うだけで、Webサービスを作る際のテンプレートコードを吐き出してくれるオーサリングツールです。 無料で使えてバックエンドとフロントエンドの両方のコードに対応しています。

http://jp.fujitsu.com/solutions/cloud/k5/playground/lob/

とはいえ、僕も使ってみたのは最近になってからなので一緒に画面見ながら作ってみましょ。

のびすけトップページがこんな感じです。

若狭おしゃれですね。

のびすけGET STARTEDから進むと色々なWebアプリケーションのテンプレートを選択する画面になります。

富士榮いろいろなテンプレートがありますね。

のびすけ例えば地図系のアプリケーションの場合はMapを選択したりと、自分が作成するユースケースに近いものを選択します。

若狭フロントエンド側のテンプレートが作れるんですね?

のびすけそうです。 ただそれだけではなく、PlaygroundではAPIの追加や編集もGUIで行えます。例えばさっき紹介したMapのテンプレートだとデフォルトでGET /sample_locationsだけですが、例えばPOST /webhookのエンドポイントを作りたい時にはCreate a New WebAPIのフォームにwebhookと入力し、POSTの箇所にチェックを入れるだけでOKです。

のびすけこれでPOSTリクエストの/webhookAPIが出来ました。

若狭なるほど、フロントだけじゃなくてバックエンド側も生成されるんだ。

PlaygroundではLINEも含め各種APIの連携もカンタン

富士榮へぇ〜便利そうだね。でもこれ LINEと関係無いんじゃない?

のびすけちょっと待ってくださいね笑 もう少し使い方を見ていきます。

APIのエンドポイントを作るだけではなく、 内部ロジックに色々なAPIとの連携コードをGUIから追加することができます。

のびすけ例えば右側のAPI LogicsのカラムからLINE Messaging APIのブロックをドラッグ&ドロップで中央のAPIカラムに移動させるとLINE Messaging APIと連携するためのテンプレートコードが生成されます

作成したアプリケーションはJavaScript(React.jsとNode.js)のコードとしてDL可能

富士榮なるほど、これでLINE BOTも作れる訳だ。 GUIで作った後はどうやって開発をするのかな?

のびすけダウンロードボタンから作成したアプリケーションをダウンロードできます。

のびすけダウンロードしたzipファイルを展開すると、backendとfrontendの二つのフォルダを確認できます。

のびすけ実際にコードをエディタで開いてみると、先ほどGUIで編集したコードがしっかりと生成されています。

のびすけしかもswaggerに対応しているのでドキュメント管理もしっかりと出来ます。サクッとWebアプリケーションの作成が出来る手軽さにも関わらず、管理面も考えてくれています。

のびすけ今回はこの後LINE BOT作成に使うのでfrontend側のコードは割愛しますが、フロントエンド側もReactやWebpackといった流行りの技術スタックに対応してくれています。ここで気付く人も多いと思いますが、Playgroundの実態はNode.jsとReact.jsのコード生成になっています。

小林C#が使いたいなぁ。対応してないの?

のびすけ現状では......要望があれば今後他の言語にも対応していくかもしれないですね。

ギョウザ(エアポート)投稿おじさん

のびすけさて本題ですが、みんなで何作りましょうね......

富士榮うーむ

若狭少し前に話題になったエアポート投稿オジさんってあるじゃないですか。それをネタに何か出来ないですかね?

小林「さて私はどこにいくでしょう?」の質問がムカつくってやつですよね。

のびすけそれにしましょ笑

オジさんは若い子に構ってもらいたい

のびすけ機械学習させて画像認識ですかね。

小林通常通りだとその路線ですよね。でもおじさんってなんで写真投稿や急にクイズだしてくるんですかね?

若狭それはもう、 誰かに構ってもらいたいからですよ。

のびすけ裏側がAIだって分かりきってるとそもそも投稿しない可能性ありますね。

小林ソーシャルな世界につなげて応えてもらうのはどうでしょ?世界中の誰かが応えてくれるよ的な

富士榮おじさんは若い子に構ってもらいたいからTwitterやInstagramと連携できるといいね。構ってもらいたい...

のびすけそれなら投稿するかも! おじさんホイホイですね。

小林では、ギョウザの写真を投稿するとインターネット上の誰かが返事をしてくれる。そんなBOTにしましょう。

BOTの仕様

のびすけということでまとめてみるとこんな感じですね。

  • ① おじさんがギョウザの写真を撮る
  • ② ギョウザの写真をLINE BOTに送る「これはどこのギョウザでしょう」
  • ③ ギョウザ写真がTwitter BOTに投稿される
  • ④ 若者たちがツイートで返事をする
  • ⑤ おじさんは誰かが返事してくれて、承認欲求が満たされる

一同これは使うね☆

BOTの作成

のびすけでは実際に作ってみましょうか。

のびすけPlaygroundでアプリケーションを作成すると、アプリケーションごとにURLが生成されます。

ダウンロードをしたタイミングで情報が保存されるみたいですね。この仕組みを使うとGUIで作成中のアプリケーションをシェアして複数人で非同期的に作業することもできます。

急にコンソールになりますが(笑)、DLして展開したコードを見てみましょう。backendとfrontendのフォルダがあるので、backendフォルダに移動してnpmで依存パッケージのインストールを行います。

フォルダの確認

$ ls
README.md backend   frontend

backendフォルダに移動して依存パッケージインストール

$ cd backend
$ npm i

のびすけとりあえずアプリケーションの起動をしてみましょう。

$ npm start

> backend@1.0.0 start /Users/n0bisuke/.Trash/backend
> node index.js

Your server is listening on port 3000 (http://localhost:3000)
Swagger-ui is available on http://localhost:3000/docs

のびすけこれでアプリケーションが起動したのでhttp://localhost:3000にアクセスしてみましょう。

のびすけ表示されましたが、/のAPIを作成してなかったのでCannot GET /と表示されてしまいました。今回試してみたMapアプリケーションのデフォルトAPIがGET /sample_locationsだったのでhttp://localhost:3000/sample_locationsにアクセスしてみると分かりやすいです。

Twitter BOTの作成準備

のびすけちょっとここから分担していきましょうか。

小林Twitter BOTの作成準備しますね。Twitterアカウントを作って......

小林Twitter BOT用に4つのキーを取得します。

文章詳細は割愛しますが、Twitter BOTを作るときにはConsumer Key, Consumer Secret, Access Token ,Access Token Secretの4つのキーを使います。

小林Playgroundではツイート連携用にTwitterのFilitered Public Streamのブロックを追加ですね。

小林ただ、今回はロジック部分だけを使うので後でコードだけ別の箇所に移植します。

TweetのPOST部分は現状は無いようなのであとで独自に追加です。

LINE BOTの作成

のびすけLINEのDeveloper登録などは手前味噌ですがこちらの記事(1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest)を参照します。

LINE Developerのサイトで作成していきます。

のびすけngrokを利用してトンネリングすると開発が楽です。

$ npm i -g ngrok
$ ngrok http 3000

ngrok by @inconshreveable                                 (Ctrl+C to quit)

Session Status                online
Account                       n0bisuke (Plan: Free)
Version                       2.2.8
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://060afc3e.ngrok.io -> localhost:3000
Forwarding                    https://060afc3e.ngrok.io -> localhost:3000

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00

のびすけここで表示されるアドレス(この場合060afc3e.ngrok.io)をLINE BOTの管理ページのWebhook URLに設定すれば開発が始められます。

のびすけPlaygroundで自動生成されたコードにconfig.jsがあります。ここにLINE BOTの管理ページにあるアクセストークンとチャンネルシークレットを設定して連携させます。

のびすけconfig.jsにはTwitterの記載も見えます。これはさっき小林さんがPlayground上でTwitter連携のブロックを追加したので追加されています。PlaygroundでAPI連携した分だけコードに反映されていますね。

Playgroundアプリケーションの開発

若狭これ、使ってみて気づいた注意点です。Playgroundで採用されているフレームワークのExpressですが、POSTリクエストの処理をする際にbodyParserを有効にする必要があります。デフォルトのindex.jsだとbodyParser部分がコメントアウトされているのでコメントを解除しましょう。

index.js
'use strict';

var app = require('express')();
var http = require('http');
var swaggerTools = require('swagger-tools');
var fs = require('fs');
var config = require('./config');
var cors = require('cors');
var bodyParser = require('body-parser'); //デフォルトだとコメントアウトされている箇所その1

var options = {
  swaggerUi: '/swagger.json',
  controllers: './controllers',
};

var swaggerDoc = JSON.parse(fs.readFileSync('./api/swagger.json', 'utf8'));

swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) {

// @see https://github.com/expressjs/body-parser#bodyparserjsonoptions
// @todo change the value if you need to handle the body size larger than 100kb.
  app.use(bodyParser.json({
    limit: '100kb',
  })); //デフォルトだとコメントアウトされている箇所その2

  app.use(cors());
  app.use(middleware.swaggerMetadata());
  app.use(middleware.swaggerValidator());
  app.use(middleware.swaggerRouter(options));
  app.use(middleware.swaggerUi());

  http.createServer(app).listen(config.serverPort, function () {
    console.log('Your server is listening on port %d (http://localhost:%d)', config.serverPort, config.serverPort);
    console.log('Swagger-ui is available on http://localhost:%d/docs', config.serverPort);
  });
});

若狭まずは呼びかけたら反応するBOTを作って挙動の確認をします。logics/webhookPOST.jsの編集です。PlaygroundのブロックだとLINE Messaging API - Send Messageが使いやすいのでこれをベースに話をします。

若狭POSTリクエストのoptionsの箇所のurlとtoの箇所を変更します。

logics/webhookPOST.js

省略

  var options = {
    // url: 'https://api.line.me/v2/bot/message/push',
    url: 'https://api.line.me/v2/bot/message/reply', //変更
    method: 'post',
    headers: {
      'Authorization': 'Bearer ' + accessToken,
    },
    json: {
      // "to": messageReceiverId,
      "replyToken": req.body.events[0].replyToken, //変更
      "messages": message,
    }
  };

省略

若狭これでアプリケーションを再起動して呼びかけると......

若狭無事にhello worldと返ってきました。

ちなみにPlayground上でコードの編集が出来て状態の保存もされるので、DLする前に編集しておくとチーム開発も可能です。

小林あれ、僕先にDLしてローカル編集しちゃってました......

若狭マージ頑張りましょ......

写真を受け付ける

富士榮このBOTに写真を投稿できるようにしましょうか。Messaging APIのリファレンスのコンテンツを取得するの箇所を確認します。

GET https://api.line.me/v2/bot/message/{messageId}/contentで画像を受けられます。

logics/webhookPOST.js

省略

  var accessToken = config.line.accessToken;
  var messageReceiverId = '';

  if(req.body.events[0].message.type === 'image'){
    let options = {
      url: `https://api.line.me/v2/bot/message/${req.body.events[0].message.id}/content`, //変更
      method: 'get',
      headers: {
        'Authorization': 'Bearer ' + accessToken,
      },
      encoding: null
    };

    Request(options, function(error, response, body) {
      if (!error && response.statusCode == 200) {
        require('fs').writeFileSync(`./image.jpg`, new Buffer(body), 'binary');
        // Returns the status code 200 OK and an empty JSON object.
        // console.log(response.body);
        next(body);
      } else {
        console.log(error);
        // @todo handle error
      }
    });
  }else{
    next(req.body);
  }

省略

富士榮LINE BOTに送った画像は全てjpg画像になって取得できるのでimage.jpgという名前で固定して保存します。

Twitterにも投稿

のびすけTwitterと連動させましょう。Twitterブロックで生成されたコードを編集してmedia/uploadstatuses/updateの機能を追加します。画像は先ほど保存したimage.jpgです。

logics/webhookPOST.js

省略

  const twitter = require('twitter');
  const client = new twitter({
    consumer_key: config.twitter.consumerKey,
    consumer_secret: config.twitter.consumerSecret,
    access_token_key: config.twitter.accessTokenKey,
    access_token_secret: config.twitter.accessTokenSecret
  });

  const data = require('fs').readFileSync('./image.jpg');
  const mes = 'どこのギョウザでしょう。';

  (async () => {
    const media = await client.post('media/upload', {media: data});
    console.log(media);
    const status = {
        status: mes,
        media_ids: media.media_id_string // Pass the media id string
    }
    const response = await client.post('statuses/update', status);
    // console.log(response);
    next(req.body);
  })();

省略

のびすけこれでLINE側で保存した画像をTwitterに投稿できます。

ちなみにこの辺のブロックを追加したときの仕組みですが、コードをみるとこんな構成になっています。

logics/webhookPOST.js

exports.webhookPOSTStart = function (req, res, results, next) {
  //処理1
}

exports.webhookPOST1 = function (req, res, results, next) {
  //処理2
}

exports.webhookPOST2 = function (req, res, results, next) {
  //処理3
}

exports.webhookPOSTEnd = function (req, res, results, next) {
  //処理4
}

のびすけブロックを追加するとPOST1,POST2,POST3......と繋がっていきます。これはcontrollers/Map.js側で入れ子状態に関数を実行する仕組みになっていて処理をそれぞれの関数に分けて記述しても次へと繋げてくれています。

controllers/Map.js

省略

module.exports.webhookPOST = function webhookPOST (req, res, next) {
  webhookPOSTLogic.webhookPOSTStart(req, res, {}, function (result) {
    webhookPOSTLogic.webhookPOST1(req, res, result, function (result) {
      webhookPOSTLogic.webhookPOST2(req, res, result, function (result) {
        webhookPOSTLogic.webhookPOSTEnd(req, res, result);
      });
    });
  });
};

省略

Twitterのリプライを拾う

小林Twitter上で反応があったらLINE側に投稿するロジックを組みましょう。

ここはPlaygroundで生成されたコードがそのまま使えるので楽ですね。

webhookPOST.js

省略

const twitter = require('twitter');
const keyword = '@gyoza_experts';  
const client = new twitter({
  consumer_key: config.twitter.consumerKey,
  consumer_secret: config.twitter.consumerSecret,
  access_token_key: config.twitter.accessTokenKey,
  access_token_secret: config.twitter.accessTokenSecret
});

client.stream('statuses/filter', {track: keyword}, function(stream) {
  stream.on('data', function(tweet) {
    //反応があった場合の処理
    //ここにLINE側への投稿処理を追加
  });

  stream.on('error', function(error) {
    // @todo handle error
  });
});

省略

小林注意点としてはWebhookでAPIリクエストを受けたタイミングで起動するのではなく、アプリケーションの起動時に実行できるようにルーティング箇所じゃない場所に記述しましょう。

デプロイ

若狭あとはクラウドにPushすれば......完成です! 手順が短いのでnowを使います。

$ npm i -g now
$ now

若狭これでデプロイ完了です。

実際に使ってみた

のびすけじゃこの出来たBOTを使って投稿してみましょうか。

カシャカシャカシャ

のびすけ撮った写真をBOTに送ると......

のびすけツイッターに投稿された!

一同(今私はどこにいるでしょう.....)

返事が来るまで飲み続ける一行










返事が!

のびすけ誰かから返事がありました!

富士榮やっぱり返事があると嬉しいですね。

小林全自動よりも後ろに人がいた方が投稿しがいがある。

のびすけ

まとめ

いかがでしたでしょうか。
Playgroundを使うことでLINE BOTもカンタンに作成することができました。
API Expertsが集まったから作れたとかそういう話ではなく、本当に手軽なツールだと思うのでオススメです。
これを機に一度触ってみてはいかがでしょうか。

それにしてもギョウザ投稿おじさん。
平和な世界ですね。(裏で僕がツイートにリプライしてたんですけどね......笑)

▼詳しくはこちら