Skip to main content

Microsoft

Twilio Functions – Common Cases

Twilio Functions are the glue that connect user code and Studio to the Twilio environment. They offer a convenient way to execute JavaScript while remaining inside of the Twilio ecosystem.  Functions have access to environment variables and shared NPM packages.  Functions also have access to the Twilio REST Helper Library. With this Studio flows can be extended to access more APIs.  This article provides a few common cases we encountered building Twilio offerings for clients.  It also builds upon Understanding Twilio Studio Flow.

Supporting CORS

It may become necessary to make a request from a domain external to the Twilio project.  To support Cross-Origin Resource Sharing, CORS, responding to OPTIONS request is necessary.  To achieve this consider the following example:

exports.handler = function(context, event, callback) {
const response = new Twilio.Response();
response.appendHeader('Access-Control-Allow-Origin', '*');
response.appendHeader('Access-Control-Allow-Methods', 'GET, OPTIONS, PUT, POST, DELETE');
response.appendHeader('Access-Control-Allow-Headers', 'Content-Type');
// check if the event has any data and if not assume this is the OPTIONS request
if (Object.keys(event).length === 0) {
response.setStatusCode(200);
callback(null, response);
} else {
// call method here to do actual work
method(context, event, callback, response);
}
};
view raw cors.js hosted with ❤ by GitHub

The above code relies on the assumption that all OPTIONS requests will have no request body, event is an empty object. This assumption breaks down when dealing with GET requests. A GET request will have no request body. It is possible to support GET, but it would require duplicating the work in both the OPTIONS and GET. I would suggest sticking to CORS-enabled POST request for Twilio Functions that need to be accessed outside of the Twilio environment.

Calling Other Twilio Functions and Assets

Twilio Functions have access to the Runtime Client which provides access to Functions, Assets, and Sync.  For now let us ignore Sync and focus on Functions and Assets.  A typical Twilio Function will export a handler method.  Using the Runtime Client we can get the path of that function and proceed to load that module and call:

exports.handler = function(context, event, callback) {
let path = Runtime.getFunctions()['function_name'].path;
let fn = require(path);
fn.handler(context, event, (error, response) => {
if (error) {
console.log(error);
// handle error case
} else {
console.log(response);
// handle response
}
});
};
view raw fn.js hosted with ❤ by GitHub

Putting common functionality into Assets is another way to share code across Twilio Functions.  The code below handles loading an asset JavaScript and calling a method exposed via exports.

function log (data, message) {
try {
if (data && data.debug) {
console.log(message);
}
} catch (error) {
console.log(`Encountered error logging: ${error.message}`);
}
}
module.exports = {
log
};
view raw asset.js hosted with ❤ by GitHub
exports.handler = function(context, event, callback) {
let path = Runtime.getAssets()['asset.js'].path;
let assetJS = require(path);
assetJS.log({
debug: true
}, 'asset test message');
callback(null, {});
};
view raw fn.js hosted with ❤ by GitHub

A or B

This method has helped in numerous Studio cases where two paths converge and only one value will be present in the Twilio Function call.  It handles both JSON and raw data values.

function AorB (event) {
try {
console.log(JSON.stringify(event));
} catch {
// no-op
}
let response = new Twilio.Response();
response.setStatusCode(200);
let body;
if (event.a) {
body = event.a;
} else if (event.b) {
body = event.b;
} else {
console.log('a and b both undefined');
}
console.log(`responding with body: ${body}`);
if (event.json && event.json.toLowerCase() == 'true') {
response.appendHeader('Content-Type', 'application/json');
body = JSON.parse(body);
}
response.setBody(body);
return response;
}
view raw aorb.js hosted with ❤ by GitHub

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Shelby Hagman

More from this Author

Categories
Follow Us
TwitterLinkedinFacebookYoutubeInstagram