企画意図
初心者のプログラミングスキルで、最低限の面白さを表現するために、人気IPである〇〇モン(デジモンじゃない方)のデータを呼び出せるAPIの力を全力で借りて、オリジナルLINEBotの実装を目指します。
今回使用する、APIに関しては、こちらのシンプルにAPIが体験できるリストをまとめたページから選びました。初心者の方は参考にしてみてください。(僕には全然シンプルじゃなかったけどね!)
環境
Node.js
axios
Express
ngrok
<使用API>
LINE Messaging API SDK for nodejs
PokeAPI
作成するオーキードーキー博士BOTの説明
何か親しみを感じるおじさんの顔が見えますね。紹介します、オーキードーキー博士です。(N社に怒られませんように)
今回実装する「オーキードーキー博士Bot」は、「ポケモン」という言葉を聞くと、初代ポケットモンスターに登場した151のポケモンの中から、あなたにぴったりなポケモンを選び、本日のラッキーモンスターとして提案してくれます。
それ以外の会話には、お前の話はつまらんと言わんばかりに話を遮り、「ポケモン」の話を促してきます。なかなか、頑固な性格のようです。自分の話だけしたがる方、時々いますよね。
(実装力がないばかりに、頑固な性格にしてしまってごめんよ、博士…。)
実際のBotの挙動
当初の計画通りには行きませんでしたが、ひとまず動くことをゴールにしました!オーキードーキー博士が、今日のラッキーポケモンをぶっきらぼうに教えてれるBOTです。#API #JS #LINE #protoout #ポケモン pic.twitter.com/Yka4omPDHF
— yoshio333 (@yoshio333333) March 23, 2022
オーキードーキー博士のLINEBotと、ともだちになりたい方はこちら
↓
※博士は気難しいので、時間帯によって既読スルーをしたり、明後日な返答をすることがあります。
ソースコード
まずは、全体のソースコードです。
'use strict';
// ########################################
// 初期設定など
// ########################################
// パッケージを使用します
const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
// ローカル(自分のPC)でサーバーを公開するときのポート番号です
const PORT = process.env.PORT || 3000;
// Messaging APIで利用するクレデンシャル(秘匿情報)です。
const config = {
channelSecret: '**************',
channelAccessToken: '******************};
// ########## ▼▼▼ サンプル関数 ▼▼▼ ##########
const sampleFunction = async (event) => {
// 1〜151の数をランダムに吐き出す
let a = Math.floor(Math.random() * 151)
let pushData = {};
let replyText = '';
if (event.message.text === 'ポケモン') {
// axiosでpokeAPIを叩きます
const res = await axios.get('https://pokeapi.co/api/v2/pokemon-form/' + a);
console.log(res.data);
// 画像を送るメッセージを作る
pushData = {type: 'image',
originalContentUrl: res.data.sprites.front_default,
previewImageUrl: res.data.sprites.front_default};
return client.replyMessage(event.replyToken,pushData)
}
else {
replyText = 'その話題はつまらん。わしはオーキードーキー博士じゃ。正確に「ポケモン」と入力すると、今日のラッキーモンスターを教えてやるぞ!';
return client.replyMessage(event.replyToken, {
type: 'text',
text: replyText})
}
;
};
// ########## ▲▲▲ サンプル関数 ▲▲▲ ##########
// ########################################
// LINEサーバーからのWebhookデータを処理する部分
// ########################################
// LINE SDKを初期化します
const client = new line.Client(config);
// LINEサーバーからWebhookがあると「サーバー部分」から以下の "handleEvent" という関数が呼び出されます
async function handleEvent(event) {
// 受信したWebhookが「テキストメッセージ以外」であればnullを返すことで無視します
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
// サンプル関数を実行します
return sampleFunction(event);
}
// ########################################
// Expressによるサーバー部分
// ########################################
// expressを初期化します
const app = express();
// HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をします
app.post('/webhook', line.middleware(config), (req, res) => {
// 検証ボタンをクリックしたときに飛んできたWebhookを受信したときのみ以下のif文内を実行
if (req.body.events.length === 0) {
res.send('Hello LINE BOT! (HTTP POST)'); // LINEサーバーに返答します(なくてもよい)
console.log('検証イベントを受信しました!'); // ターミナルに表示します
return; // これより下は実行されません
} else {
// 通常のメッセージなど … Webhookの中身を確認用にターミナルに表示します
console.log('受信しました:', req.body.events);
}
// あらかじめ宣言しておいた "handleEvent" 関数にWebhookの中身を渡して処理してもらい、
// 関数から戻ってきたデータをそのままLINEサーバーに「レスポンス」として返します
Promise.all(req.body.events.map(handleEvent)).then((result) => res.json(result));
});
// 最初に決めたポート番号でサーバーをPC内だけに公開します
// (環境によってはローカルネットワーク内にも公開されます)
app.listen(PORT);
console.log(`ポート${PORT}番でExpressサーバーを実行中です…`);
各部の解説 ①(乱数の設定)
では、細かい要素を説明していきます。
// 1〜151の数をランダムに吐き出す
let a = Math.floor(Math.random() * 151)
PokeAPIは、IDでポケモンを呼び出せます。そのため、初代のポケモンが割り振られている1〜151の数字を吐き出すように「a」という関数をあらかじめ設定しておきます。(ゲームボーイの初代しかやったことがない。)
各部の解説 ②(関数をAPI内に呼び出す)
const res = await axios.get('https://pokeapi.co/api/v2/pokemon-form/' + a);
console.log(res.data);
そしてaxiosでPokeAPIを呼び出すURLに、先程の乱数を生み出す関数「a」を入れこみます。こうすることで、毎回ランダムに数字が入るようになり、色々なポケモンのデータが呼び出されるようになります。
各部の解説 ③(ポケモンの画像を呼び出す)
先程の、コードでランダムに呼び出されたポケモン一体のいろいろなデータが呼び込まれているので、その中から、さらにポケモンの画だけを指定し(front_default)image形式で吐き出すようにしておきます。
pushData = {type: 'image',
originalContentUrl: res.data.sprites.front_default,
previewImageUrl: res.data.sprites.front_default};
各部の解説 ④(LINEプラットフォームに送る)
先程の関数pushDataの中に、ポケモンの画像が入っているので、下記のコードでLINEプラットフォームに戻します。後は、LINEがいい感じに「ポケモン」と送ってきた、ユーザーのところに、ポケモンの画像を送り届けてくれます。
return client.replyMessage(event.replyToken,pushData)
つまずいたポイント
その①
let pushData = {};
letで関数を指定しているときに、その関数はletのある{}の中でしか効かなくなるようです。関数を指定する場所は気をつけましょう。
その②
必要のない箇所を””で囲んでしまっていたので、ただの文字として認識されてしまっていました。
<不正解>
originalContentUrl: "res.data.sprites.front_default"
<正解>
originalContentUrl: res.data.sprites.front_default,
正しいコードを書いていなかったので、結果何度も深夜にポケモンと叫び続けることになりました。みなさま、コードは正確に!
怪しげなところを直してみるが、LINEAPIがちっとも返事をしてくれないので、ポケモンをGETできない#protoout pic.twitter.com/nZXuena9fq
— yoshio333 (@yoshio333333) March 21, 2022
本当はやりたかったこと
「もっと優しい博士にしたかった。」
「オーキードーキー博士はポケモンの画像を返してくれるが、それにあわせてポケモンの名前や、少しフレンドリーなセリフも戻したかった。」
return client.replyMessage(event.replyToken,pushData)
return client.replyMessage(event.replyToken, {
type: 'text',
text: '今日の君のラッキーモンスターは**じゃ。いい日になりそうじゃのう。'})
こんな感じのコードで(これは、動きません)
ただ、JavaScriptは、returnで一つの値しか返せないらしく、それを解決する方法もあるらしいのですが、時間切れとなり、現状の石頭タイプのオーキードーキー博士に仕上がりました。
やはり今のままだと、やり取りにそっけない感じがあり、まだまだ物足りなさがあります。妻にも、実際にオーキードーキー博士と戯れてもらいましたが、フーンと言う感じでした。「あんなに夜作業してるのにこの程度ですか」と思われていないだろか…。やりたいことと、企画に手が追いつかない悔しさよ…。
そして博士!!プログラミングの勉強をちゃんとして、いつか、やさしくてひょうきんな博士に戻してやるからな!!
次回予告
次回 #protoout 「やさしくなったオーキードーキー博士!?」
みんなも、俺と一緒にポケモンGETリクエストだぜ!
それでは、次の課題で会いましょう!