# (チュートリアル)Node.jsを使ってサンプル応答ボットを作る

Messaging APIは、サービスとLINEユーザーとの間で双方向のコミュニケーションを可能にする機能です。

Messaging APIの機能を利用してユーザーとの交流を深めることができます。様々な種類のメッセージの送信、ユーザープロフィールの取得、ユーザーが送信したコンテンツの取得など、その機能は多岐にわたります

このチュートリアル記事では、Node.jsを使ってMessaging APIでメッセージを送信する方法を説明します。

# チュートリアルのゴール

このチュートリアルを最後まで進めると、Messaging APIの使い方を実践的に学べるとともにユーザーが送信したメッセージに自動的に応答するアプリが作成できます。

サンプルボットとの会話イメージ

# 始める前に

このチュートリアルを始める前に、いくつかのコンセプトやツールについて確認しておくとよりスムーズに進めることができます。

このチュートリアルではSDKを使用しません

このチュートリアルではMessaging APIの仕様の理解やアプリのカスタム化を目的として、LINEが提供するSDKを使わずにNode.jsでMessaging APIを使用する方法を紹介します。Node.jsでMessaging APIをより少ないコード行数で素早く利用したい場合は、LINE Messaging API SDK for nodejs (opens new window)の利用をお勧めします。

# 想定される技術的知識

このチュートリアルは、JavaScriptとNode.jsの基本的な知識を必要とします。

# Messaging APIの概要

このチュートリアルをスムーズに進めるために、『Messaging APIドキュメント』の「Messaging APIの概要」を読んでおくことをお勧めします。

# 必要なツール

アプリを作成するには、以下のツールの登録およびインストールが必要です。

# Herokuの設定

まずは、Herokuの環境を整えましょう。ターミナルまたはコマンドラインツールを開いてください。

まだHeroku CLIにログインしていない場合は、このコマンドを実行しログインします。

heroku login

このコマンドをアプリを作成したい場所で実行すると、新しいディレクトリが作成され、Gitが初期化され、Herokuを使った新しいアプリが作成されます。

mkdir sample-app
cd sample-app
git init
heroku create {Name of your app}

{Name of your app}には、一意の名前を入力してください。たとえば次のような名前を推奨します。msg-api-tutorial-{YYYYMMDD}

アプリが問題なく作成されると、HerokuのURLがhttps://{Name of your app}.herokuapp.com/のような形式で生成されます。このURLは後で必要になります。

生成されたHerokuのURLに、ブラウザでアクセスしてみてください。ウェルカムページが表示されます。

ウェルカムページ

# package.jsonファイルを作成する

npmがプロジェクトを識別やプロジェクトのメタデータを保持、依存関係を処理できるようにするために、package.jsonファイルを作成しましょう。プロジェクトのルートディレクトリで、次のように実行します。

npm init -y

npm initは、npmパッケージを初期化します。このチュートリアルでは特別な設定は必要ないので、-yコマンドを使用して、パッケージをセットアップするための質問をすべてスキップします。

以下のようなpackage.jsonが作成されます。

{
  "name": "sample-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

また、Herokuのようなサーバープラットフォームが、サーバーの起動時にどのファイルを使用するかを知るために、スタートスクリプトを追加する必要があります。このチュートリアルでは、サーバーの設定ファイルとしてindex.jsを指定します。

作成したpackage.jsonファイルをテキストエディタで開き、"start": "node index.js"を追加しましょう。

{
  "name": "sample-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",  
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

このプロジェクトのために追加でインストールされたパッケージは、package.jsonで管理されます。このアプリでは、以下のパッケージを使用します。

以下のコマンドを実行して、このパッケージをインストールしましょう。

npm install express

Express.jsをインストールすると、node_modulesというディレクトリが作成されます。このディレクトリにはローカルでインストールしたパッケージが保存されます。

このディレクトリがHerokuにプッシュされることを防ぐため、.gitignoreファイルを作成します。

以下のコマンドを実行して.gitignoreファイルを作成します。

touch .gitignore

作成した.gitignoreファイルをテキストエディタで開きます。.gitignoreの中に、以下を追加します。

node_modules/

# 開発を始める

# グローバル設定

サーバー設定ファイルのindex.jsを作りましょう。

touch index.js

作成したindex.jsファイルをテキストエディタで開きます。index.jsの中に、以下を追加します。

const https = require("https")
const express = require("express")
const app = express()

ここでは、先ほどインストールしたexpressパッケージと、httpsパッケージをインポートした上で、expressをインスタンス化しています。httpsは、このアプリのHTTPリクエストを処理するために使用するパッケージです。このパッケージは、Node.jsにデフォルトで付属しているので、expressパッケージのようにインストールする必要はありません。

続いて、必要な環境変数を追加しましょう。

環境変数とは、プログラムの外部で値が設定される変数です。このチュートリアルでは、設定プロセスを簡素化し、機密情報が誤って公開されるのを防ぐために使用します。

index.jsで、インポートしたパッケージの下に、以下を追加します。

const PORT = process.env.PORT || 3000
const TOKEN = process.env.LINE_ACCESS_TOKEN

process.env.PORTは、サーバーがどのポートにListenするかを指定します。process.env.LINE_ACCESS_TOKENは、Messaging APIを呼び出すために必要なチャネルアクセストークンを指定します。

# ミドルウェアの設定

Express.jsは、ミドルウェアのWebフレームワークです。ミドルウェア関数を使って、リクエストとレスポンスのサイクルを決めることができます。

このチュートリアルでは、Express.jsに付属するミドルウェア関数であるexpress.json()express.urlencoded()を使用して、リクエストオブジェクトをそれぞれJSON、文字列、配列として扱います。

ミドルウェアの機能を使用するために、app.use()を呼び出します。index.jsに、以下を追加します。

app.use(express.json())
app.use(express.urlencoded({
  extended: true
}))

# ルーティングの設定

それでは、ボットサーバに基本的なルーティングロジックを追加してみましょう。ベストプラクティスとして、ヘルスチェック等の失敗を防ぐためにドメインのルート(/)へのHTTP GETリクエストに対してステータス200を送信しましょう。

index.jsファイルに以下を追加します。

app.get("/", (req, res) => {
  res.sendStatus(200)
})

それでは、ボットサーバーに基本的なルーティングロジックを追加してみましょう。app.listen()関数を使って、サーバーがListenするポートを指定します。 環境変数PORTを設定しているので、特に指定されていない限り、3000をリッスンします。

index.jsに、以下の項目を追加します。

app.listen(PORT, () => {
  console.log(`Example app listening at http://localhost:${PORT}`)
})

ユーザーがボットと対話すると、LINEプラットフォームのサーバーは、ボットのサーバーがホストするWebhook URLにHTTP POSTリクエストを送信します。

app.post()は、指定されたパスへのHTTP POSTリクエストをルーティングします。この関数を使って、ボットサーバがこれらのリクエストにどのように応答するかを設定できます。

index.jsで、app.get()app.listen()関数の間に、以下を追加します。

app.post("/webhook", function(req, res) {
  res.send("HTTP POST request sent to the webhook URL!")
})

これは、/webhookエンドポイントにHTTP POSTリクエストが送られてきたときに、HTTP POST request sent to the webhook URL!というHTTPレスポンスを返すようにボットサーバに指示するものです。

ここまでで、index.jsは以下のようになっているはずです。

const https = require("https")
const express = require("express")
const app = express()
const PORT = process.env.PORT || 3000
const TOKEN = process.env.LINE_ACCESS_TOKEN

app.use(express.json())
app.use(express.urlencoded({
  extended: true
}))

app.get("/", (req, res) => {
  res.sendStatus(200)
})

app.post("/webhook", function(req, res) {
  res.send("HTTP POST request sent to the webhook URL!")
})

app.listen(PORT, () => {
  console.log(`Example app listening at http://localhost:${PORT}`)
})

それでは、エンドユーザーがメッセージを送信した際の返信を設定しましょう。

ユーザーからのメッセージに対して返信をするために、ユーザーからメッセージを受信したことを識別する必要があります。 ユーザーがボットにメッセージを送信すると、メッセージイベントオブジェクトがWebhook URLに送信されます。メッセージイベントオブジェクトにはtypeプロパティが含まれており、値は message に設定されています。このmessageを使って、受け取ったWebhookイベントオブジェクトが messageタイプであることを識別できます。

ユーザーに返信を送るには、応答メッセージを送るエンドポイント(https://api.line.me/v2/bot/message/reply)を使います。

index.jsapp.postに以下を追加しましょう。

app.post("/webhook", function(req, res) {
  res.send("HTTP POST request sent to the webhook URL!")
  // ユーザーがボットにメッセージを送った場合、返信メッセージを送る
  if (req.body.events[0].type === "message") {
    // 文字列化したメッセージデータ
    const dataString = JSON.stringify({
      replyToken: req.body.events[0].replyToken,
      messages: [
        {
          "type": "text",
          "text": "Hello, user"
        },
        {
          "type": "text",
          "text": "May I help you?"
        }
      ]
    })

    // リクエストヘッダー
    const headers = {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + TOKEN
    }

    // リクエストに渡すオプション
    const webhookOptions = {
      "hostname": "api.line.me",
      "path": "/v2/bot/message/reply",
      "method": "POST",
      "headers": headers,
      "body": dataString
    }

    // リクエストの定義
    const request = https.request(webhookOptions, (res) => {
      res.on("data", (d) => {
        process.stdout.write(d)
      })
    })

    // エラーをハンドル
    request.on("error", (err) => {
      console.error(err)
    })

    // データを送信
    request.write(dataString)
    request.end()
  }
})

このコードを読み解いてみましょう。

まず、APIサーバーに送信する返信トークンと返信メッセージデータをJSON形式で定義し、それをdataString変数で文字列化します。

headersは、リクエストヘッダーに必要なプロパティを指定します。

また、リクエストに渡すオプションをwebhookOptions変数で定義します。webhookOptionsは、Node.jsドキュメントのhttps.request (opens new window)メソッドで定義されている仕様に従ったオプションを指定します。エンドポイントのホスト名とパス、HTTPリクエストメソッド、headersとbodyを指定します。

const dataString = JSON.stringify({
  replyToken: req.body.events[0].replyToken,
  messages: [
    {
      "type": "text",
      "text": "Hello, user"
    },
    {
      "type": "text",
      "text": "May I help you?"
    }
  ]
})

const headers = {
  "Content-Type": "application/json",
  "Authorization": "Bearer " + TOKEN
}

const webhookOptions = {
  "hostname": "api.line.me",
  "path": "/v2/bot/message/reply",
  "method": "POST",
  "headers": headers,
  "body": dataString
}

messageタイプのHTTP POSTリクエストが/webhookエンドポイントに送信されると、返信を送信するためにhttps://api.line.me/v2/bot/message/replyエンドポイントにHTTP POSTリクエストを送信します。

request変数を定義して、リクエストを設定します。

const request = https.request(webhookOptions, (res) => {
  res.on("data", (d) => {
    process.stdout.write(d)
  })
}

request.onは、APIサーバーへのリクエスト送信時にエラーが発生した場合にコールバックされる関数です。

request.on("error", (err) => {
  console.error(err)
})

最後に、このコードが実行されると、定義したリクエストが送信されます。

request.write(dataString)
request.end()

最終的なコードは以下のようになります。

const https = require("https")
const express = require("express")
const app = express()
const PORT = process.env.PORT || 3000
const TOKEN = process.env.LINE_ACCESS_TOKEN

app.use(express.json())
app.use(express.urlencoded({
  extended: true
}))

app.get("/", (req, res) => {
  res.sendStatus(200)
})

app.post("/webhook", function(req, res) {
  res.send("HTTP POST request sent to the webhook URL!")
  // ユーザーがボットにメッセージを送った場合、返信メッセージを送る
  if (req.body.events[0].type === "message") {
    // 文字列化したメッセージデータ
    const dataString = JSON.stringify({
      replyToken: req.body.events[0].replyToken,
      messages: [
        {
          "type": "text",
          "text": "Hello, user"
        },
        {
          "type": "text",
          "text": "May I help you?"
        }
      ]
    })

    // リクエストヘッダー
    const headers = {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + TOKEN
    }

    // リクエストに渡すオプション
    const webhookOptions = {
      "hostname": "api.line.me",
      "path": "/v2/bot/message/reply",
      "method": "POST",
      "headers": headers,
      "body": dataString
    }

    // リクエストの定義
    const request = https.request(webhookOptions, (res) => {
      res.on("data", (d) => {
        process.stdout.write(d)
      })
    })

    // エラーをハンドル
    request.on("error", (err) => {
      console.error(err)
    })

    // データを送信
    request.write(dataString)
    request.end()
  }
})

app.listen(PORT, () => {
  console.log(`Example app listening at http://localhost:${PORT}`)
})
ボットを本番用として公開する場合は署名を検証してください

本番用として、不特定多数のユーザー向けにボットを公開する場合には署名の検証が必要です。HTTPリクエストがLINEプラットフォームから送られたことを確認するために、リクエストヘッダーのx-line-signatureに含まれる署名を検証してください。

署名の検証方法について詳しくは、『Messaging APIドキュメント』の「署名を検証する」を参照してください。

# Messaging APIチャネルを準備する

Messaging APIの機能を利用するには、Messaging APIチャネルを作成し、Webhook URLを登録する必要があります。

Messaging APIチャネルを作成するには、『Messaging APIドキュメント』の「LINE Developersコンソールでチャネルを作成する」の手順に従ってください。

作成したMessaging APIチャネルの[Messaging API設定]タブで、チャネルアクセストークンを発行します。

Messaging APIチャネルのチャネルアクセストークンセクションを示す画像

[Messaging API設定]タブで、[Webhook URL]に、「Herokuの設定」で取得したHerokuのURLをhttps://{Name of your app}.herokuapp.com/webhookのURL形式で記入します。Webhook URLhttps://{Name of your app}.herokuapp.com/ではないので注意してください。

HerokuのURLを忘れてしまったら

HerokuのURLを忘れてしまった場合は、Heroku Dashboard (opens new window)で確認できます。

[Webhookの利用]を有効にします。

Messaging API設定タブの「Webhookの利用」設定

[Messaging API設定]タブのQRコードを読み取って、ボットに紐付けられたLINE公式アカウントを友だちとして追加します。

[応答メッセージ]と[あいさつメッセージ]を無効にします。

これで、Messaging APIチャネルの準備が整いました。

# Herokuでアプリをデプロイする

グローバル設定」で、チャネルアクセストークンとして環境変数LINE_ACCESS_TOKENの値を使うように設定しました。Herokuにデプロイしたアプリを正常に動作させるために、環境変数LINE_ACCESS_TOKENを登録する必要があります。

ターミナルまたはコマンドラインツールで、「Messaging APIチャネルを準備する」で取得したチャネルアクセストークンを使って、以下を実行してください。

heroku config:set LINE_ACCESS_TOKEN={チャネルアクセストークンをここに入力してください}

これで、アプリをデプロイする準備が整いました。

ターミナルまたはコマンドラインツールで、以下のコードをHerokuにプッシュします。

git add .
git commit -m "First commit"
git push heroku master

# Webhook URLを検証する

Webhookが正常に動作しているか確認しましょう。

Messaging APIチャネルを準備する」で作成したチャネルの[Messaging API設定]タブをクリックします。

[Webhook URL]の[検証]をクリックします。

Webhook URLに問題がない場合、「成功」のメッセージが表示されます。問題があった場合、エラーメッセージが表示されますので、メッセージの内容に沿って対応してください。

「成功」のメッセージが表示されたらサンプルボットの完成です!

LINEでボットにメッセージを送ってみてください。このようなメッセージが届くはずです。

サンプルボットとの会話イメージ

# トラブルシューティング

ボットが正常に動作していない場合は、以下のコマンドを実行することでHerokuのログを確認できます。

heroku logs --tail

# 次のステップ

このボットには、さまざまな機能を追加できます。その例をいくつかご紹介します。

  1. リッチメニューを送信して、ユーザーにタップ可能なオプションを表示できます。

  2. ユーザーが特定のアクションを実行したときに送信されるアクションオブジェクトを使って、レスポンスを送信できます。

  3. ユーザープロフィールの取得で、カスタマイズしたメッセージを送信できます。

前述の通り、LINE Messaging API SDK for nodejs (opens new window)を使えば、より素早くボットを開発できます。こちらもぜひご検討ください。

# 関連ドキュメント