https://d226lax1qjow5r.cloudfront.net/blog/blogposts/build-a-serverless-eurovision-voting-system-with-node-js-and-vonage/Blog_Eurovision-Voting_1200x600.png

Node.jsとVonageでサーバーレスのユーロビジョン投票システムを構築する

最終更新日 May 4, 2021

所要時間:1 分

ユーロビジョンは、私が1年で最も好きなイベントのひとつだ。知らない人のために説明しておくと、ユーロビジョンは歌のコンペティションである。 奇妙な, 素晴らしいそして 奇抜が同居している。参加国はそれぞれ1つの演技を提出し、オリジナル曲を披露する。 馬鹿馬鹿しくそして 素晴らしい.さあ さあ a もう少し もっと リンク.

決勝に進出した国々は、参加国の人々がお気に入りの演技(自国の演技を除く)に投票する前にライブパフォーマンスを行う。各国からの投票が集計され、その結果、それぞれ58ポイントが与えられる:近年は、プロの審査員が各国の票の半分を占めるようになっているが、この企画のために、審査員の存在は忘れておこう。

2019 Eurovision Leaderboard2019 Eurovision Leaderboard

私はユーロビジョンの大ファンで、番号の出所を検証するためにVonage Number Insights APIを使って完全に機能する投票システムを構築するのは楽しいプロジェクトだと思った。

私たちはまず、すべての参加国のデータベースを構築します。このデータセットは、ファイナリストが誰であるかも強調します(2019年の出場者を使用)。次に、SMS経由で入ってくる投票を処理し、有効であれば投票を保存し、Vonage Messages APIを使って返信します。 Vonage Messages APIを使って返信します。.最後に、更新されるリーダーボードで国ごとの結果を得ることができるフロントエンドを構築する。プロジェクト全体はNetlifyでホストされ、Vue.jsが最小限のフロントエンドに使われます。

完成したコードをご覧になりたい場合は、以下をご覧ください。 https://github.com/nexmo-community/eurovision-voting-system-js.

準備はいいか?行こう

前提条件

これを機能させるには、いくつかのアカウントが必要だ。まだの方は、アカウントを取得してください:

ターミナルを開き、このプロジェクト用に新しい空のディレクトリを作成し、次のように入力して新しいプロジェクトを初期化する。 npm init -y.完了したら npm install dotenv encoding mongodb netlify-lambda nexmo@beta.

Nexmo CLIも必要です。以下を実行してください。 npm install -g nexmo-cli@betaを実行してインストールし、オンラインでアカウントにアクセスしてAPIキー/シークレットを取得します。 nexmo setup <api_key> <api_secret>.

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.

MongoDBデータベースのセットアップ

MongoDB Atlas でホスティングされた MongoDB インスタンスを使います。Mongo DB Atlas のアカウントにログインして、好きな名前で新しいプロジェクトを作成します。新しいクラスタを作成します。 Eurovision-で、変更がデプロイされるのを待ちます。

をクリックします。 接続ボタンをクリックして現在の IP アドレスを追加し、このデータベースにアクセスできる新しい MongoDB ユーザーを作成します (パスワードに注意しましょう)。

次のペインでは、データベースへの接続方法がいくつか表示されます。を選択します。 アプリケーションに接続するを選択し、URIをクリップボードにコピーします。

.envファイルの作成

先に進む前に、プロジェクト・ディレクトリに .envファイルを作成しなければならない。ファイルの内容は以下のようにする:

DB_URL=<Mongo DB URI>

<password>をMongoDBユーザーのパスワードに、そして <dbname>eurovision.

コレクションの作成

をクリックしてください。 コレクションボタンをクリックし 自分のデータを追加をクリックして新しいコレクションを作成します。2つ作成します:

  1. データベース名 eurovisionコレクション名: countries

  2. データベース名 eurovisionコレクション名: votes

どこからでもアクセスできるようにする

このリストに自分のIPアドレスを追加し、ローカル・アプリケーションからこのデータベースにアクセスできるようにしました。しかし、後でこのプロジェクトをデプロイするときには、静的IPアドレスにアクセスすることはできません。をクリックしてください。 ネットワーク・アクセスをクリックし、次に IPアドレスの追加をクリックし、最後に どこからでもアクセスを許可する.変更を確認し、制限を解除します。

国別人口

2019年には42のユーロビジョン・エントリーがあり、そのうち26が決勝に進出した。このデータを入力するのは一度だけなので、このデータ入力を自動化するスクリプトを書いた。というフォルダを作成する。 boilerplateというフォルダを作成し、その中に addCountries.js.その中に以下のコードを記述する:

// Load environment variables
require('dotenv').config()
 // Initialize MongoClient
const { MongoClient } = require('mongodb')
const mongo = new MongoClient(process.env.DB_URL, { useUnifiedTopology: true })
 const countriesList = [
  { "iso": "ALB", "name": "Albania", "final": true },
  { "iso": "ARM", "name": "Armenia", "final": false },
  { "iso": "AUS", "name": "Australia", "final": true },
  { "iso": "AUT", "name": "Austria", "final": false },
  { "iso": "AZE", "name": "Azerbaijan", "final": true },
  { "iso": "BLR", "name": "Belarus", "final": true },
  { "iso": "BEL", "name": "Belgium", "final": false },
  { "iso": "HRV", "name": "Croatia", "final": false },
  { "iso": "CYP", "name": "Cyprus", "final": true },
  { "iso": "CZE", "name": "Czech Republic", "final": true },
  { "iso": "DNK", "name": "Denmark", "final": true },
  { "iso": "EST", "name": "Estonia", "final": true },
  { "iso": "FIN", "name": "Finland", "final": false },
  { "iso": "FRA", "name": "France", "final": true },
  { "iso": "DEU", "name": "Germany", "final": true },
  { "iso": "GEO", "name": "Georgia", "final": false },
  { "iso": "GRC", "name": "Greece", "final": true },
  { "iso": "HUN", "name": "Hungary", "final": false },
  { "iso": "ISL", "name": "Iceland", "final": true },
  { "iso": "IRL", "name": "Ireland", "final": false },
  { "iso": "ISR", "name": "Israel", "final": true },
  { "iso": "ITA", "name": "Italy", "final": true },
  { "iso": "LVA", "name": "Latvia", "final": false },
  { "iso": "LTU", "name": "Lithuania", "final": false },
  { "iso": "MKD", "name": "North Macedonia", "final": true },
  { "iso": "MLT", "name": "Malta", "final": true },
  { "iso": "MDA", "name": "Moldova", "final": false },
  { "iso": "MNE", "name": "Montenegro", "final": false },
  { "iso": "NLD", "name": "Netherlands", "final": true },
  { "iso": "NOR", "name": "Norway", "final": true },
  { "iso": "POL", "name": "Poland", "final": false },
  { "iso": "PRT", "name": "Portugal", "final": false },
  { "iso": "ROU", "name": "Romania", "final": false },
  { "iso": "RUS", "name": "Russia", "final": true },
  { "iso": "SMR", "name": "San Marino", "final": true },
  { "iso": "SRB", "name": "Serbia", "final": true },
  { "iso": "SVN", "name": "Slovenia", "final": true },
  { "iso": "ESP", "name": "Spain", "final": true },
  { "iso": "SWE", "name": "Sweden", "final": true },
  { "iso": "CHE", "name": "Switzerland", "final": true },
  { "iso": "UKR", "name": "Ukraine", "final": false },
  { "iso": "GBR", "name": "United Kingdom", "final": true }
]
 // Connect to database, and insert all items in the countryList in the countries collection
mongo.connect().then(async () => {
  try {
    const countries = await mongo.db('eurovision').collection('countries')
    const result = await countries.insertMany(countriesList)
    console.log(`Added ${result.insertedCount} documents to the collection`)
    mongo.close()
  } catch(e) {
    console.error(e)
  }
})

ファイルを保存し、ターミナルを開いて以下を実行する。 node boilerplate/addCountries.js.完了したら、MongoDB Atlasでコレクションを確認すると、countriesコレクションに42のドキュメントがあるはずです。

Country entries populated in AtlasCountry entries populated in Atlas

Netlify機能を設定する

Vonage API統合のために作成する必要があるエンドポイントは2つある。ひとつはステータス・エンドポイントで、このアプリケーションではロジックは必要ないが、HTTP 200 ステータスを返す必要がある。これらのエンドポイントをビルドしてホストするには、Netlify Functions を使います。その前に、いくつかセットアップが必要です。

あなたの package.jsonファイルの scriptsセクションを次のように書き換えてください:

"scripts": {
  "netlify:serve": "netlify-lambda serve functions/src",
  "netlify:build": "netlify-lambda build functions/src"
},

プロジェクトのルート・ディレクトリに netlify.tomlファイルを作成し、以下のコードを書く:

[build]
  functions = "./functions/build"

最後に、プロジェクト内に functionsディレクトリを作成し、その中に srcディレクトリを作成します。Netlify 関数はすべてこのディレクトリに作られます。

新しい functions/srcディレクトリに status.jsファイルを作成する。その中に関数を作成する:

const headers = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'Content-Type'
}
 exports.handler = async (event, context) => {
  try {
    return { headers, statusCode: 200, body: 'ok' }
  } catch(e) {
    console.error('Error', e)
    return { headers, statusCode: 500, body: 'Error: ' + e }
  }
}

ターミナルで npm run netlify:serve.別のターミナルで、以下を実行して新しいエンドポイントを試す。 curl http://localhost:9000/status.ターミナルには ok.

着信メッセージの受信

また、ロング・バーチャル・ナンバー(LVN)がメッセージを送信されたときにデータを受信するエンドポイントも必要です。の内容をコピーして status.jsという名前の新しいファイルに inbound.js.

インバウンド・エンドポイントの作成

ファイルの先頭で、querystringパッケージ(Node.jsに組み込まれている)をrequireする:

const qs = require('querystring');

ブロックの先頭に tryブロックの先頭に、以下のコードを追加する:

const { msisdn, to: lvn, text } = qs.parse(event.body)
const vote = text.toUpperCase().trim()
console.log(vote)

netlify-lambdaサーバーを再起動し、新しいターミナルを開いて、以下を実行してください。 npx ngrok http 9000を実行して、テスト用の一般にアクセス可能なバージョンの netlify-lambda サーバを作成してください。一時的な ngrok URL に注意してください。

Vonage APIアプリケーションのセットアップ

プロジェクト・ディレクトリで nexmo app:create:

  • アプリケーション名:何でも

  • 機能の選択:メッセージ

  • メッセージの受信URL: <ngrok_url>/inbound

  • メッセージ ステータス URL: <ngrok_url>/status

  • 公立/私立:空欄のまま

この操作により .nexmo-appファイルを作成する。後でこのファイルを使いますが、秘密鍵が入っているので共有しないでください。ターミナルに表示される新しいアプリケーションIDをメモしておいてください。 .nexmo-appファイルにもあります)。

次に、LVNを購入してこのアプリケーションとリンクさせる必要がある。実行する:

nexmo number:search GB --sms

番号をコピーして実行する:

nexmo number:buy <number>
nexmo link:app <number> <application_id>
nexmo numbers:update <number> --mo_http_url=<ngrok_url>/inbound

これでLVNはセットアップされ、アプリケーションにリクエストを転送するようになった。メッセージを送ってみて、ターミナルに表示されるのを確認してください。

Message logged in terminalMessage logged in terminal

以下のように .envに追加する:

VONAGE_KEY=<your_api_key>
VONAGE_SECRET=<your_api_secret>
VONAGE_APP=<your_application_id>
VONAGE_PRIVATE_KEY=<your_private_key>

アプリケーションの秘密鍵は .nexmo_appファイルにあります。

データベースに投票を保存する

の一番上にある inbound.jsを要求し、初期化する。 MongoClient:

require('dotenv').config()
const { MongoClient } = require('mongodb')
const mongo = new MongoClient(process.env.DB_URL, { useUnifiedTopology: true })

文の下に console.log(vote)文の下に、データベースに接続し、新しいエントリーをコレクションにプッシュし、動作することをテストする:

await mongo.connect()
const votes = await mongo.db('eurovision').collection('votes')
const countries = await mongo.db('eurovision').collection('countries')
 await votes.insertOne({ msisdn, lvn, vote })

netlify-lambdaサーバーが自動的に再起動するのを待ち、LVNに別のメッセー ジを送る。Atlasで投票集をチェックすると、新しい文書が表示されるはずです。

ナンバー・インサイト

Vonage Number Insights APIは、電話番号(MSISDN)を与えると、それに関する洞察を提供します。ベーシック、スタンダード、アドバンスの3つの階層がある。このアプリケーションでは、基本的な検索の一部として返される番号の発信国を知りたい。

が定義されているすぐ上で headersが定義されているところで、Nexmoノード・クライアント・ライブラリを要求し、初期化します:

const Nexmo = require('nexmo')
const nexmo = new Nexmo({
  apiKey: process.env.VONAGE_KEY,
  apiSecret: process.env.VONAGE_SECRET,
  applicationId: process.env.VONAGE_APP,
  privateKey: Buffer.from(process.env.VONAGE_PRIVATE_KEY.replace(/\\n/g, "\n"), 'utf-8')
})

注意: Netlifyでホストされた後、このアプリケーションが動作するためには、Bufferを作成して置き換える必要があります。 \nを作成する必要があります。Netlifyでホストされていないアプリケーションでは、これを直接 process.env.VONAGE_PRIVATE_KEY.

ファイルの一番下に、番号から国番号を取得する新しい関数を作る:

function getCountryCodeFromNumber(number) {
  return new Promise((resolve, reject) => {
    nexmo.numberInsight.get({level: 'basic', number}, async (err, res) => {
      if(err) reject(err)
      else resolve(res.country_code_iso3)
    })
  })
}

Number Insights APIが返す情報は他にもある。このアプリケーションでは、電話番号に関連付けられた3桁のISOコードのみが必要です。このISOコードは、当社のコレクションに参加しているすべての国に対して保存されます。 countries収集されます。

その上に votes.insertOne()を加える:

const votersCountry = await getCountryCodeFromNumber(msisdn)
console.log(votersCountry)

LVNに別のメッセージを送る。国番号は端末に記録されているはずです。

ユーザーに応答を送信する

メッセージを受け取ったら、ユーザーに応答してそのことを知らせなければなりません。アプリケーションの一番下に、これを行う関数を追加してください:

function sendMessage(sender, recipient, text) {
  return new Promise((resolve, reject) => {
    const to = { type: 'sms', number: recipient }
    const from = { type: 'sms', number: sender }
    const message = { content: { type: 'text', text } } 
    nexmo.channel.send(to, from, message, (err, res) => {
      if(err) reject(err)
      resolve({ headers, statusCode: 200, body: 'ok' })
    })
  })
}

これで、この関数を使ってユーザーにメッセージを送信し、その値を直接返すことができる。の returnステートメントを try {}ブロックの文を新しい関数呼び出しに置き換えてください:

return await sendMessage(lvn, msisdn, 'Thank you for voting!')

LVNにメッセージを送ると、返信があるはずです。

投票が有効かどうかをチェックする

私たちは、送られてきたすべての票を保存したいわけではありません。有効であるために必要なチェックがいくつかあります。変数の下に votersCountry変数の下に、チェックを作成する:

const existingVote = await votes.findOne({ msisdn: msisdn })
const countryInFinal = await countries.findOne({ iso: vote, final: true })
const votersCountryCanVote = await countries.findOne({ iso: votersCountry })
 if(existingVote) {
  return await sendMessage(lvn, msisdn, 'You have already voted')
}
if(!countryInFinal) {
  return await sendMessage(lvn, msisdn, 'That country is not in the final, or your message is not a valid country code.')
}
if(!votersCountryCanVote) {
  return await sendMessage(lvn, msisdn, 'Your number is not from a participating country')
}
if(votersCountry == vote) {
  return await sendMessage(lvn, msisdn, 'You cannot vote for your own country')
}

の中のオブジェクトを votes.insertOne()の中のオブジェクトを、保存したい情報を含むように変更する:

votes.insertOne({ msisdn, vote, votersCountry })

if文の中にreturn文があるので、どの条件も満たさない場合、つまり有効な場合のみ投票が挿入される。

投票数を増やす

投票システムは完成した。しかし、結果のエンドポイントを構築するには、数千票が必要だ。前回同様、20k票を追加するスクリプトを以下に示す。このコードを新しい addVotes.jsファイルに追加する:

require('dotenv').config()
const { MongoClient } = require('mongodb')
const mongo = new MongoClient(process.env.DB_URL, { useUnifiedTopology: true })
 mongo.connect().then(async () => {
  try {
    const countries = await mongo.db('eurovision').collection('countries')
    const votes = await mongo.db('eurovision').collection('votes')
    const list = await countries.find().toArray()
     const votesList = []
    for(let i=0; i<20000; i++) {
      const { iso: votersCountry } = list[Math.floor(Math.random() * list.length)]
      const availableCountries = list.filter(c => c != votersCountry && c.final)
      const { iso: vote } = availableCountries[Math.floor(Math.random() * availableCountries.length)]
       votesList.push({
        msisdn: String(Math.ceil(Math.random() * 100000)),
        votersCountry, vote
      })
    }
    
    const result = await votes.insertMany(votesList)
    console.log(`Added ${result.insertedCount} documents to the collection`)
    mongo.close()
  } catch(e) {
    console.error(e)
  }
})

既存のドキュメントを削除してから、このスクリプトを5、6回実行してください。これであなたのMongoDB Atlasデータベースにはたくさんのサンプル票があるはずです。

12000 records in the votes collection12000 records in the votes collection

フロントエンド用エンドポイントの作成

ドロップダウンに入力する国を返すエンドポイントと、指定した国の得点を返すエンドポイントが必要です。

Completed dashboardCompleted dashboard

国別リスト

に新しいファイルを作成する。 /functions/src/countries.js:

require('dotenv').config()
const { MongoClient } = require('mongodb')
const mongo = new MongoClient(process.env.DB_URL, { useUnifiedTopology: true })
 const headers = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'Content-Type'
}
 exports.handler = async (event, context) => {
  try {
    await mongo.connect()
    const countries = await mongo.db('eurovision').collection('countries')
    const list = await countries.find().toArray()
    return { headers, statusCode: 200, body: JSON.stringify(list) }
  } catch(e) {
    console.error('Error', e)
    return { headers, statusCode: 500, body: 'Error: ' + e }
  }
}

netlify-lambdaサーバーを再起動して、次のように実行してみてください。 curl http://localhost:9000/countries.

結果を得る

このエンドポイントは、クエリ・パラメータとして ?country=CODE.という名前の新しいファイルに、各国のエンドポイントのコードをコピー&ペーストします。 results.js.という名前の新しいファイルに貼り付けます。 try {}ブロックの内容を次のように置き換えます:

await mongo.connect()
const countries = await mongo.db('eurovision').collection('countries')
const votes = await mongo.db('eurovision').collection('votes')
 const { country } = event.queryStringParameters
 const topTen = await votes.aggregate([
  { $match: { votersCountry: country } },
  { $group: { _id: '$vote', votes: { $sum: 1 } } },
  { $sort: { votes: -1 } },
  { $limit: 10 }
]).toArray()
 const points = [ 12, 10, 8, 7, 6, 5, 4, 3, 2, 1 ]
 const list = await countries.find().toArray()
 const results = topTen.map((votes, i) => {
  const countryRecord = list.find(c => c.iso == votes._id)
  return {
    ...votes,
    points: points[i],
    country: countryRecord.name
  }
})
 return { headers, statusCode: 200, body: JSON.stringify(results) }

変数は topTen変数は、MongoDBの集約を使用して、提供された国によって投票された上位10エントリを返します。そして、各エントリにポイント値を追加します。 points配列に追加します。

サーバーを再起動して curl http://localhost:9000/results?country=GBRを実行する。

Scaffoldフロントエンド

プロジェクト・ルートに index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Eurovision Results Pane</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div id="app">
    <div id="leaderboard">
      <h1>Leaderboard</h1>
      <div class="list">
        <div class="country" v-for="country in leaderboard">
          <span class="name">{{country.name}}</span>
          <span class="score">{{country.score}}</span>
        </div>
      </div>
    </div>
    <div id="admin">
      <h1>Get Results</h1>
      <form>
        <select v-model="toReveal">
          <option disabled value="">Select country</option>
          <option v-for="country in leftToReveal" :value="country.iso">{{country.name}}</option>
        </select>
        <input type="submit" @click.prevent="getScores" value="Get Scores">
      </form>
      <div id="results">
        <h2>{{resultsCountry}}</h2>
        <div class="result" v-for="result in results">
          <span class="name">{{result.country}}</span>
          <span class="points">+{{result.points}}</span>
        </div>
      </div>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  <script src="client.js"></script>
</body>
</html>

プロジェクト・ルートに style.cssファイルを作成する:

@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;900&display=swap');

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    background: #050636;
    font-family: 'Montserrat', sans-serif;
}

#app {
    display: grid;
    grid-template-columns: auto 350px;
    grid-gap: 1em;
    padding: 1em;
}

#leaderboard {
    background: white;
    color: #050636;
    padding: 1em 1em 0;
}

.list {
    columns: 2;
    column-gap: 1em;
    margin-top: 1em;
}

.country,
.result {
    padding: 0.5em;
    background: #f0f0f0;
    margin-bottom: 1em;
    width: 100%;
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    font-size: 1.25em;
    align-items: center;
}

.score {
    font-size: 1.25em;
    font-weight: bold;
}

#admin {
    background: #2a2b87;
    color: white;
    padding: 1em;
}

form {
    display: grid;
    grid-template-columns: 225px auto;
    grid-gap: 1em;
}

form {
    margin: 1em 0;
}

.result {
    background: #4c4eb3;
    margin-top: 0.5em;
}

プロジェクト・ルートに client.jsファイルを作成する:

const app = new Vue({
  el: '#app',
  async created() {
    const countryResp = await fetch(this.baseURL + '/countries');
    const countries = await countryResp.json();
    this.countries = countries.map(country => {
      return { ...country, results: false, score: 0 }
    })
  },
  data: {
    countries: [],
    toReveal: undefined,
    results: undefined,
    resultsCountry: undefined
  },
  computed: {
    leaderboard() {
      return this.countries.filter(c => c.final).sort((a, b) => b.score - a.score)
    },
    leftToReveal() {
      return this.countries.filter(c => !c.results)
    },
    baseURL() {
      return "http://localhost:9000"
    },
    toRevealCountry() {
      const country = this.countries.find(c => c.iso == this.toReveal)
      return country.name
    }
  },
  methods: {
    async getScores() {
      // Get results
      const resultsResp = await fetch(this.baseURL + '/results?country=' + this.toReveal);
      this.results = await resultsResp.json();
       // Assign points to countries
      for(let result of this.results) {
        const country = this.countries.find(c => c.iso == result._id)
        country.score += result.points
      }
       // Remove item from results select
      const votingCountry = this.countries.find(c => c.iso == this.toReveal)
      votingCountry.results = true
      
      // Show country name in results pane
      this.resultsCountry = votingCountry.name
    }
  }
})

いくつか重要なことがある:

  • その中で created()では、すべての国に2つのプロパティを追加している。 resultsプロパティを追加する。

  • 計算された財産は leftToReveal計算されたプロパティには resultsに設定されている国のみが含まれます。 trueに設定されている国のみを含むので、誤って国をダブルカウントすることはありません。

リフレッシュの間、結果を持続させる

これはかなり優れた、かなり堅牢なシステムだ。改善できる点としては、リフレッシュの間のスコアの永続化だ(結果発表中にこのようなことが起こった場合)。

メソッドの一番下に getScores()メソッドの最後に countriesデータをlocalStorageに追加します:

localStorage.setItem('countries', JSON.stringify(this.countries))

更新 created()を使用すると、localStorageに新しい国データがない場合にのみ、そのデータを取得することができます:

async created() {
  if(localStorage.getItem('countries')) {
    this.countries = JSON.parse(localStorage.getItem('countries')) 
  } else {
    const countryResp = await fetch(this.baseURL + '/countries');
    const countries = await countryResp.json();
    this.countries = countries.map(country => {
      return { ...country, results: false, score: 0 }
    })
  }
},

Netlifyでホストする

プロジェクト・ルートに.gitignore.このファイルに記載されているファイルやディレクトリは、git リポジトリには含まれません。ファイルは次のようにします:

node_modules
functions/build
.env
.nexmo-app

このリポジトリをGitHubにプッシュし、Netlifyアカウントにログインします。クリック Gitから新しいサイトをクリックし、リポジトリを選び 基本ビルド設定ビルドコマンドは npm run netlify:build.そして 詳細ビルド設定ファイルの各項目を .envファイルの各項目を追加する。

デプロイ後、2つの変更が必要だ:

  1. Vonage API アプリケーションの URL を次のように更新します。 <netlify_url>/.netlify/functions/status(または /inbound).

  2. client.jsメソッドを baseURLメソッドを次のように更新する:

baseURL() {
  if(location.hostname == 'localhost' || location.hostname == "127.0.0.1") {
    return "http://localhost:9000"
  }  else {
    return "<netlify_url>/.netlify/functions"
  }
},

新しいコミットをプッシュすると、Netlifyサイトは自動的に再デプロイされます。

総括と次のステップ

このアプリケーションにはかなり多くの可動部分がある。しかし、各パーツは、実際に機能するユーロビジョン投票システムを作成するために、それぞれの仕事をしています。

Nexmo CLIまたはウェブダッシュボードを使用して、異なる国から複数のLVNを取得することができます。どのLVNにメッセージを送っても、ユーザーは1回しか投票できません。改善点としては、投票ウィンドウを閉じて、すべての国が同じ投票期間を持つようにすることです。

最終プロジェクトは下記でご覧いただけます。 https://github.com/nexmo-community/eurovision-voting-system-js

これまで通り、サポートが必要な場合はお気軽に Vonage開発者コミュニティSlack.そこでお会いできることを楽しみにしています。

アイスランドちなみに、2020年大会ではアイスランドがベストエントリーだった。

シェア:

https://a.storyblok.com/f/270183/400x400/c822f15b89/kevinlewis.png
Kevin Lewisヴォネージの卒業生

Vonageの元デベロッパー・アドボケイトで、ロンドンの地元テック・コミュニティをサポートする役割を担っていた。彼は経験豊富なイベントオーガナイザーであり、ボードゲーマーであり、ムーというかわいい犬のパパでもある。また、You Got This(幸せで健康的な仕事生活に必要なコア・スキルに関するイベント・ネットワーク)のリード・オーガナイザーでもある。