Node.jsのアプリケーションからSORACOM APIを使ってグローバルSIMにSMSを送信する

# はじめに

開発中のアプリケーションから、日本向けのSORACOM SIMが刺さっているデバイスにAWSのSNSでSMSを送信して、デバイス側の制御を行なっていました。
この度グローバル向けのSIMに対してもSMSを送信しようとなったので、普段通りAWSからSMSを送信しました。
しかし、 `Message Invalid` というメッセージとともにエラーを吐いてきました。
「SORACOMのグローバルSIMってAPI以外は弾いてるんじゃね？」という意見が出てきたので、大人しくSORACOMのAPIでSMSを送信するようにしてみました。

## グローバルSIMにSMS機能が実装されていた

11月8日にグローバルSIM向けのSMS機能が実装され正式リリースされました。
APIからSMSを送信することができて、かつセキュアな機能となってます。
詳細は[こちら](https://blog.soracom.jp/blog/2017/11/08/sms-ga/)で確認できます。

## んじゃAPIを使おう

SMSを送信するAPIはこれです。

```
https://g.api.soracom.io/v1/subscribers/{imsi}/send_sms
```

このURLに対してPOSTします。
Headerには `APIキー` ・ `トークン` ・ `Content-type`
Bodyには下記のフォーマットでリクエスト送ります

```json
{
  "encodingType": 2,
  "payload": "string"
}
```

## Nodeからどうやってリクエストする？

Node.jsのrequestモジュールを使ってAPI叩くかと考えていたんですが、いかんせんSORACOMAPIのヘッダー周りを自前で実装するのはめんどくさいなーとなったので、npmで[soracom](https://www.npmjs.com/package/soracom)というモジュールをインストールしてヘッダー周りの生成を解決させようとしました。
そこでふと気づいたのが、「**これ2年以上メンテされてなくね？w**」
先に使っていた技術者から聞いたところによると、APIのエンドポイントが日本向けのURLにハードコーディングされているので、グローバル向けのAPIを実行することができません。
なので、Headerに必要な `APIキー` と `トークン` を生成するのに使います。

```js
const Soracom = require("soracom");

class SoracomClient {

  constructor() {
    this.soracom = new Soracom({
      authKeyId: "xxxxxxxxxx",  // 認証キー ID
      authKey: "xxxxxxxxxx"     // 認証キー シークレット
    });
  }

  // "/auth"に認証キーを送信して認証する
  // 認証が通ったらAPIキーとtokenが生成される
  authenticate() {
    return new Promise((resolve, reject) => {
      this.soracom.post("/auth", (err, res, auth) => {
        if (err) {
          return reject(err);
        } else {
          this.soracom.defaults(auth);
          return resolve();
        }
      });
    });
  }

  // SMSを送信する
  sendSMS() {
    return new Promise((resolve, reject) => {
      const options = {
        url: "https://g.api.soracom.io/v1/subscribers/{imsi}/send_sms",  //"{imsi}"=imsi番号
        method: "post",
        headers: this.soracom.defaultHeaders,
        qs: this.soracom.defaultParams
      }
      options.headers["Content-type"] = "application/json";
      const messageBody = {
        "encodingType": 1,
        "payload": "API send_sms message"
      }
      options.body = JSON.stringify(messageBody);
      request(options, function (err, response, body){
        if (err) {
          return reject(err);
        } else {
          return resolve(body);
        }
      });
    });
  }
}

module.exports = SoracomClient;
```

これで `sendSMS` を実行すればAPI経由でSMSを送信することができます。
あとはRouterから呼び出したりしてやれば良いのではないでしょうかね。
(下記は `./lib` ディレクトリに上記のjsファイルを `soracom_client.js` として用意している場合です。)

```js
const express = require("express");
const router = express.Router();
const co = require("co");
const SoracomClient = require("./lib/soracom_client");

router.post("/sendSMSMessage", (req, res) => {
  co(function *() {
    const soracom = new SoracomClient();
    yield soracom.authenticate();
    return yield soracom.sendSMS();
  }).then(() => {
    return res.send("Send SMS Success");
  }).catch((err) => {
    return res.send(err);
  });
});
```

例えばjsから `/sendSMSMessage` に対してPOSTでajaxを実行すれば、グローバルSIMが刺さっているデバイスに対してSMSを送信することができます。
ajaxのdataの中にimsiやメッセージ内容を入れて引数で渡していけば、SMSを送信するSIMやメッセージの内容を変えることができますね。

# さいごに

他にもSORACOMのAPIは豊富に用意されているので、様々な応用ができます。
弊社でもAPIを投げてSIMのステータスを操作してたりします。
いやーSORACOM便利っすね。

ではまた。