This content originally appeared on Twilio Blog and was authored by Ashley Boucher
この記事はTwilio Developer VoicesチームのAshley Boucherが執筆したこちらの記事(英語)を日本語化したものです。
Twilio Syncは、Twilio ConversationsなどのTwilio APIの基盤となる技術です。Twilio Syncを利用すると、クラウドに保存されたステータスをアプリに追加でき、リアルタイムのコラボレーションの新しい機会を生み出します。
本稿では、Twilio Syncを使ってアプリでユーザーのオンラインステータスを表示する方法をご紹介します。
必要なツール
- インストール済のNode.js
- Twilioアカウント
アプリと環境を設定する
今回のアプリはフロントエンドとバックエンドの2つの部分で構成されています。フロントエンドはユーザーが実際に操作するアプリの部分です。フロントエンドはTwilio Sync JavaScript SDKを使用します。このSDKはSync APIと対話するための許可を得るためにアクセストークンを必要とします。バックエンド側でこのアクセストークンを生成します。
まずはファイル構造やアプリの環境を整えましょう。
ターミナルまたはコマンドプロンプトを開き、以下のコマンドを実行してください。フロントエンドとバックエンドの両方の親ディレクトリとなる新しいディレクトリを作成します。
mkdir react-sync
作成したディレクトリに移動します。
cd react-sync
次にバックエンドの設定をします。バックエンドはExpressで構築します。
mkdir token-service
cd token-service
npm init -y
npm install express twilio dotenv cors
上記のコマンドは、新しいNode.jsアプリを作成し、以下の4つのdependenciesをインストールします。
- サーバー構築に使用する
express
- Twilio Node Helper Libraryを利用し、アクセストークンを生成するための
twilio
- 環境変数を読み込むために使う
dotenv
- React.jsのフロントエンドからExpressアプリへのリクエストを送信するための
cors
token-serviceディレクトリで、.envとindex.jsという2つの新しいファイルを以下のコマンドで作成します。テキストエディターで直接作成しても構いません。
touch .env index.js
.envファイルは環境変数を追加する場所で、index.jsファイルはバックエンドのコードを書く場所です。
Twilioの認証情報を取得する
お使いのテキストエディターで.envファイルを開きます。
以下の変数とその値をコピーして、ファイルに貼り付けます。
TWILIO_ACCOUNT_SID=XXXXX
TWILIO_API_KEY=XXXXX
TWILIO_API_SECRET=XXXXX
SYNC_SERVICE_SID=XXXXX
XXXXX
の文字列は、Twilioの認証情報のプレースホルダーを表しています。これらの認証情報を取得し、.envファイルに追加する方法をご紹介します。
Account SID
Twilio Consoleに移動し、Account SIDを確認します。Account SIDの値をコピーして、.envファイルのTWILIO_ACCOUNT_SID
変数に貼り付けてください。
APIキーとAPIシークレット
次に、Twilio ConsoleのAPI Keyセクションにアクセスします。赤いプラス記号をクリックして、新しいAPIキーを作成します。FRIENDLY NAMEのテキストフィールドにキーの名称を入力し、KEY TYPEをStandard
に設定します。Create API Keyをクリックします。
画面にSIDとSECRETを含むデータが表示されます。SIDはあなたのAPIキーです。
SIDを.envファイルのTWILIO_API_KEY
の値として、SECRETをTWILIO_API_SECRET
の値として貼り付けてください。
この画面を離れると、あなたのSECRETには二度とアクセスできません。値のバックアップを取っておくことを推奨します。
Service SIDを同期する
Twilio ConsoleのSyncセクションに移動します。Create new Sync Serviceをクリックし、新しいSyncサービスを作成します。ポップアップが表示されたら、「react-sync」のような判別しやすい名前を入力してください。Createをクリックし、次の画面で画面の右上のService SIDをコピーします。
Service SIDの値を.envファイルのSYNC_SERVICE_SID
変数に貼り付けてください。
このファイルを保存して閉じると、アプリの設定が完了します。
トークンサービスの構築
お使いのテキストエディターでindex.jsファイルを開き、以下のコードを追加してください。
const express = require('express');
const cors = require('cors');
require('dotenv').config();
const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(cors());
const port = 3000;
app.get('/token', cors({origin:'http://localhost:3001'}), (req, res) => {
// generate access token here
});
app.listen(port, () => {
console.log(`Token Service listening at http://localhost:${port}`)
});
このコードでExpressアプリを作成し、オリジンのhttp://localhost:3001から/tokenエンドポイントへのGET
リクエストの送信ルートを確立させます。フロントエンド側がTwilio Sync APIに接続する必要があるときは、このエンドポイントにリクエストを行います。現時点では/tokenルートにはまだコードがなく、generate access token here
というコメントがあるだけです。次のステップでコードを追加していきます。
/tokenルートの、コメントの下に次のコードを追加します。
const AccessToken = require('twilio').jwt.AccessToken;
const SyncGrant = AccessToken.SyncGrant;
const token = new AccessToken(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_API_KEY,
process.env.TWILIO_API_SECRET
);
const syncGrant = new SyncGrant({
serviceSid: process.env.SYNC_SERVICE_SID,
});
token.addGrant(syncGrant);
token.identity = req.query.identity;
res.send({
accessToken: token.toJwt()
});
本稿でご紹介するアクセスの生成方法は、デモンストレーションを目的としており、本質的に安全な方法ではありません。本番アプリではクライアントにアクセストークンを付与する前に、ユーザーを検証し、認証してください。Syncを使用するアプリをリリースする前に、How to secure your Twilio Sync appsを参照してください。
ファイルを保存すれば、バックエンドの準備は完了です。
次に進む前に、ターミナルのtoken-serviceディレクトリから以下のコマンドを実行して、Expressサーバーを起動してください。
node index.js
サーバーが起動すると、次のようなメッセージが表示されます。
Token Service listening at http://localhost:3000
このプロセスは動作させたまま次のステップに進んでください。
Reactのフロントエンドを構築するための基盤を作る
新しくターミナルまたはコマンドプロンプトウィンドウを開き、react-syncディレクトリに移動して、以下のコマンドでフロントエンドの枠組みを作ります。
npx create-react-app client
npm install twilio-sync
上記のコマンドを実行すると、react-sync/clientディレクトリが作成されます。この新しいフォルダの中には、いくつかのファイルとサブフォルダがありますが、そのうちのひとつがsrcです。
このプロジェクトでは、App
というコンポーネントと、OnlineUsers
という子コンポーネントの2つを作ります。App
コンポーネントが主要コンポーネントとなります。このコンポーネントは、ローカルユーザーのサインインを制御します。OnlineUsers
コンポーネントは、すべてのオンラインユーザーのリストをレンダリングし、リモートユーザーのサインインやログアウトなどのイベントに応答します。
Appコンポーネント
srcフォルダを開いて、App.jsファイルを探します。
App.jsのコードをすべて削除し、以下に置き換えます。
import {useState} from 'react';
import OnlineUsers from './OnlineUsers.js';
var SyncClient = require('twilio-sync');
このコードでは、ReactからuseState()
フックをインポートし、先ほど述べたOnlineUsers
という子コンポーネントをインポートし、さらにTwilio Syncクライアントオブジェクトをインポートしています。まだOnlineUsers
は作成していないので、Reactサーバーがすでに稼働している場合はエラーが表示されます。
コンポーネント構造の作成
次のステップでは、機能的なコンポーネントを作成します。先ほど追加したコードの下に、以下のコードを貼り付けます。
function App() {
const [identity, setIdentity] = useState('');
const [localUser, setLocalUser] = useState(null);
const [onlineUsersSyncList, setOnlineUsersSyncList] = useState(null);
}
export default App;
このコードは、Appコンポーネントの枠組みを作成し、その中で前の手順でインポートしたuseState()フックを使用して以下の3つの状態変数を設定しています。
identity
はローカルユーザーがフォームフィールドに入力した際、ユーザーの氏名を取得するために使用します。localUser
はListItem
リソースを表します。ListItem
はSyncの共有状態にあるローカルユーザーを含むTwilio Syncオブジェクトです。onlineUsersSyncList
はList
リソースを表します。List
はListItem
リソースを順序付けしたリストで、Syncの共有状態にあるすべてのオンラインユーザーを表します。
コンポーネントに条件付きレンダリングを追加する
App関数内の状態変数の下に以下のreturnメソッドを追加します。
return (
<div className="app">
{
localUser && onlineUsersSyncList
? <OnlineUsers localUser={localUser} onlineUsersSyncList={onlineUsersSyncList} />
: <div>
<input
type="text"
value={identity}
onChange={(event) => setIdentity(event.target.value)}
placeholder="Enter your name"></input>
<button onClick={getAccessToken}>Connect to App and show you're online!</button>
</div>
}
</div>
);
このコードは、App
コンポーネントがロードされたときに、レンダリングされる項目を決定する役割を果たします。まず、localUser
とonlineUsersSyncList
の状態の値が「Truthy」であるかどうか、つまりnull
、false
、empty
、undefined
ではない何らかの値を持っているかどうかを確認します。
コンポーネントが初期ロードされ、ユーザーがサインインする前の状態では前述した変数ははすべて「Falsy」な値になります。この場合、コンポーネントはユーザーの名前を入力するテキスト入力フィールドと、ユーザーがサインインするためにクリックするボタンをレンダリングします。
ユーザーがボタンをクリックすると、そのクライアントにアクセストークンが付与されます。クライアントがアクセストークンを取得すると、Syncリソースが初期化され、状態値が設定されます。これらの処理はすべて、ボタンがクリックされたときに呼び出されるgetAccessToken()
という関数の中で行われます。次の工程でこの関数を追加します。
状態値が更新されると、コンポーネントが再レンダリングされ、状態の値が「Truthy」になります。これにより、入力フィールドとボタンの代わりにOnlineUsers
コンポーネントがレンダリングされます。
このフローは、ユーザーを認証または確認するメカニズムを含んでいないため、安全なサインインを確証していません。匿名のユーザーでもアクセストークンを取得できてしまいます。本稿ではTwilio Syncの機能のご紹介を目的としているため、これらの設定に関する詳細は省略しています。本番環境ではこのままデプロイせず、安全なサインイン方法を導入してください。
コンポーネントにgetAccessToken()関数を追加する
return()
メソッドが追加されたので、前述したgetAccessToken()
メソッドを追加して App
コンポーネントを完成させます。
以下のコードをApp
コンポーネント内の、状態変数宣言の下、return()
の前に追加します。
const getAccessToken = async () => {
const res = await fetch(`http://localhost:3000/token?identity=${identity}`);
const data = await res.json();
const syncClient = new SyncClient(data.accessToken);
const SyncList = await syncClient.list('online-users');
const localUser = await SyncList.push({name: identity})
await setLocalUser(localUser);
await setOnlineUsersSyncList(SyncList);
}
このコードは、バックグラウンドで動作しているExpressサーバの /token ルートにGET
リクエストを行います。
レスポンスでアクセストークンを取得すると、SyncClient
のインスタンスが作成され、SyncList
とlocalUser
の2つのSyncオブジェクトの作成に使用されます。これらのオブジェクトにそれぞれコンポーネントの状態変数の値を割り当てます。
App
コンポーネントの説明は以上です。次にOnlineUsers
コンポーネントについて説明します。
OnlineUsersコンポーネント
/client/srcフォルダにOnlineUsers.jsという新しいファイルを作成します。
OnlineUsers.jsファイルに以下のコードを追加します。
import {useState, useEffect} from 'react';
このコードでReactからuseState()
とuseEffect()
のフックをインポートします。
インポートの下に以下のコードを追加して、OnlineUsers
コンポーネントの枠組みを作成します。
コンポーネントを構築する
function OnlineUsers({localUser, onlineUsersSyncList}) {
}
export default OnlineUsers;
このコードでは、空のコンポーネントを作成してエクスポートし、親のApp
コンポーネントからのPropsオブジェクトを分割代入(Destructuring)して、2つの変数localUser
とonlineUsersSyncList
に変換しています。
次に、以下のコードでOnlineUsers
関数の中で、初期状態を設定します。
function OnlineUsers({localUser, onlineUsersSyncList}) {
const [onlineUsers, setOnlineUsers] = useState([]);
}
export default OnlineUsers;
コンポーネントがマウントれたタイミングで処理を実行する
useEffect()
フックを使って、コンポーネントのマウント後に以下の処理を実行します。
- 現在の全員のオンラインユーザーリストをSyncから取得し、それを状態変数
onlineUsers
に割り当てます。 - イベントリスナーを
onlineUsersSyncList
オブジェクトに設定して、ユーザーがオンラインになるタイミングを監視します。 - イベントリスナーを
onlineUsersSyncList
オブジェクトに設定して、ユーザーがオフラインになるタイミングを監視します。
以下のコードをコピーして、関数内の状態宣言の下に貼り付けます。
useEffect(() => {
getSetOnlineUsers();
onlineUsersSyncList.on('itemAdded', event => {
if (!event.isLocal) {
getSetOnlineUsers();
}
});
onlineUsersSyncList.on('itemRemoved', getSetOnlineUsers);
window.addEventListener("beforeunload", removeParticipant);
}, []);
ヘルパー関数を追加する
このコードは、まだ定義していない2つの関数、getSetOnlineUsers()
とremoveParticipant()
を呼び出しています。これからこれらの関数を追加していきます。useEffect()
のフックの下に、以下のコードを貼り付けます。
// Gets current list of online users from Sync
const getSetOnlineUsers = async() => {
const items = await onlineUsersSyncList.getItems();
setOnlineUsers(items.items);
}
// Removes local user from Sync list
const removeParticipant = async () => {
const list = await onlineUsersSyncList.remove(localUser.index)
list.close();
}
コンポーネントのレンダリング
OnlineUsers
コンポーネントのステートに格納されたユーザーのリストをレンダリングするために、return()
メソッドを追加します。以下のコードをOnlineUsers
関数の閉じかっこ(}
)の前に貼り付けます。
return (
<div className="participants">
<h2>Online users:</h2>
{
onlineUsers.map(p => <div key={p.index}>{p.data.name}</div>)
}
</div>
);
このファイルを保存して閉じれば、コンポーネントの作成は完了です。
Syncアプリを試す
ターミナルまたはコマンドプロンプトに戻り、1つ目のウィンドウでバックエンドのExpressサーバーがポート3000で動作していることを確認します。
2つ目のターミナルウィンドウで、clientディレクトリに移動し、以下のコマンドを実行します。
npm start
これにより、ローカルのReactサーバーが起動します。Reactサーバーは通常、ポート3000で起動しますが、バックエンドがすでにこのポートで動作しているため、3001番ポートで動作しても問題ないか確認を求められます。確認のためにy
を押します。
サーバーが起動し、ブラウザ上のhttp://localhost:3001に自分のアプリが表示されるようになります。
ブラウザでタブまたはウィンドウを2つ用意し、アプリを開きます。
1つのタブで、テキストフィールドに名前を入力してボタンをクリックすると、名前がオンラインユーザーリストに表示されます。
2つ目のタブで、別の名前を入力し、ボタンをクリックします。今度は、両方のユーザーがリストに表示されます。
どちらかのタブを閉じると、開いているタブにオンラインのユーザーが1人になっていることが表示されます。
お疲れ様でした。Express、ReactでのTwilio Syncアプリの開発が完了しました。本稿では、Twilio Syncの使い方の一例を紹介しました。この経験を生かして、マルチプレイヤーのオンラインゲームや、SyncとVanilla JavaScriptを使ったコラボレーションノートパッドを作ってみてはいかがでしょうか。 ぜひ、あなたの作品をTwitterで共有してください。
Ashleyは、TwilioブログのJavaScriptエディターです。Ashleyと協力し、Twilioにテクニカルストーリーを紹介するには、Twitterで@ahl38までご連絡ください。TwitterでAshleyが見つからない場合は、どこかのパティオでコーヒーを飲んでいることでしょう(ワインの時間かも)。
This content originally appeared on Twilio Blog and was authored by Ashley Boucher
Ashley Boucher | Sciencx (2021-08-04T08:25:49+00:00) Express、ReactとTwilio Syncでオンラインステータスをアプリ内で共有できる機能を実装する. Retrieved from https://www.scien.cx/2021/08/04/express%e3%80%81react%e3%81%a8twilio-sync%e3%81%a7%e3%82%aa%e3%83%b3%e3%83%a9%e3%82%a4%e3%83%b3%e3%82%b9%e3%83%86%e3%83%bc%e3%82%bf%e3%82%b9%e3%82%92%e3%82%a2%e3%83%97%e3%83%aa%e5%86%85%e3%81%a7/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.