はじめに
BitStar Advent Calender12日目を担当するBitStarの@tak_11です!
BitStarに入社し半年ほどが経った頃、新しいプロダクト開発でReact, TypeScriptを使うことになりました。
未経験のバックエンドエンジニアとして入社したものの、
React, TypeScriptよくわからん!!けどなんかかっこいい!!自分も触りたい!!
という不純な動機でとりあえずTypeScriptの勉強を始めたのですが、その時のことを備忘録を兼ねて記事にしてみます。
line公式ドキュメントを参考に、送信したメッセージをオウム返しするline botを作成しました。
というかほとんどJavaScriptで書かれているものをTypeScriptに書き直しただけです笑
https://line.github.io/line-bot-sdk-nodejs
実際に作成したのは2023/2頃のため、現在の仕様と異なっている場合があります。
あくまで参考程度に見ていただけると幸いです。
準備
LINE Developersでアカウント作成
line botの作成にはLINE Developersでアカウントを作成してアクセストークン等を取得する必要があります。
こちらに関しては公式や他の方の記事で詳しく説明されているので割愛させていただきます。
ディレクトリ作成
設定はデフォルトで問題ないので-y
とします。
$ npm init -y
次に必要なパッケージをインストールします。
$ npm i @line/bot-sdk dotenv express
次に開発環境でのみ必要なパッケージをインストールします。
$ npm i -D @types/express @types/node nodemon
tsconfigを初期化します。
$ tsc --init
最後にtsconfigの設定を少し書き換えます。
"rootDir": "./src"
"outDir": "./dist"
これで準備は完了です。
実装
それでは実装していきましょう。
srcディレクトリを作成し、app.tsファイルを作成します。
$ mkdir src
$ touch src/app.ts
サーバーを立ち上げる
lineメッセージを受け取れるようにする前に、まずはローカルにサーバーを立ち上げてアクセスできるか確認しましょう。
import express, { Request, Response } from "express";
const app = express();
const PORT = 3000;
app.listen(PORT);
app.get("/", (_req: Request, res: Response) => {
res.send("hello, world!");
});
ターミナルでコマンドを実行し、typescriptをコンパイルします。
$ tsc -w
別のターミナルを開いて、コンパイルしたファイルを実行します。
nodemonをインストールしているので実行したファイルに変更があればサーバーを自動で再起動してくれます。
$ nodemon dist/app.js
localhost:3000
にアクセスして、
と表示されれば成功です!
メッセージを受け取れるようにする
取得したアクセストークン等を環境変数として使用するため、dotenv
を使用します。
まずは新しく.env
ファイルを作成します。
$ touch .env
取得したチャネルシークレットとアクセストークンを.env
ファイルに記述します。
LINE_CHANNEL_SECRET="取得したチャネルシークレット"
CHANNEL_ACCESS_TOKEN="取得したアクセストークン"
.env
に記述した情報を読み込みます。
import dotenv from "dotenv";
dotenv.config();
const config: Config = {
channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN,
channelSecret: process.env.LINE_CHANNEL_SECRET,
};
次に必要なモジュールをインポートします。
import { middleware, Config, MiddlewareConfig } from "@line/bot-sdk";
受け取ったlineメッセージをコンソールに出力したいと思います。
まずは/webhook
でPOSTリクエストを受け付けれるようにします。
app.post("/webhook", middleware(config as MiddlewareConfig), (req: Request, _res: Response) => {
});
先ほどインポートしたmiddleware関数を第二引数で指定します。
これでリクエストを受け取った際にそのリクエストが不正でないか確認し、渡ってきたwebhookオブジェクトをJSONとして受け取れるようにします。
また、middleware関数の引数としてチャネルシークレットの値が必要です。
先ほど定義したconfigの中に定義されているのでそちらを使いましょう。
引数の型はMiddlewareConfig
と設定されているので型アサーションして記述します。
次にリクエストを受け取った時の処理を追加します。
app.post("/webhook", middleware(config as MiddlewareConfig), (req: Request, _res: Response) => {
+ console.log(req.body.events[0].message);
});
req.body.events
の中に配列でwebhookEventオブジェクトが格納されており、そのオブジェクトのmessageプロパティで送信したメッセージ内容を確認できます。
ngrokを使って外部からメッセージを送れるようにする。
次にngrokを使って外部にアプリケーションを公開します。
ちなみにエングロックと読むみたいです。
$ brew install ngrok
アカウントの作成もしましょう。
https://ngrok.com/download
アカウントが作成できたらターミナルでプロジェクトのルートパスに移動し、以下のコマンドを実行します。
$ ngrok http 3000
すると以下のURLが表示されます。
Forwarding https://{hogehoge}.jp.ngrok.io -> http://localhost:3000
https://{hogehoge}.jp.ngrok.io
にアクセスするとサーバー立ち上げの際に確認した、hello, world!が表示されます。
これでサーバーを立ち上げているPC以外からもアクセスできるようになりました!
ちなみに{hogehoge}の部分はngrokを起動するたびに変わる乱数なので再起動ごとにURLが変わります。
最後にLINE Developersコンソールを開き、「Messaging API設定」からWebhook URLを設定します。
ここに先ほどngrokで取得したURLに/webhook
を追加して記入します。
実際にメッセージを送ってみる
まずはLINE Developersのコンソールにline botのQRコードがあるので友達追加しましょう。
そして追加したline botのトークルームで試しに「テスト」と送ってみましょう。
するとnodemonを実行しているターミナルにメッセージ内容が表示されているはずです。
{ type: 'text', id: 'xxxxxxxxxxxx', text: 'テスト' }
オウム返ししてみる
送信したメッセージをオウム返しするようにします。
追加で必要なモジュールをインポートします。
// Client, ClientConfig, WebhookEventを追加
- import { middleware, Config, MiddlewareConfig } from "@line/bot-sdk";
+ import { Client, middleware, Config, ClientConfig, MiddlewareConfig, WebhookEvent } from "@line/bot-sdk";
以下のコードを追加します。
const client = new Client(config as ClientConfig);
const handleEvent = (event: WebhookEvent) => {
if (event.type !== "message" || event.message.type !== "text") {
return Promise.resolve(null);
}
return client.replyMessage(event.replyToken, {
type: "text",
text: event.message.text,
});
};
handleEvent関数では、まず渡ってきたwebhookイベントの中身がテキストメッセージか確認し、違っていればnull
を返します。
テキストメッセージであればreplyMessage関数を呼び出し返信します。
第一引数でeventのreplyTokenを指定し、第二引数に返したいメッセージを格納したオブジェクトを指定します。
typeプロバティには"text"を指定し、オウム返しをしたいのでtextプロパティには渡ってきたメッセージをそのまま格納します。
これでオウム返しする関数の完成です。
ではこれをメッセージが送られてきた時に実行されるようにします。
先ほど書いたコードを一部修正します。
app.post("/webhook", middleware(config as MiddlewareConfig), (req: Request, res: Response) => {
- console.log(req.body.events[0].message);
+ Promise.all(req.body.events.map(handleEvent)).then((result) => {
+ res.json(result);
+ });
});
events
に格納されてるのはWebhookEventオブジェクトの配列です。
また、handleEventで呼び出されるreplyMessageの戻り値はPromiseオブジェクトです。
なのでmapメソッドでPromiseオブジェクトの配列を作成し、Promise.allの引数として渡します。
最後にthenメソッドを繋げてレスポンスを定義したら完了です。
オウム返しを確認する
振り返り
いかがだったでしょうか?
改めて振り返るとなぜReact, TypeScriptの組み合わせではなくNode.js, TypeScriptだったのか。笑
最後に
BitStarでは最初に触れたReact, TypeScriptやRuby, Railsを活用した開発を行っており、一緒に開発できるエンジニアを積極募集中です!
ご興味のある方はぜひ以下の募集情報をご確認ください!