Twilio Functionsではcontext.getTwilioClient()は使わない

:::note alert
2023年5月1日を持ちまして、株式会社KDDIウェブコミュニケーションズのTwilioリセール事業が終了したため、本記事に記載されている内容は正確ではないことを予めご了承ください。
:::

# はじめに

みなさん、こんにちは。
KDDIウェブコミュニケーションズの Twilioエバンジェリストの高橋です。

今回は、Twilio Functions でよく使われる、`context.getTwilioClient()`はオススメしませんという記事です。

## getTwilioClientって何？

そもそも`context.getTwilioClient()`とはどのようなものかというと、[こちら](https://www.twilio.com/docs/runtime/functions/invocation#helper-methods)にドキュメントがありますが、Twilio Functions のヘルパーメソッドです。
通常、Twilio の RestAPI を呼び出すときなどは以下のようなコードを記述します。

```javascript:Node.jsの場合
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = require('twilio')(accountSid, authToken);

client.messages
      .create({body: 'こんにちは', from: '+150xxxxxxxxxx', to: '+8180xxxxxxxx'})
      .then(message => console.log(message.sid));
```
この例では、SMSを送信するための　RestAPI をコールしています。**AuthToken については、外部に漏れてはいけない情報のため、コード内に記載することはせず、環境変数を利用するのが一般的です。**
Twilio Functions を利用せずに外部のサーバー上で実行する場合などは、この方法が従来よく利用されていました。
しかし、RestAPI をコールするために外部サーバーを用意するのは面倒なので、これを Twilio 内で実行するためのサーバーレスプラットフォームが Twilio Functions です。
そして、Twilio Functions から同じ　RestAPI をコールする場合は、以下のように書き換えることができます。

```javascript:TwilioFunctionsの場合
const client = context.getTwilioClient();

client.messages
      .create({body: 'こんにちは', from: '+150xxxxxxxxxx', to: '+8180xxxxxxxx'})
      .then(message => console.log(message.sid));

```
この記法を使うと、Twilio Functions を実行するプロジェクト内の認証情報が自動的に適用されるため、AccountSid や AuthToken を意識しないで記述ができるのでとても便利です。

## サーバーレスCLI

Twilio には、CLI と呼ばれるコマンドインターフェースがあり、この中には前述の Twilio Functions をコマンドベースで操作することができるサーバーレスCLIも用意されています。サーバーレスCLIについては、以下の記事をどうぞ。
[Twilio CLI（サーバーレス開発編）](https://qiita.com/mobilebiz/items/fb4439bf162098e345ae)

CLIは頻繁にバージョンアップされており、例えばサーバーレスの初期セットアップは以下のコマンドで実行できます。

```sh
twilio serverless:init --template=blank test
```
これにより、以下のような`test`という名前のサーバーレス環境の雛形が完成します。

```sh
.
├── assets
├── functions
│   └── blank.js
├── node_modules [362 entries exceeds filelimit, not opening dir]
├── package-lock.json
├── package.json
└── readmes
    └── blank.md
```

そして同時に、以下のような`.env`ファイル（環境変数として利用）もできています。

```text
ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxx
AUTH_TOKEN=

# Variables for function ""
# ---
```

以前のサーバーレスCLIでは、`ACCOUNT_SID`には、CLIプロファイルを作成したときに自動的に生成されたAPI Keyが入り、`AUTH_TOKEN`には、API Secretが入っていました。
実態はAPI Keyなのに、`ACCOUNT_SID`という変数名はおかしいよなーとずっと思っていたのですが、CLIのバージョンアップ（多分、2.x以降？）にようやく改善され、上記の例のように`ACCOUNT_SID`には本当のAccountSidが入り、`AUTH_TOKEN`は空白の状態で生成されるようになりました。

## AUTH_TOKENは空白でいいのか

**結論から言うと大丈夫です。**空白のままでもデプロイはできますし、大きな問題はありません。
がしかし、**コード内で、`context.getTwilioClient()`を利用するときだけは注意が必要**です。

具体的には、サーバーにデプロイして実行する場合は問題ないのですが、ローカルで実行する場合はエラーが出ます。
例えば、以下のようなコードを書いたとします。

```javascript:アカウントのリストを取得するコード
exports.handler = function (context, event, callback) {
  const client = context.getTwilioClient();

  client.api.accounts
    .list({ limit: 20 })
    .then((accounts) => accounts.forEach((a) => console.log(a.sid)));

  callback(null, {});
};
```

実際にローカルで実行してみると、以下のようなエラーが出ます。

```
twilio serverless:start
┌──────────────────────────────────────────────┐
│                                              │
│   Twilio functions available:                │
│   └── /blank | http://localhost:3000/blank   │
│                                              │
│   Twilio assets available:                   │
│   ⚠ No assets found                          │
│                                              │
└──────────────────────────────────────────────┘

│ ERROR Missing Auth Token
│ 
│ You are missing a Twilio Auth Token. You can add one into your .env file:
│ 
│ AUTH_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

500 GET /blank │ Response Type text/html; charset=utf-8
```

これは、Auth Token がありませんよというエラーです。
では`.env`の`AUTH_TOKEN`を書かなくてはいけないかというと、もちろん書いても構わないのですがオススメしませんというのがこの記事の趣旨です（趣旨にたどり着くまでが長いｗ）。
ではどうしたらよいかというと、API KeyとAPI Secretを使ってください。

具体的には、`.env`は以下のように設定します。

```text
ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
AUTH_TOKEN=

# Variables for function ""
# ---
API_KEY=SKxxxxxxxxxxxxxxxxxxxxxxxxxxxx
API_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

`AUTH_TOKEN`は空白のままにし、代わりに`API_KEY`と`API_SECRET`を記載します。API KeyとAPI Secretのペアも外部に漏洩してはいけないものですが、Auth Tokenに比べると万が一の対応が軽減されます。
そして、コードは以下のように書き換えます。

```javascript
exports.handler = function (context, event, callback) {
  const client = require("twilio")(context.API_KEY, context.API_SECRET, {
    accountSid: context.ACCOUT_SID,
  });

  client.api.accounts
    .list({ limit: 20 })
    .then((accounts) => accounts.forEach((a) => console.log(a.sid)));

  callback(null, {});
};

```

2〜4行目の記述方法であれば、Auth Tokenを使わなくても良いため、より安全なコードになります。

# まとめ

`.env`には機密情報を記載するケースが多いのですが、ついうっかり外部に公開してしまう可能性も非常に高いファイルです。そのため、なるべく重要な情報は書かない方が理想的なので、今回のようなコーディングを心がけておくと良いかと思います。

---
### Twilio（トゥイリオ）とは

https://cloudapi.kddi-web.com
Twilio は音声通話、メッセージング（SMS /チャット）、ビデオなどの 様々なコミュニケーション手段をアプリケーションやビジネスへ容易に組み込むことのできるクラウド API サービスです。初期費用不要な従量課金制で、各種開発言語に対応しているため、多くのハッカソンイベントやスタートアップなどにも、ご利用いただいております。

自己紹介|　
:--|:--
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/b51a8b88-abd5-ce5e-195a-de3564ba2ae6.png" height='200' width='150'/>|高橋克己（Katsumi Takahashi） 自称「<font color='red'>赤い芸人</font>」<br />グローバル・インターネット・ジャパン株式会社　代表取締役<br />株式会社KDDIウェブコミュニケーションズ　Twilio事業部エバンジェリスト<br /><br />2001年より大手通信事業者の法人サービスの教育に携わり、企業における電話のしくみや重要性を研究。2016年よりTwilio事業部にジョインし、Twilioを使ったスマートコミュニケーションの普及活動を精力的に行っている。<br />2015 Hall of Doers<br />2019 Twilio Champions