LINE APIでオーキードーキー博士とポケモンGETリクエストしようぜ！

# 企画意図
初心者のプログラミングスキルで、最低限の面白さを表現するために、人気IPである〇〇モン（デジモンじゃない方）のデータを呼び出せるAPIの力を全力で借りて、オリジナルLINEBotの実装を目指します。

今回使用する、APIに関しては、こちらのシンプルにAPIが体験できるリストをまとめたページから選びました。初心者の方は参考にしてみてください。（僕には全然シンプルじゃなかったけどね！）

https://zenn.dev/protoout/books/public-apis-api-get

### 環境
Node.js
axios
Express
ngrok

＜使用API＞
LINE Messaging API SDK for nodejs
PokeAPI

## 作成するオーキードーキー博士BOTの説明

![IMG_20220323_175131_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2562329/fa9939fa-993d-3187-f122-4ba72d0a4dd2.jpeg)

何か親しみを感じるおじさんの顔が見えますね。紹介します、オーキードーキー博士です。（N社に怒られませんように）

今回実装する「オーキードーキー博士Bot」は、「ポケモン」という言葉を聞くと、初代ポケットモンスターに登場した151のポケモンの中から、あなたにぴったりなポケモンを選び、本日のラッキーモンスターとして提案してくれます。

それ以外の会話には、お前の話はつまらんと言わんばかりに話を遮り、「ポケモン」の話を促してきます。なかなか、頑固な性格のようです。自分の話だけしたがる方、時々いますよね。

（実装力がないばかりに、頑固な性格にしてしまってごめんよ、博士…。）

## 実際のBotの挙動

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">当初の計画通りには行きませんでしたが、ひとまず動くことをゴールにしました！オーキードーキー博士が、今日のラッキーポケモンをぶっきらぼうに教えてれるBOTです。<a href="https://twitter.com/hashtag/API?src=hash&amp;ref_src=twsrc%5Etfw">#API</a> <a href="https://twitter.com/hashtag/JS?src=hash&amp;ref_src=twsrc%5Etfw">#JS</a> <a href="https://twitter.com/hashtag/LINE?src=hash&amp;ref_src=twsrc%5Etfw">#LINE</a> <a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/%E3%83%9D%E3%82%B1%E3%83%A2%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#ポケモン</a> <a href="https://t.co/Yka4omPDHF">pic.twitter.com/Yka4omPDHF</a></p>&mdash; yoshio333 (@yoshio333333) <a href="https://twitter.com/yoshio333333/status/1506578272150118403?ref_src=twsrc%5Etfw">March 23, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



オーキードーキー博士のLINEBotと、ともだちになりたい方はこちら
↓
![717wplxf (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2562329/62878093-9e1b-1a67-aa6e-096b5b6c6168.png)

※博士は気難しいので、時間帯によって既読スルーをしたり、明後日な返答をすることがあります。

## ソースコード

まずは、全体のソースコードです。

```js
'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サーバーを実行中です…`);

```

### 各部の解説　①（乱数の設定）

では、細かい要素を説明していきます。

```js
  // 1〜151の数をランダムに吐き出す
 let a = Math.floor(Math.random() * 151)
```
PokeAPIは、IDでポケモンを呼び出せます。そのため、初代のポケモンが割り振られている1〜151の数字を吐き出すように「a」という関数をあらかじめ設定しておきます。（ゲームボーイの初代しかやったことがない。）

### 各部の解説　②（関数をAPI内に呼び出す）

```js
 const res = await axios.get('https://pokeapi.co/api/v2/pokemon-form/' + a);
  console.log(res.data);
```
そしてaxiosでPokeAPIを呼び出すURLに、先程の乱数を生み出す関数「a」を入れこみます。こうすることで、毎回ランダムに数字が入るようになり、色々なポケモンのデータが呼び出されるようになります。

### 各部の解説　③（ポケモンの画像を呼び出す）

先程の、コードでランダムに呼び出されたポケモン一体のいろいろなデータが呼び込まれているので、その中から、さらにポケモンの画だけを指定し（front_default）image形式で吐き出すようにしておきます。
```js
pushData = {type: 'image',
  originalContentUrl: res.data.sprites.front_default,
  previewImageUrl: res.data.sprites.front_default};
```

### 各部の解説　④（LINEプラットフォームに送る）

先程の関数pushDataの中に、ポケモンの画像が入っているので、下記のコードでLINEプラットフォームに戻します。後は、LINEがいい感じに「ポケモン」と送ってきた、ユーザーのところに、ポケモンの画像を送り届けてくれます。

```js
return client.replyMessage(event.replyToken,pushData)
```

## つまずいたポイント

その①
let pushData = {};
letで関数を指定しているときに、その関数はletのある｛｝の中でしか効かなくなるようです。関数を指定する場所は気をつけましょう。

その②

必要のない箇所を””で囲んでしまっていたので、ただの文字として認識されてしまっていました。

＜不正解＞
```js
originalContentUrl: "res.data.sprites.front_default"
```
＜正解＞
```js
originalContentUrl: res.data.sprites.front_default,
```

正しいコードを書いていなかったので、結果何度も深夜にポケモンと叫び続けることになりました。みなさま、コードは正確に！


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">怪しげなところを直してみるが、LINEAPIがちっとも返事をしてくれないので、ポケモンをGETできない<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://t.co/nZXuena9fq">pic.twitter.com/nZXuena9fq</a></p>&mdash; yoshio333 (@yoshio333333) <a href="https://twitter.com/yoshio333333/status/1505970420440215552?ref_src=twsrc%5Etfw">March 21, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 本当はやりたかったこと
「もっと優しい博士にしたかった。」
「オーキードーキー博士はポケモンの画像を返してくれるが、それにあわせてポケモンの名前や、少しフレンドリーなセリフも戻したかった。」

```js
 return client.replyMessage(event.replyToken,pushData)
 
 return client.replyMessage(event.replyToken, {
 type: 'text',
 text: '今日の君のラッキーモンスターは**じゃ。いい日になりそうじゃのう。'})
```
こんな感じのコードで（これは、動きません）

ただ、JavaScriptは、returnで一つの値しか返せないらしく、それを解決する方法もあるらしいのですが、時間切れとなり、現状の石頭タイプのオーキードーキー博士に仕上がりました。

やはり今のままだと、やり取りにそっけない感じがあり、まだまだ物足りなさがあります。妻にも、実際にオーキードーキー博士と戯れてもらいましたが、フーンと言う感じでした。「あんなに夜作業してるのにこの程度ですか」と思われていないだろか…。やりたいことと、企画に手が追いつかない悔しさよ…。

そして博士！！プログラミングの勉強をちゃんとして、いつか、やさしくてひょうきんな博士に戻してやるからな！！

## 次回予告
![名称未設定のデザイン (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2562329/68a634e0-a00a-74b9-7feb-e7fcab268822.png)


次回 #protoout 「やさしくなったオーキードーキー博士！？」
みんなも、俺と一緒にポケモンGETリクエストだぜ！

それでは、次の課題で会いましょう！