The Twilio Runtime Client provides a direct way of orchestrating the various parts of the Twilio Runtime without requiring an imported module. Using the Runtime Client, developers can reference other Functions to better organize their code, access configuration and files stored in Assets, and manage real-time data via Twilio Sync.
Access the Runtime Client in a Function by referencing Runtime
, which exposes the following API:
The getAssets
method returns an object that contains the names each private Asset in a Service. Each Asset name serves as the key to an Asset object that contains the path
to that Asset, as well as an open
method that can be conveniently used to access its contents. These paths can be used to retrieve files served on Twilio Assets.
For example, executing Runtime.getAssets()
could return an object with the following private Assets:
_14{_14 '/names.json': {_14 path: '/var/task/files/ZNdad14da2e70d2533f640cf362fec0609',_14 open: [Function: open]_14 },_14 '/rickroll.mp3': {_14 path: '/var/task/files/ZNdfbfaf15a02e244fa11337548dabd9d0',_14 open: [Function: open]_14 },_14 '/helper-method.js': {_14 path: '/var/task/files/ZN5d6d933785a76da25056328a5764d49b',_14 open: [Function: open]_14 }_14}
getAssets()
only returns private Assets. Public and protected assets can be accessed via their publicly facing urls without the need for calling getAssets()
. Refer to the visibility guide for more context!
Note that an Asset such as names.json
will be returned with a key of '/names.json'
. To correctly retrieve the Asset and its path, the leading /
and extension must be part of the key used to access the object returned by Runtime.getAssets()
.
For example: Runtime.getAssets()['/names.json'].path
Property | Type | Description |
---|---|---|
path | string | String specifying the location of the private Asset |
open | function | Convenience method that returns the contents of the file from path in utf8 encoding |
If you would like to include a JavaScript module that isn't available on npm, the best way to do so is to upload the module as a private Asset, then use getAssets
in order to require the module as shown in the Load a module from an asset code example.
Example of how to get the file path for an Asset
_10exports.handler = function (context, event, callback) {_10 // Note: the leading slash and file extension are necessary to access the Asset_10 const path = Runtime.getAssets()['/my-asset.json'].path;_10_10 console.log('The path is: ' + path);_10_10 return callback();_10};
Example of how to load a third party library stored in an Asset
_12exports.handler = function (context, event, callback) {_12 // First, get the path for the Asset_12 const path = Runtime.getAssets()['/answer-generator.js'].path;_12_12 // Next, you can use require() to import the library_12 const module = require(path);_12_12 // Finally, use the module as you would any other!_12 console.log('The answer to your riddle is: ' + module.getAnswer());_12_12 return callback();_12};
Leverage the built-in open method for convenience
_10exports.handler = function (context, event, callback) {_10 const openFile = Runtime.getAssets()['/my_file.txt'].open;_10 // Calling open is equivalent to using fs.readFileSync(asset.filePath, 'utf8')_10 const text = openFile();_10_10 console.log('Your file contents: ' + text);_10_10 return callback();_10};
Directly read the contents of an Asset using filesystem methods
_13// We're reading a file from the file system, so we'll need to import fs_13const fs = require('fs');_13_13exports.handler = async function (context, event, callback) {_13 // Retrieve the path of your file_13 const file = Runtime.getAssets()['/my_file.txt'].path;_13 // Asynchronously read the file using a different encoding from utf8_13 const text = await fs.readFile(file, 'base64');_13_13 console.log('Your file contents: ' + text);_13_13 return callback();_13};
The getFunctions
method returns an object that contains the names of every Function in the Service. Each Function name serves as the key to a Function object that contains the path
to that Function. These paths can be used to import code from other Functions and to compose code hosted on Twilio Functions.
For example, executing Runtime.getFunctions()
could return an object with the following Functions:
_11{_11 'sms/reply': {_11 path: '/var/task/handlers/ZNdad14da2e70d2533f640cf362fec0609.js',_11 },_11 'helper': {_11 path: '/var/task/handlers/ZNdfbfaf15a02e244fa11337548dabd9d0.js',_11 },_11 'example-function': {_11 path: '/var/task/handlers/ZN5d6d933785a76da25056328a5764d49b.js',_11 },_11}
Note that, unlike an Asset, a Function such as sms/reply.js
will be returned with a key of "sms/reply"
. To correctly retrieve the Function and its path, do not include characters such as a leading slash or the .js
extension in the key used to access the object returned by Runtime.getFunctions()
.
For example: Runtime.getFunctions()["sms/reply"].path
Property | Type | Description |
---|---|---|
path | string | String specifying the location of the Function |
Example of how to retrieve the file path for a Function
_10exports.handler = function (context, event, callback) {_10 // Get the path for the Function. Note that the key of the function_10 // is not preceded by a "/" as is the case with Assets_10 const path = Runtime.getFunctions()['example-function'].path;_10_10 console.log('The path to your Function is: ' + path);_10_10 return callback();_10};
Private Functions are a great way to store methods that may be reused between your other Functions. For example, lets say we have a private Function called Zoltar
that exports a fortune-generating method, ask
:
Implement Zoltar and define an ask method
_20exports.ask = () => {_20 // We're not totally sure if Zoltar's advice is all that helpful_20 const fortunes = [_20 'A long-forgotten loved one will appear soon.',_20 'Are you sure the back door is locked?',_20 "Communicate! It can't make things any worse.",_20 'Do not sleep in a eucalyptus tree tonight.',_20 'Fine day for friends.',_20 'Good news. Ten weeks from Friday will be a pretty good day.',_20 'Living your life is a task so difficult, it has never been attempted before.',_20 'Stay away from flying saucers today.',_20 'The time is right to make new friends.',_20 'Try to relax and enjoy the crisis.',_20 'You need more time; and you probably always will.',_20 'Your business will assume vast proportions.',_20 ];_20_20 // Generate a random index and return the given fortune_20 return fortunes[Math.floor(Math.random() * fortunes.length)];_20};
You could then access this private method by using Runtime.getFunctions()
to get the path for the Zoltar Function, import Zoltar as a JavaScript module using require
, and then access the ask
method as in the following code sample:
Example of how to include code from other Functions
_13exports.handler = function (context, event, callback) {_13 // First, get the path for the Function. Note that the key of the function_13 // is not preceded by a "/" as is the case with Assets_13 const zoltarPath = Runtime.getFunctions()['zoltar'].path;_13 _13 // Next, use require() to import the library_13 const zoltar = require(zoltarPath);_13 _13 // Finally, use the module as you would any other!_13 console.log('The answer to your riddle is: ' + zoltar.ask());_13 _13 return callback();_13}
We've made it convenient for you to access the Sync REST API from Functions. Use the Runtime Client to access any of Sync's real-time data primitives and store information between Function invocations. The same data can be accessed using the Sync API library, making Sync from Functions the perfect way to update your real-time apps and dashboards.
The Runtime Client provides a wrapper around the Twilio REST API Helper for Twilio Sync. By default, calling Runtime.getSync()
will return a Sync Service object that has been configured to work with your default Sync Instance.
For added convenience and less typing, the following methods returned from getSync
are renamed from their usual name in the Node.js SDK, as you will see in the examples.
Default method name | Method name in Functions |
---|---|
syncMaps | maps |
syncLists | lists |
getSync
optionally accepts a configuration object with the following properties.
Parameter | Type | Description |
---|---|---|
serviceName | string | String specifying either the serviceSid or uniqueName of the Sync Service to connect to. Defaults to default . |
Example of how to get the default Sync Service Instance
_15exports.handler = (context, event, callback) => {_15 // Use the getSync method with no arguments to get a reference to the default_15 // Sync document for your account. Fetch returns a Promise, which will_15 // eventually resolve to metadata about the Sync Service, such as its SID_15 Runtime.getSync()_15 .fetch()_15 .then((defaultSyncService) => {_15 console.log('Sync Service SID: ', defaultSyncService.sid);_15 return callback(null, defaultSyncService.sid);_15 })_15 .catch((error) => {_15 console.log('Sync Error: ', error);_15 return callback(error);_15 });_15};
Example of how to use Runtime Client to get an Sync Service Instance by providing the SID
_15exports.handler = (context, event, callback) => {_15 // Pass a serviceName to getSync to get a reference to that specific_15 // Sync document on your account. Fetch returns a Promise, which will_15 // eventually resolve to metadata about the Sync Service, such as friendlyName_15 Runtime.getSync({ serviceName: 'ISXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' })_15 .fetch()_15 .then((syncService) => {_15 console.log('Sync Service Name: ' + syncService.friendlyName);_15 return callback(null, syncService.friendlyName);_15 })_15 .catch((error) => {_15 console.log('Sync Error: ', error);_15 return callback(error);_15 });_15};
Example of how to create a Map in Sync with the Runtime Client
_16exports.handler = (context, event, callback) => {_16 // maps, which is a shortcut to syncMaps, allows you to create a new Sync Map_16 // instance. Be sure to provide a uniqueName identifier!_16 Runtime.getSync()_16 .maps.create({_16 uniqueName: 'spaceShips',_16 })_16 .then((newMap) => {_16 console.log(newMap);_16 return callback(null, newMap);_16 })_16 .catch((error) => {_16 console.log('Sync Error: ', error);_16 return callback(error);_16 });_16};
Example of how to add an entry to a Sync Map with the Runtime Client
_21exports.handler = (context, event, callback) => {_21 // Given an existing Sync Map with the uniqueName of spaceShips, you can use_21 // syncMapItems.create to add a new key:data pair which will be accessible_21 // to any other Function or product with access to the Sync Map!_21 Runtime.getSync()_21 .maps('spaceShips')_21 .syncMapItems.create({_21 key: 'fastestShip',_21 data: {_21 name: 'Millenium Falcon',_21 },_21 })_21 .then((response) => {_21 console.log(response);_21 return callback(null, response);_21 })_21 .catch((error) => {_21 console.log('Sync Error: ', error);_21 return callback(error);_21 });_21};
Example of how to create Sync List with Runtime Client
_16exports.handler = (context, event, callback) => {_16 // If your use case warrants a list data structure instead of a map, you_16 // can instantiate a Sync List. As with Maps, be sure to provide a uniqueName!_16 Runtime.getSync()_16 .lists.create({_16 uniqueName: 'spaceShips',_16 })_16 .then((newList) => {_16 console.log(newList);_16 return callback(null, newList);_16 })_16 .catch((error) => {_16 console.log('Sync Error: ', error);_16 return callback(error);_16 });_16};
Example of how to append to a Sync List using the Runtime Client
_20exports.handler = (context, event, callback) => {_20 // Given an existing Sync List with the uniqueName of spaceShips, you can use_20 // syncListItems.create to append a new data entry which will be accessible_20 // to any other Function or product with access to the Sync List!_20 Runtime.getSync()_20 .lists('spaceShips')_20 .syncListItems.create({_20 data: {_20 text: 'Millennium Falcon',_20 },_20 })_20 .then((response) => {_20 console.log(response);_20 return callback(null, response);_20 })_20 .catch((error) => {_20 console.log('Sync Error: ', error);_20 return callback(error);_20 });_20};
Example of how to create a Sync Document using the Runtime Client
_19exports.handler = (context, event, callback) => {_19 // Last but not least, it's also possible to create Sync Documents._19 // As always, remember to provide a uniqueName to identify your Document._19 Runtime.getSync()_19 .documents.create({_19 uniqueName: 'userPreferences',_19 data: {_19 greeting: 'Ahoyhoy!',_19 },_19 })_19 .then((newDoc) => {_19 console.log(newDoc);_19 return callback(null, newDoc);_19 })_19 .catch((error) => {_19 console.log('Sync Error: ', error);_19 return callback(error);_19 });_19};
Example of creating a Sync Map and adding data to it in the same Function execution
_28exports.handler = async (context, event, callback) => {_28 // Grab a reference to the Sync object since we'll be using it a few times_28 const sync = Runtime.getSync();_28_28 try {_28 // First, lets create a brand new Sync Map_28 const newMap = await sync.maps.create({ uniqueName: 'quicklyUpdatedMap' });_28 console.log('newMap: ', newMap);_28_28 // Now, let's access that map and add a new item to it._28 // Be sure to specify a unique key and data for the item!_28 // Creation is an async operation, so we need to await it._28 const newMapItem = await sync.maps(newMap.sid).syncMapItems.create({_28 key: 'fastestShip',_28 data: {_28 name: 'Millenium Falcon',_28 },_28 });_28_28 // Now that we have a new item, let's log and return it._28 console.log('newMapItem: ', newMapItem);_28 return callback(null, newMapItem);_28 } catch (error) {_28 // Be sure to log and return any errors that occur!_28 console.error('Sync Error: ', error);_28 return callback(error);_28 }_28};