Azure の Functions Bot を TypeScript で作る(+ VSCodeでデバッグする)

Bot Application が Azure Functions で作れるようになっていました。

image.png

Node.js か C# のいくつかのテンプレートから選択できます。

Node.js → Basic を選択して作った Functions は JavaScript なので、これを TypeScript に変えてみます。

Node.js のサンプルをダウンロードする

Bot を作成したあと、ビルド → zip ファイルをダウンロード でソースコード一式がダウンロードできます。

そのディレクトリ構成は次の図に。

image.png

TypeScript に書き換える

/messages ディレクトリが Function のソースなので、ターミナルでここに移動し、

tsc init

を実行します。すると tsconfig.json が作成されるので、それを次のように書き換えます。

messages/tsconfig.json

{
  "compilerOptions": {
    "target": "es2015",
    "module": "commonjs",
    "sourceMap": true,
    "strict": false,
    "esModuleInterop": true
  }
}

コメント行や説明のコメントは省略しています。既定値から変えたのは次の通り。

  • "target": "es2015" - Azure Functions の実行環境は node.js v8.4.0 以上を推奨 とのことで、node v8.2.0 は ES2016 までの API をすべてサポートしています
  • "sourceMap": true - ソースマップを有効にし、ローカルでの TypeScript デバッグを可能にします。
  • "strict": false - とりあえず厳密な型チェックはOFFで

次に TypeScript で必要なモジュールをインストールします。

ターミナルで messages ディレクトリに移動し、

npm install @types/node --save-dev

を実行します。実行後、 package.json@types/node が追加されます。

messages/package.json

{
  "name": "emptybot",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "botbuilder": "^3.13.1",
    "botbuilder-azure": "^3.0.4"
  },
  "devDependencies": {
    "@types/node": "^10.5.1",   <-- ここが追加された
    "restify": "^5.0.0"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

次に index.js をリネームし index.ts とし、内容を次のように書き換えます。

messages/index.ts

import { ChatConnector, MemoryBotStorage, UniversalBot, Session } from 'botbuilder';
import { BotServiceConnector, AzureTableClient, AzureBotStorage } from 'botbuilder-azure';
import * as path from 'path';

const useEmulator = (process.env.NODE_ENV == 'development');

const connector = useEmulator ? new ChatConnector() : new BotServiceConnector({
    appId: process.env['MicrosoftAppId'],
    appPassword: process.env['MicrosoftAppPassword'],
    openIdMetadata: process.env['BotOpenIdMetadata']
});

/*----------------------------------------------------------------------------------------
* Bot Storage: This is a great spot to register the private state storage for your bot. 
* We provide adapters for Azure Table, CosmosDb, SQL Azure, or you can implement your own!
* For samples and documentation, see: https://github.com/Microsoft/BotBuilder-Azure
* ---------------------------------------------------------------------------------------- */

const tableName = 'botdata';
const azureTableClient = new AzureTableClient(tableName, process.env['AzureWebJobsStorage']);
const storage = useEmulator ? new MemoryBotStorage() : new AzureBotStorage({ gzipData: false }, azureTableClient);

const bot = new UniversalBot(connector);
bot.localePath(path.join(__dirname, './locale'));
bot.set('storage', storage);

bot.dialog('/', function (session: Session) {
    session.send('あなたは ' + session.message.text + 'と言いましたね。');
});

if (useEmulator) {
    const restify = require('restify');
    const server = restify.createServer();
    server.listen(3978, function() {
        console.log('test bot endpont at http://localhost:3978/api/messages');
    });
    server.post('/api/messages', connector.listen());    
} else {
    module.exports = connector.listen();
}

処理内容はほぼ変えず、文法を TypeScript にしただけです(MemoryBotStorage を使うとこだけ処理を追加してます、これをしないとローカルで動かなかったので)。

messages ディレクトリで

tsc

を実行します。すると同じディレクトリに index.jsindex.js.mmap が生成されます。

この index.js をこれまでの index.js の代わりに Azure にアップロードすれば、関数はいままでどおり動作します。

ローカルでデバッグする(VSCode使用)

launch.json の定義が古いのでちょっと追記します。

messages/.vscode/launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch",
            "type": "node",
            "request": "launch",
            "protocol": "inspector",  <-- この行を追加
            "program": "${workspaceRoot}/index.js",
            "cwd": "${workspaceRoot}",
            "env": {
                "NODE_ENV": "development"
            }
        }
    ]
}

index.ts(.js じゃないよ) の適当な行にブレークポイントを仕掛けて、メニュー -> デバッグ -> デバッグの開始 をします。

image.png

ちゃんと止まるはずです。

BotFramework-Emulator にローカルのエンドポイントである http://localhost:3978/api/messages を指定すれば、ボットのデバッグができます。

image.png

環境

  • macOS - 10.13.5
  • Node.js - v8.9.4
  • npm - 5.6.0
  • TypeScript - 2.9.2
  • Visual Studio Code(VSCode) - 1.24.1
  • BotFramework-Emulator - 3.5.36

参考