Edited at

TwilioのRuntime Clientを使ってSyncをデータベースのように扱おう

More than 1 year has passed since last update.


はじめに

Twilioには、Functionsというサーバーレスアーキテクチャがあります。

https://jp.twilio.com/functions

これにより、ユーザ側にWebサーバーを立てなくても、大体のことはできるようになりました。

ただ、Twilioにはデータベースがないので、ちょっとした情報を保存して、別のFunctionsから参照したりすることが難しいです。

Assetsというストレージサービスもあり、テキストファイルなどをFunctionsから読み込むことはできますが、こちらも更新ができません。

そこで、データベースの代わりにTwilio Syncを使うという手があります。

https://jp.twilio.com/sync

Twilio Syncは元々、複数のデバイス間で情報を同期させるためのサービスで、たとえばコールセンターで現在誰が待機中かを知るような、いわゆるリアルタイム通信をするような時に利用されます。

このSyncでは、あるデバイスから受け取った情報を、一旦Twilio上に保存してから配信するようになっています。これをうまく利用することで、データベース的に利用してしまおうというのが、本記事の趣旨となります。


Runtime Client

Runtime Clientは、Functionsから利用できる特別なオブジェクトです。

ドキュメントは以下にございます。

https://jp.twilio.com/docs/api/runtime/runtime-client

たとえば、Runtime Clientを使って、デフォルトのSyncサービス(アカウントごとに1つだけ、自動的に生成されています)を読み出すのは、以下のようなコードになります。

なお、実行するためには、FunctionsのConfigureページにある「Enable ACCOUNT_SID and AUTH_TOKEN」のチェックボックスを入れてください。


functions

exports.handler = function(context, event, callback) {

Runtime.getSync()
.fetch()
.then(defaultSyncService => {
console.log('Sync Service SID: ' + defaultSyncService.sid)
callback(null, defaultSyncService.sid)
})
.catch(error => {
console.log(error)
callback(error)
});
};



Documentsオブジェクト


  • 単一のJSON形式オブジェクト

  • 1データのサイズは最大16KB

  • 単純な値のPUB/SUBに向いている

  • 履歴を取るような使い方には向いていない

  • JavaScript SDKを使うと、Documentオブジェクトの生成、更新、購読、削除が可能

  • サーバーサイドのREST API経由でも管理可能

  • Documentsオブジェクトの利用例


    • コールセンターでオペレータの稼働確認などに利用



デフォルトサービス内にDocumentsオブジェクトを作成するには、以下のコードが参考になるでしょう。

このコードでは、すでに同じ名前のDocumentsオブジェクトがあればそれを更新し、ない場合は新規で作成するようになっています。


functions

exports.handler = function(context, event, callback) {

let sync = Runtime.getSync();
let payload = {
name: 'test'
};

sync.documents("testDoc")
.update({
data: payload
}).then(response => {
console.log(response)
callback(null, 'OK')
}).catch(error => {
sync.documents.create({
uniqueName: "testDoc",
data: payload
}).then(response => {
console.log(response)
callback(null, 'OK')
}).catch(error => {
console.log(error)
callback(error)
})
})
};


作成したDocumentsオブジェクトを読み込むには以下のコードを参考にしてください。


functions

exports.handler = function(context, event, callback) {

Runtime.getSync().documents('testDoc')
.fetch()
.then(response => {
console.log(response);
callback(null, response.data)
}).catch(error => {
console.log(error)
callback(error)
});
};


Listsオブジェクト


  • 格納順が保証されたJSONリスト

  • 時系列で確認したい履歴を取るような使い方に向いている

  • JavaScript SDKを使うと、Listオブジェクトの生成、更新、購読、削除が可能

  • サーバーサイドのREST API経由でも管理可能

  • Listsオブジェクトの利用例


    • ログの保存などに利用



デフォルトサービス内のListsオブジェクトにデータを追加していくには、以下のコードが参考になるでしょう。

このコードでは、すでに同じ名前のListsオブジェクトがあればそれにデータを追加し、ない場合は新規で作成するようになっています。


functions

exports.handler = function(context, event, callback) {

let sync = Runtime.getSync();
let payload = {
id: 'ABC',
number: 123,
};

sync.lists.create({ // リストオブジェクトを生成
uniqueName: 'list_of_data',
})
.then(response => { // 作成完了
console.log(`Sync list created.`);
})
.catch(error => { // すでに存在
console.log(`Sync list already exists.`);
})
.then(() => { // アイテムの書き込み
return sync.lists('list_of_data').syncListItems.create({
data: payload
});
}).then(response => { // 書き込み成功
console.log(response)
callback(null)
}).catch(error => { // 書き込み失敗
console.log(error)
callback(error)
});
};


また、Listsオブジェクトの内容を表示させるには、以下のコードが参考になるでしょう。

eachループは非同期で動作するので、callbackの記述場所が難しいのですが、doneパラメータを活用することで解決できます。


functions

exports.handler = function(context, event, callback) {

let sync = Runtime.getSync();
sync.lists('list_of_data').syncListItems.each({
done: function() {
callback(null, 'Done.');
},
}, item => {
console.log(item.data);
});
};


Mapオブジェクト


  • 格納順が保証されないKey/Value形式のJSONデータ

  • Keyで検索して、内容を記録するような使い方に向いている

  • JavaScript SDKを使うと、Listオブジェクトの生成、更新、購読、削除が可能

  • サーバーサイドのREST API経由でも管理可能

  • Mapsオブジェクトの利用例


    • オペレータの内線番号やスキルなどの登録に利用



デフォルトサービス内のMapsオブジェクトにデータを追加、もしくは更新していくには、以下のコードが参考になるでしょう。

このコードでは、すでに同じ名前のMapsアイテムがあればそれにデータを更新し、ない場合は新規で追加するようになっています。


functions

exports.handler = function(context, event, callback) {

let sync = Runtime.getSync();
let key = 1;
let payload = {
'name': 'Yoshio Hayashi',
'gender': 'male',
'age': 40
};

sync.maps.create({
uniqueName: "users"
})
.then(response => {
console.log(`Maps created.`);
})
.catch(error => {
console.log(`Maps exist.`);
})
.then(() => {
return sync.maps('users').syncMapItems(key).update({
data: payload
});
})
.then(response => {
console.log(response);
callback(null, 'updated.');
})
.catch(error => {
console.log(`Item not exist.`);
})
.then(() => {
return sync.maps('users').syncMapItems.create({
key: key,
data: payload
});
})
.then(response => {
console.log(response);
callback(null, 'added.');
})
.catch(error => {
console.log(error);
callback(error);
});
};


また、特定のMapアイテムの内容を表示させるには、以下のコードが参考になるでしょう。


functions

exports.handler = function(context, event, callback) {

let sync = Runtime.getSync();
let key = 1;

sync.maps('users').syncMapItems(key).fetch()
.then(sync_map_item => {
console.log(sync_map_item);
callback(null, 'found.');
})
.catch(error => {
console.log(error);
callback(null, 'Not found.');
});
};


ちなみに、Twilio Syncに保存されているデータは、明示的に削除しない限り消えません(TTLパラメータを指定している場合を除く)。

気になる料金はこちらです。

ちょっとしたデータの保存や、サンプルプログラムの作成などでデータベースを外部に構築するまでもないようなケースではきっと役に立つはずです。