Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

How to call Twilio Functions from a Flex plugin


This is a guide on how to securely call a Twilio Function from a Flex Plugin. This tutorial builds off of the Plugin from the Plugin Development Quickstart.

Flex provides some common SDK endpoints that you can use, but it doesn't make every Twilio API available to you. Fortunately, you can use Twilio Functions to decide exactly which Twilio APIs you need, make requests to them, and return the results to Flex.

This tutorial requires that you have an existing Flex Plugin. You'll write a Twilio Function that gets the cumulative statistics of all workers in a workspace and passes that data to your Flex Plugin.

(warning)

Warning

Currently, Flex Plugins can only make application/x-www-form-urlencoded requests to Twilio Functions. Nested objects are not supported.


Creating a Twilio Function

creating-a-twilio-function page anchor

First, you'll need to write a Twilio Function. The Function below returns cumulative statistics from a TaskRouter Workspace using the NodeJS Helper Library(link takes you to an external page).

Head over to Twilio Functions Console(link takes you to an external page) page. You can create a new Service, or use an existing Service that you already have. Add a Function, and paste the following code into it:


_33
exports.handler = function(context, event, callback) {
_33
// Add the NodeJS Helper Library by calling context.getTwilioClient()
_33
const client = context.getTwilioClient();
_33
_33
// Create a custom Twilio Response
_33
// Set the CORS headers to allow Flex to make an HTTP request to the Twilio Function
_33
const response = new Twilio.Response();
_33
response.appendHeader('Access-Control-Allow-Origin', '*');
_33
response.appendHeader('Access-Control-Allow-Methods', 'OPTIONS, POST, GET');
_33
response.appendHeader('Access-Control-Allow-Headers', 'Content-Type');
_33
_33
// Use the NodeJS Helper Library to make an API call.
_33
// Note how you are passing the workspace SID using a key from the event parameter.
_33
client.taskrouter.v1
_33
.workspaces(event.WorkspaceSid)
_33
.workers()
_33
.cumulativeStatistics()
_33
.fetch()
_33
.then(data => {
_33
response.appendHeader('Content-Type', 'application/json');
_33
response.setBody(data);
_33
// Return a success response using the callback function.
_33
callback(null, response);
_33
})
_33
.catch(err => {
_33
response.appendHeader('Content-Type', 'plain/text');
_33
response.setBody(err.message);
_33
response.setStatusCode(500);
_33
// If there's an error, send an error response
_33
// Keep using the response object for CORS purposes
_33
callback(null, response);
_33
});
_33
};

Name your Function something meaningful like Cumulative Report and give it the URI of /cumulative. Before saving, make sure the checkbox Check for valid Twilio signature is unchecked; we'll come back on how to secure your Function later on. Now save your Function and wait for it to deploy.

Cumulative function.

Configure and Test Your Function

configure-and-test-your-function page anchor

Visit the Functions Configuration Page(link takes you to an external page) and ensure that the Enable ACCOUNT_SID and AUTH_TOKEN option is checked. Enabling this checkbox allows context.getTwilioClient(); to generate a new Twilio client using your account credentials. Save the page.

Now, try testing your Function. Your domain will be a hyphenated string of random words and numbers and can be found at the top of the Function Editor. You can find your Workspace SID by visiting TaskRouter Workspaces(link takes you to an external page) page.

Visit the Function URL using the browser of your choice. Add the query parameter ?WorkspaceSid=WSxxx and the browser should make a GET request to your Function. For example, visiting

https://YOUR_DOMAIN.twil.io/cumulative?WorkspaceSid=WSxxx

should yield:


_20
{
_20
...
_20
"activityDurations": [{
_20
"avg": 900,
_20
"min": 900,
_20
"max": 900,
_20
"friendly_name": "Available",
_20
"sid": "WAxxx",
_20
"total": 900
_20
},
_20
...
_20
]
_20
"reservationsCreated": 0,
_20
"reservationsAccepted": 0,
_20
"reservationsRejected": 0,
_20
"reservationsTimedOut": 0,
_20
"reservationsCanceled": 0,
_20
"reservationsRescinded": 0
_20
...
_20
}


Call your Function from a Flex Plugin

call-your-function-from-a-flex-plugin page anchor

To get this data into Flex, you'll need to modify your Plugin code using the Plugin Builder(link takes you to an external page). In your text editor of choice, open the folder that contains your Plugin.

(information)

Info

Somewhere in your Plugin, you'll need to make a call to your Function. You can use the native fetch Web API(link takes you to an external page) to make a request to your function.

For our Plugin, we're going to change the GET request to a POST request. Even though we're ultimately going to retrieve data about our TaskRouter Workspace, the Plugin is invoking a Function, not retrieving the data directly. Given that we might want to send a lot of data at some point, using a POST request scales better, as well. Finally, POST request bodies are easier to work with than query parameters.

For a Plugin called YourPlugin, here's what YourPlugin.js might look like:


_37
import { FlexPlugin } from 'flex-plugin';
_37
import React from 'react';
_37
_37
const PLUGIN_NAME = 'YourPlugin';
_37
_37
export default class YourPlugin extends FlexPlugin {
_37
constructor() {
_37
super(PLUGIN_NAME);
_37
}
_37
_37
/**
_37
* This code is run when your plugin is being started
_37
* Use this to modify any UI components or attach to the actions framework
_37
*
_37
* @param flex { typeof import('@twilio/flex-ui') }
_37
* @param manager { import('@twilio/flex-ui').Manager }
_37
*/
_37
_37
init(flex, manager) {
_37
// Describe the body of your request
_37
const body = { WorkspaceSid: 'WSxxx' };
_37
_37
// Set up the HTTP options for your request
_37
const options = {
_37
method: 'POST',
_37
body: new URLSearchParams(body),
_37
headers: {
_37
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
_37
}
_37
};
_37
_37
// Make the network request using the Fetch API
_37
fetch('https://YOUR_DOMAIN.twil.io/cumulative', options)
_37
.then(resp => resp.json())
_37
.then(data => console.log(data));
_37
}
_37
}

When you run your Plugin, you should see the API response logged to the browser console!


Securing your Twilio Function

securing-your-twilio-function page anchor

Your Function currently is publically accessible, so anyone on the internet can invoke it! No need to fear, though: you can secure it by using the JSON Web Token(link takes you to an external page) (JWT) from your Flex instance and then validating the token inside your Function.

Update the fetch code to also include the JWT in the request body:


_38
import { FlexPlugin } from 'flex-plugin';
_38
import React from 'react';
_38
_38
const PLUGIN_NAME = 'YourPlugin';
_38
_38
export default class YourPlugin extends FlexPlugin {
_38
constructor() {
_38
super(PLUGIN_NAME);
_38
}
_38
_38
/**
_38
* This code is run when your plugin is being started
_38
* Use this to modify any UI components or attach to the actions framework
_38
*
_38
* @param flex { typeof import('@twilio/flex-ui') }
_38
* @param manager { import('@twilio/flex-ui').Manager }
_38
*/
_38
_38
init(flex, manager) {
_38
// Add the Token using the Flex manager
_38
const body = {
_38
WorkspaceSid: 'WSxxx',
_38
Token: manager.store.getState().flex.session.ssoTokenPayload.token
_38
};
_38
_38
const options = {
_38
method: 'POST',
_38
body: new URLSearchParams(body),
_38
headers: {
_38
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
_38
}
_38
};
_38
_38
fetch('https://YOUR_DOMAIN.twil.io/cumulative', options)
_38
.then(resp => resp.json())
_38
.then(data => console.log(data));
_38
}
_38
}

Note the only thing changed here is the addition of the Token key to the body parameter.

Now, it's easy to update your Function so that it can verify this token. Visit the Functions Configuration(link takes you to an external page) page, and scroll to the bottom of the page. Visit the twilio-flex-token-validator package(link takes you to an external page) page on the npm registry to find the current version of the package. Once you know the version, add twilio-flex-token-validator and its current version to your Dependencies. Save the page.

Return to your cumulative Function and import functionValidator from the twilio-flex-token-validator module. Then, wrap your Function with it:


_35
const TokenValidator = require('twilio-flex-token-validator').functionValidator;
_35
_35
exports.handler = TokenValidator(function(context, event, callback) {
_35
// Add the NodeJS Helper Library by calling context.getTwilioClient()
_35
const client = context.getTwilioClient();
_35
_35
// Create a custom Twilio Response
_35
// Set the CORS headers to allow Flex to make an HTTP request to the Twilio Function
_35
const response = new Twilio.Response();
_35
response.appendHeader('Access-Control-Allow-Origin', '*');
_35
response.appendHeader('Access-Control-Allow-Methods', 'OPTIONS POST GET');
_35
response.appendHeader('Access-Control-Allow-Headers', 'Content-Type');
_35
_35
// Use the NodeJS Helper Library to make an API call.
_35
// Note how you are passing the workspace SID using a key from the event parameter.
_35
client.taskrouter.v1
_35
.workspaces(event.WorkspaceSid)
_35
.workers()
_35
.cumulativeStatistics()
_35
.fetch()
_35
.then(data => {
_35
response.appendHeader('Content-Type', 'application/json');
_35
response.setBody(data);
_35
// Return a success response using the callback function.
_35
callback(null, response);
_35
})
_35
.catch(err => {
_35
response.appendHeader('Content-Type', 'plain/text');
_35
response.setBody(err.message);
_35
response.setStatusCode(500);
_35
// If there's an error, send an error response
_35
// Keep using the response object for CORS purposes
_35
callback(null, response);
_35
});
_35
});

The TokenValidator reads the Token parameter and validates it. If the token is invalid, the validator will respond with a 403. If the token is valid, then your code will execute.

Congratulations! You now have a secure Function that you can invoke from your Flex Plugin!


Rate this page: