https://d226lax1qjow5r.cloudfront.net/blog/blogposts/checking-the-tube-status-with-nexmo-and-tfl-apis-dr/Elevate-Tube-Status.png

VonageのSMS APIでロンドンの地下鉄状況を確認する

最終更新日 April 30, 2021

所要時間:11 分

今日は、Vonageを使ってロンドン地下鉄のある路線の運行状況をチェックできるアプリケーションを作る。 SMS APIを使用します。.ロンドン交通局 (TFL API)を利用して、ユーザが選択した地下鉄路線の状況をリアルタイムで取得します。トリガーは、私たちのバーチャル番号へのインバウンドSMSになります。それは計画のように聞こえますか?では、このチュートリアルに従ってください。私たちは ウェブサイトを直接SMSで受け取ることができる。これは、Google Maps/Citymapperをチェックするためにインターネットにアクセスできない場合や、毎月のデータ使用量を超えてしまった場合に特に便利です。

アプリケーションのワークフローは以下の図のようになる:

sketch diagram of workflowsketch diagram of workflow

私は知っているᘌ あなたはロンドンに住んでいない可能性があり、このチュートリアルはあなたには関係ないと思うかもしれません。しかし、このチュートリアルはVonageの上に何が構築できるかを示す非常に分かりやすい例だと思います。

このチュートリアルでは、このアプリケーションをゼロから作成するためのすべての手順を説明します。しかし、完成した 完成したリポジトリを手に入れたい場合は、そちらをご覧ください!

前提条件

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.

チュートリアルの最初の部分で必要なもの:

  • Javascript/node.jsの基本的な知識。

  • を使用する必要があります。 ngrokを使ってローカルサーバーをインターネットに公開する必要があります。詳しくは 詳しいチュートリアルをご覧ください。

アプリケーションをHerokuにデプロイしたい場合は、以下も必要です:

  • A Herokuアカウント(Free-tierのみを使用します)。

  • 基本的な gitコマンドでアプリケーションを Heroku にデプロイします。

プロジェクトの設定

ローカルマシンにtubestatusというプロジェクトフォルダを作成し、そこに移動する。

mkdir tubestatus && cd tubestatus

コードを格納するメイン・ファイルを作りましょう。また .envファイルも作成します。ここにはVonageと認証情報、その他いくつかの変数を格納します。

touch server.js .env

次のステップは package.jsonファイルを作成することである。

npm init -y

必要な依存関係をインストールして保存しよう。

npm install --s express dotenv @vonage/server-sdk body-parser request

さて、Vonageアプリを作成し、番号を購入する必要がある。

このコマンドでVonage CLIをグローバルにインストールします:

npm install @vonage/cli -g

次に、Vonage API キーとシークレットを使って CLI を設定します。この情報は 開発者ダッシュボード.

vonage config:set --apiKey=VONAGE_API_KEY --apiSecret=VONAGE_API_SECRET

ローカル・サーバーがリッスンしているのと同じポート(私の場合は3000)でngrokを実行してみよう。

ngrok http 3000

ngrok

CLIを使ってVonageアプリケーションを作成し、ngrok URLへのウェブフックを作成する。

vonage apps:create ✔ Application Name … my_project ✔ Select App Capabilities › Messages ✔ Create messages webhooks? … yes ✔ Inbound Message Webhook - URL … http://3126bbcb.ngrok.io/inbound ✔ Inbound Message Webhook - Method › POST ✔ Status Webhook - URL … https://example.com/webhook_name ✔ Status Webhook - Method › POST ✔ Allow use of data for AI training? Read data collection disclosure - https://help.nexmo.com/hc/en-us/articles/4401914566036 … no Creating Application... done

の後にプリントアウトされるIDを保存しておきたい。 Application created:.すぐに必要になる。

電話を受けるには番号が必要です。以下のコマンドで番号を借りることができます(国番号をあなたのコードに置き換えてください)。例えば、あなたがアメリカにいる場合、次のように置き換えます。 GBUS:

vonage numbers:search US vonage numbers:buy [NUMBER] [COUNTRYCODE]

その番号をアプリにリンクさせる:

vonage apps:link --number=VONAGE_NUMBER APP_ID

最後に .envファイルに apiKeyVonageシークレット apiSecretそして先ほど購入した from.次に、TFL app_idapp_key.

apiKey = your_vonage_api_key apiSecret = your_vonage_api_secret from = your_vonage_number app_id = TFL_app_id app_key = TFL_app_key PORT = 3000

楽しいことから始めよう

いつものように、プロジェクトの最初にすべての依存関係を要求しよう。私たちは expressフレームワークを使います。環境変数を扱うために dotenvライブラリを使うことにします。環境変数を扱うために body-parserを使って、Vonage のサーバーから送られてくるリクエストを解析できるようにする。TFL APIへのAPIリクエストには requestライブラリを選んだ。 axios.最後に、そして最も重要なことですが、😊回線状況をユーザーに送り返すためにVonageライブラリが必要です。

新しく作成したファイルに以下のコードを貼り付けます。インストールされているすべての依存関係をインポートし、TFL APIが提供するすべての受け入れ可能な行名を含む変数を定義しています。ユーザーが有効な行名を提供しない場合、TFL APIにリクエストを送信したくありません(すべての値が大文字な理由は後で説明します)。statusと呼ばれる変数には、当該行のステータスに関連するあらゆるステータスが格納される。また、VonageとTFLのAPIを利用するために必要な認証情報をそれぞれ追加します。これらは .envファイルから取得します:

const Vonage = require('@vonage/server-sdk')
const express = require('express');
const bodyParser = require('body-parser');
const port = process.env.PORT || 3000;
const request = require('request');
const dotenv = require('dotenv');

let status = []

dotenv.config();

const lines =['CENTRAL','BAKERLOO', 'DISTRICT', 'VICTORIA', 'NORTHERN', 'CIRCULAR', 'HAMMERSMITH-CITY', 'JUBILEE', 'METROPOLITAN', 'PICCADILLY', 'WATERLOO-CITY' ];

const vonage = new Vonage({
  apiKey: process.env.apiKey,
  apiSecret: process.env.apiSecret
})

以下の行では、アプリケーションを開始し、基本的なミドルウェアを定義している。サーバがリッスンするポートとして3000を定義していますが、他のポートを選択することもできます。コメントアウトされた部分には、リクエストの受信経路が記述されます:

const app = express();

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

//We will define our route here

app.listen(port, ()=>{console.log('App listening in port ', port)});

コードを少し整理するために、2つの関数を定義してみよう。最初の関数 sendSms()は2つのパラメータを受け取ります:ユーザーの電話番号と、ユーザーに送り返すテキストです。少しコードを再利用します。

function sendMessage(to, message){
  vonage.message.sendSms(process.env.from, to, message, (err, responseData) => {
    if (err) {
        console.log(err);
    } else {
        if(responseData.messages[0]['status'] === "0") {
            console.log("Message sent successfully.");
        } else {
            console.log(`Message failed with error: ${responseData.messages[0]['error-text']}`);
        }
    }
})
}

つ目の関数 checkLineStatus()は2つのパラメータを受け取ります:ライン名とユーザーの電話番号です。

function checkLineStatus(Line, number) {

    var options = {
        json: true,
        url: 'https://api.tfl.gov.uk/Line/' + Line + '/status?app_id=' + app_id + '&app_key=' + app_key,
    }

    request(options, function (err, res, body) {
        if (err) {
            console.log(err)

        }
        else {
            if (body[0].lineStatuses[0].statusSeverityDescription === 'Good Service') {
                sendMessage(number, 'There is a ' + body[0].lineStatuses[0].statusSeverityDescription + ' operating on ' + body[0].name + ' line')

            }
            else {
                for (let i = 0; i < body.length; i++) {
                    for (let j = 0; j < body[i].lineStatuses.length; j++) {
                        status.push(body[i].lineStatuses[j].reason)
                    }
                }
                sendMessage(number, status)
                console.log(status)
            }
        }
    })
}

指定された回線のステータスがGood Serviceの場合(TFL APIは正常なサービスが実行されている場合、常にこのステータスを返すことに注意)、これをユーザーに送り返す。そうでない場合は、回線障害が発生したときに TFL API がそのようなメッセージを返すことを考慮に入れておく必要がある。 reasonオブジェクト内に lineStatusオブジェクトを生成します。これが、不通が発生するたびに配列にプッシュされるものだ(通勤客のために、不通がないことを祈る😂)。この関数の中で、路線の状態を返すために sendSms()関数を呼び出していることも忘れないでください。

最後に、ユーザーからの着信メッセージを聞くために、着信ルートを記入します。Vonageからの着信メッセージがどのようなものか見てみよう。

{ "msisdn": "447700900001", "to": "447700900000", "messageId": "0A0000000123ABCD1", "text": "Hello world", "type": "text", "keyword": "Hello", "message-timestamp": "2020-01-01T12:00:00.000+00:00", "timestamp": "1578787200", "nonce": "aaaaaaaa-bbbb-cccc-dddd-0123456789ab", "concat": "true", "concat-ref": "1", "concat-total": "3", "concat-part": "2", "data": "abc123", "udh": "abc123" }

私たちの目標を達成するために、上記のパラメーターのうち2つを保存する必要があります。ユーザーによって送信されたテキスト(行名)とユーザーの番号です。これらは新しい変数 (Tube_lineNumber_msisdnに格納されます。 /inboundに格納されます。

チューブ行を大文字にしていることは重要である。その理由は、大文字と小文字の区別を無視して、指定した文字列と別の文字列を比較したいからである。 中央, CENTRALまたは セントラル).ユーザーからの入力を大文字にし、配列(すでに大文字になっている)と比較することで、この問題を回避することができます。 lines配列(すでに大文字)と比較することで、これを回避できます。ルート用に確保したスペースに以下のコードを追加します。

app.post('/inbound', (req, res) => {
    let Tube_Line = req.body.text.toUpperCase()
    let Number_msisdn = req.body.msisdn

    if ((lines.indexOf(Tube_Line) > -1)) {
        checkLineStatus(Tube_Line, Number_msisdn)
    }
    else {
        sendMessage(Number_msisdn, 'Valid values are ' + lines)

    }

    res.status(204).send()
})

この (lines.indexOf(Tube_Line) &gt; -1)ビットに格納された値が Tube_lineに格納されている値が lines配列のいずれかの値と一致するかどうかを調べることができます。このメソッドは、指定された項目が配列内で見つかる最初のインデックスを返し、配列内に存在しない場合は -1 を返します。入力が有効な値のいずれかにマッチした場合にのみ、指定した行のステータスをチェックしたい。そうでなければ、TFL APIから美しいHTTP 404が返ってくる。ユーザーに間違った値を入力したことを知らせるのに十分優しいと仮定して、有効な値を提供するメッセージを送り返す。これは、上で説明したように、indexOfメソッドが-1に等しい場合に行われます。

よし、これを試す時が来た🙈。携帯電話を持って、配列にマッチする回線名でSMSを送ろう。 linesVonageの番号にSMSを送ろう。例として、毎日仕事に行くための回線名を問い合わせてみる。

demo of app performance on phonedemo of app performance on phone

💃💃 おわかりのように、先に設定したバーチャル番号にメッセージを送信した直後に、リクエストした回線のステータスを示す SMS を受信しています。よくやった、そしてそこまでフォローしてくれてありがとう!

インバウンドメッセージのモッキング

何らかの理由で携帯電話を使用する機会がない場合や、アプリケーションをテストするために手動で SMS を送信したくない場合にも対応できます。受信メッセージは、ウェブフックへの GET または POST リクエストとして表されます。Vonageがインバウンドメッセージを配信するためにどのメソッドを使用するかは、あなたの Vonageダッシュボード設定.このチュートリアルでは POST を使用します。

このことを考慮して、ngrokで公開されているローカルサーバーを手動で叩くことで、インバウンドメッセージの動作をシミュレートし、アプリケーションがその通りに動作するかどうかを確認することができる。ここでは POSTMANを使いますが、他のどのサービスを使ってもかまいません。一般的な生のJSONボディ(Vonageがインバウンドメッセージのために送信するもの)を定義して、インバウンドウェブフックにPOSTリクエストを行います。ただし msisdnを変更することを忘れないでください。また textパラメータを置き換えて、異なる行名の値で遊んでみてください。意図的に無効な値を入力して、許可された値を含むメッセージを受け取ることができます。私のAPIリクエストはこんな感じだ:

この場合 toパラメータは関係ないので、ランダムな値に設定した。重要なのは Content-Typeヘッダを追加し、それを application/jsonに設定することが重要です。右下を見てわかるように、アプリケーションはres.status(204)を使って /inboundルートで定義したHTTP 204をres.status(204).send()で返しています。

次は?Herokuにデプロイしよう

Herokuは、Webアプリケーションを簡単にデプロイし、ニーズに応じてサービスを拡張することを目的としたプラットフォームだ。また、日々のタスクを簡素化する便利なアドオンも提供している。Herokuは非常に使いやすく、ドキュメントも充実している。 Herokuサイト.Herokuを利用することで、サーバーのレンタルや設定の手間を省くことができる。

コンセプト ダイノという概念がHerokuのプラットフォームには存在する。これはアプリケーションがデプロイされるコンテナに他ならない。アプリケーションの使用はダイノ時間を消費するが(実行中のみ)、彼らはすぐに月550時間を無料で提供するか、クレジットカードを提供することによってあなたのアカウントを確認することに同意した場合には1000時間を提供するので心配しないでください。トラフィック需要を考慮して、アプリケーションを簡単にスケールアップまたはスケールダウンすることができますが、これはこのチュートリアルの範囲外です。

もしあなたがHerokuアプリケーションをデプロイしたことがないのであれば、Herokuのドキュメントに目を通す価値があるかもしれない。 node.jsアプリケーションのデプロイ方法.アプリの起動方法を決定するために、Herokuは最初に procfile.これは、起動時にアプリが実行するコマンドを指定するファイルです。もし Procfileが存在しない場合、Herokuはpackage.json内のスタートスクリプトを介してデフォルトのWebプロセスを開始しようとします。

を編集しましょう。 package.jsonを編集して スクリプトプロパティを含む部分にこのビットが含まれるようにしましょう:

"scripts": {
    "start": "node server.js"
  },

次に .gitignoreファイルを作成し、ローカルの環境変数やビルド関連の出力、モジュールが git リポジトリにコミットされないようにします。

/node_modules
npm-debug.log
.DS_Store
/*.env

フリー・ティアを使用する唯一の欠点は、アプリケーションが 30 分間使用されないとアイドル状態になり、(新しいリクエストを受信する際に) アプリケーションが目覚めるまで少し時間がかかることです。現実的には、アプリケーションがしばらく非アクティブだった場合、Vonageからのメッセージを受信する際に若干の遅延が発生する可能性があることを意味します。これは、TFL APIへのリクエストが、アプリケーションの再起動後に処理されるためです。このアプリケーションはタイムクリティカルではないので、これは許容範囲です。しかし、これで十分でないと思われる場合は、有料サービスに移行して、アプリケーション専用のダイノを実行させることができます。

アプリの起動方法を決定するために、HerokuはまずProcfileを探します。Node.jsアプリ用のProcfileが存在しない場合、Herokuはpackage.json内の開始スクリプトを介してデフォルトのWebプロセスを開始しようとします。Webプロセスタイプのコマンドは、PORT環境変数で指定されたポート番号にバインドする必要があります。そうでない場合、dynoは起動しません。

があることを再確認してください。 Heroku CLIがインストールされていることを再確認し、プロジェクトフォルダ内で以下のコマンドを1つずつ実行してください:

git init git add . git commit -m "First commit."

この時点で、新しい git リポジトリを作成し、すべての変更をリポジトリに追加して最初のコミットを送信しました。それではアプリケーションを作成し、Heroku にデプロイしてみましょう:

heroku create tubestatus git push heroku master

この数行でHerokuアプリを作成し、変更をHerokuにプッシュした。すべてが期待通りに進んでいれば、自分のアプリケーションが作成されているはずだ。デプロイされると、アプリが見つかるURLも提供されます。よくやった!

最後に、環境変数を提供しなかったので、アプリが環境変数を見つける場所を教えなければならない。 .env file.以下のコマンドを実行して、必要な設定変数を設定する。

heroku config:set apiKey=xxxxx heroku config:set apiSecret=xxxxxx heroku config:set app_key=xxxxxxxxxxxxxxxxxx heroku config:set app_id=xxxxxxx heroku config:set from=xxxxxxxxxxx

これらの変数が正しく追加されているかどうかは、アプリケーションの設定を以下のように見て再確認できます。 Herokuダッシュボード.これは、Herokuダッシュボードで私たちのアプリケーションがどのように見えるかです。もし 設定変数を表示をクリックすると、Heroku CLIで設定した環境変数が表示されます。

結論から言うと、このプロセスは比較的簡単だった!私は数分でこれを立ち上げ、実行することができました。あとは、新しいWebhookを指すように電話番号を更新するだけで、上記の手順(Numbers API経由で電話番号を設定した場合)を再現できます。注意点として、URLの末尾に /inboundをスクリプトのルートと一致するURLの最後に含めることを忘れないでください。

うまくいけば、私たちの番号のInbound Webhook URLを更新したら、SMSを送信すれば、期待通りに機能する。これが不通のステータスだ。私がこれをテストしていた時点で、ディストリクト・ラインを使ってヒースロー空港に移動していた場合、旅のスケジュールを変更する必要があったようだ。

SMS View of final working app

今日のところは以上ですが、もしあなたが私たちのAPIで遊び続けたいのであれば、以下のリンクが役に立つかもしれません:

シェア:

https://a.storyblok.com/f/270183/384x384/6007824739/javier-molina-sanz.png
Javier Molina Sanz

Javier studied Industrial Engineering back in Madrid where he's from. He is now one of our Solution Engineers, so if you get into trouble using our APIs he may be the one that gives you a hand. Out of work he loves playing football and travelling as much as he can.