【Node.js】AWS SNSを使ってSMS(ショートメッセージ)を送る【Typescript】



ここでいうSNSは、Twitterみたいなソーシャルネットワーキングサービス・・・ではなく、
AWSの **SimpleNotificationService** のことです。
SNSでSMSを送る(噛みそう)機能を触ったので、設定方法などを記録します。


## IAMユーザの追加
まずはユーザを作成。
SNSのフルアクセス権限を付与します。


### ユーザー詳細の設定

このページの右上にある「ユーザを追加」ボタンを押下
https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/users



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284077/ff0e1717-5812-a4e0-e92c-85895c754cdf.png)


- ユーザ名: 適当なユーザ名
- SWS認証情報タイプ: アクセスキー -プログラムによるアクセス


ユーザ名は会社のルールに則るのがいいと思います。
うちでは プロジェクト名_環境名にしています。

例: `my_web_project_staging`



### アクセス許可の設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284077/b76f3900-3f77-ec73-e483-5b7f93c8c355.png)


- 既存のポリシーを直接アタッチ選択
- AmazonSNSFullAccess✅


### タグの追加 (オプション)
なし


### 確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284077/600ba75c-fcae-6324-0b6b-2235013ca059.png)


これで「ユーザの登録」ボタンを押せば設定完了です。


## アクセスキーIDとシークレットアクセスキーをメモしておく

登録ボタン押下後、**アクセスキーID**と**シークレットアクセスキー**が表示されます
例えばNode.jsでSNSを使う場合は、この2つのキーを.envファイルなどに記載することでプロジェクトからSNSを実行することが可能になります。

<font color="MediumVioletRed">**このキーを公開すると悪用されてしまう恐れがあるので取扱注意です。**</font>

## Node.jsから扱う

Node.jsから動かせるようにする設定例です。


### パッケージのインストール

aws-sdkをインストールします
```
npm i aws-sdk
```

### ディレクトリ構成
```
- .env
- aws
  - config.ts
  - sns_client.ts
```

### .env
- .envファイルに先ほど取得したアクセスキーIDとシークレットアクセスキーを記載します

```
AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXXX
AWS_SECRET_ACCESS_KEY=xxxxxxxxX/XxxXxxxxxX+XXxxxXX/XxXXX
AWS_DEFAULT_REGION=ap-northeast-1
```

### aws/config.ts

aws-sdkの初期処理をします。

```js
import aws from 'aws-sdk'

const credential =
  process.env.NODE_ENV === 'local'
    ? new aws.SharedIniFileCredentials()
    : new aws.Credentials({
        accessKeyId: process.env.AWS_ACCESS_KEY_ID as string,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY as string,
      })
console.log('[debug] AWS credential: ', credential)
aws.config.credentials = credential
aws.config.region = process.env.AWS_DEFAULT_REGION
export default aws

```

- NODE_ENVが `local` の場合は、 `aws.SharedIniFileCredentials()`で初期化します。
これは自分の端末の `~/.aws/credentials` に書いてあるアクセスキーIDとシークレットアクセスキーを参照してくれます。

- NODE_ENVが `development` の場合は、 `aws.Credentials()`で初期化します。
ローカル開発以外の場合(開発環境や検証環境で動く場合)は、.envに書いたアクセスキーIDとシークレットアクセスキーを設定します。

- `export default aws`と書くことで、このクレデンシャルが設定されたawsを別ファイルから呼び出せるようにしています。


### aws/sns_client.ts

実際にSNS送信するコードはこちらです。
(Typescriptを使っています)

```typescript
import aws from './config'

export class SnsClient {
  public publish(message: string, phone: string) {
    const params = {
      Message: message,
      PhoneNumber: phone,
    }
    const publishTextPromise = new aws.SNS({ apiVersion: '2010-03-31' }).publish(params).promise()

    publishTextPromise
      .then(function (data) {
        console.log(`Message ${params.Message} sent to the topic ${params.PhoneNumber}`)
        console.log('MessageID is ' + data.MessageId)
        console.log(data)
        return data?.MessageId
      })
      .catch(function (err) {
        console.error(err, err.stack)
      })
    return true
  }
}
```

[AWS公式のサンプル](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javascript/example_code/sns/sns_publishtotopic.js)を元に書いています。
結構シンプルです。

- `import aws from '../config'` で、先ほど初期設定したawsファイルを読み込んでいます。

- `public publish(message: string, phone: string)` でメッセージを電話番号を引数にした関数を定義しています。

- `new aws.SNS({ apiVersion: '2010-03-31' }).publish(params).promise()`でSMS送信promiseを用意し、実行しています。

## 実行結果


成功すれば以下のメッセージが出ます。
```
Message メッセージ内容 sent to　the topic 080XXXXXXXX
MessageID is XxXXX000X-x0xxx-00XX-x0xx-x0000000xxx00x
```

権限がちゃんと設定されていないと以下のエラーが出ます。

```
User: arn:aws:iam::1234567890:user/xxx_xxx is not authorized to perform: SNS:Publish on resource: 080XXXXXXXX because no identity-based policy allows the SNS:Publish action
```

以上です。
MessageIDやRequestIDはメッセージの配信ログを見るために使うと思われます。
機会があれば試してみようかな。