The new way to create, develop and deploy Twilio functions

Stefan Judis - Aug 26 '19 - - Dev Community

SIGNAL, our customer and developer conference, was only a few days ago. In case you missed it, you can have a look at the keynotes from day one and day two and also many of the product sessions on YouTube.

Whilst there were many exciting product announcements (TwilioQuest 3 anyone?), there was one thing that got me up from my chair to yell “Hell yeah”!

Twilio Functions now can be deployed via API and this changes how many people will develop with Twilio.

Developing in a serverless environment can be challenging and raise many questions. How do you develop your serverless project locally? How do you deploy your functions to production? How do you structure your code in the first place?

Luckily, two product announcements answer all of these questions. In this article, I want to share how the new Serverless Toolkit and the new Twilio Runtime API will change the creation, development, and deployment flow of Twilio functions.

Before we get started…

To develop and deploy Twilio functions you need:

You can use the Serverless Toolkit as a standalone tool in the form of the npm package twilio-run, however, you can also integrate it into the Twilio CLI via the Twilio Serverless plugin. The Twilio CLI covers hundreds of Twilio features and API endpoints, pair it with the Serverless plugin and you have a tool that provides all the functionality you need.

After installing the CLI, you have the twilio command available in your environment. Ensure that you are authorized by running the following command in your terminal:

twilio login 
Enter fullscreen mode Exit fullscreen mode

If you need more info on how to get started with the Twilio CLI check out the Twilio video tip “Introducing the Twilio CLI!”.

After a fresh installation, the Twilio CLI is missing the serverless commands. To add these commands, install the serverless plugin from within the Twilio CLI itself. Run the plugin:install command:

twilio plugins:install @twilio-labs/plugin-serverless 
Enter fullscreen mode Exit fullscreen mode

After the plugin installation finishes, new commands like twilio serverless:deploy and twilio serverless:start become available right at your fingertips. 🎉

A quick note about plugin; the Twilio CLI is not only able to install plugins but it also provides the functionality to keep plugins up-to-date. The serverless plugin is still pretty new – make sure to run twilio plugins:update now and then to receive updates.

Create a new Serverless project

To get started with a new Twilio Runtime project, it only takes one command.

twilio serverless:init your-project-name 
Enter fullscreen mode Exit fullscreen mode

twilio serverless:init creates a new directory and mandatory files. It also installs all the required dependencies in one go.

twilio serverless:init serverless-tryout
✔ Creating project directory
✔ Creating project directories and files
✔ Downloading .gitignore file
✔ Installing dependencies
╭─────────────────────────────────────────────────────────────────────────────╮
│                                                                              │
│   Success!                                                                   │
│                                                                              │
│   Created serverless-tryout at /your/dir                                     │
│                                                                              │
│   Inside that directory, you can run the following command:                  │
│                                                                              │
│   npm start                                                                  │
│     Serves all functions in the ./functions subdirectory and assets in the   │
│     ./assets directory                                                       │
│                                                                              │
│   Get started by running:                                                    │
│                                                                              │
│   cd your-project-name                                                       │
│   npm start                                                                  │
│                                                                              │
╰─────────────────────────────────────────────────────────────────────────────╯
Enter fullscreen mode Exit fullscreen mode

Navigate into the new directory and have a look at the included files. It should look similar to the tree below.

.
├── assets
│   ├── index.html
│   ├── message.private.js
│   └── style.css
├── functions
│   ├── hello-world.js
│   ├── private-message.js
│   ├── sms
│   └    └── reply.protected.js
├── node_modules
│   ├──...
│   ├──...
│   └──...
├── .env
├── .gitignore
├── .nvmrc
├── package-lock.json
└── package.json
Enter fullscreen mode Exit fullscreen mode

The new project includes config files and two main directories: assets and functions. The files included in these directories map to the Twilio functions and assets that will be available online after you deploy the local files. For example, the JavaScript file ./functions/hello-world.js will be available at /hello-world.

The filename rules them all – public vs. private vs. protected access

Some of the generated functions and assets include a protected or private keyword in their filename. The Serverless Toolkit evaluates access permissions using the filename and omits the keywords in the public URL after the deployment. The file /functions/sms/reply.protected.js will result in a /sms/reply endpoint.

The access levels for functions are:

  • public (default) – publicly available
  • protected – only accessible by Twilio via, for examples, webhooks

And access levels for assets are:

  • public - publicly available
  • private - only accessible inside of functions via Runtime.getAssets()

You can have a look at all the configurations for functions and assets in the docs.

Let’s sum up the new project, it includes:

  • three assets (one of them is private and won’t be accessible publicly)
  • three functions (one of them is protected and won’t be accessible publicly)

Now it’s time to see what all of them do and run the project locally!

A fresh Twilio Runtime right on your computer

Developing local serverless projects was always a pain. Luckily, there is now a command that emulates the Twilio Runtime on your machine and makes development much more convenient.

Run twilio serverless:start inside of the project.

twilio serverless:start
┌────────────────────────────────────────────────────────────────────┐
│                                                                    │
│   Twilio functions available:                                      │
│   ├── /hello-world | http://localhost:3000/hello-world             │
│   ├── /private-message | http://localhost:3000/private-message     │
│   └── [protected] /sms/reply | http://localhost:3000/sms/reply     │
│                                                                    │
│   Twilio assets available:                                         │
│   ├── /index.html | http://localhost:3000/index.html               │
│   ├── /style.css | http://localhost:3000/style.css                 │
│   └── [private] /message.js | Runtime.getAssets()['/message.js']   │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

The twilio serverless:start command spins up a local server, creates the endpoints that would be deployed on the Runtime, and also emulates the environment by providing things like the Runtime client. Your localhost will behave like Twilio’s infrastructure! 🎉

When you visit the local endpoints, you’ll find out that all the functions respond with some TwiML covering everyday use cases like responding text to an incoming SMS. You can now take these functions and tweak them to your needs.

Two browser windows – one showing localhost:3000/index.html responding with instructions and localhost:3000/private-message returning some TwiML

For further instructions and explanations, navigate to the included asset [http://localhost:3000/index.html](http://localhost:3000/index.html). The example HTML page gives you more insights into the functions, assets, and the foundation for the serverless plugin – the underlying tool; twilio-run.

One last thing to mention about local development – twilio serverless:start offers many flags that will help you with environment variables, debugging and live-reloading. It even comes with the local tunnel tool ngrok built-in. Make sure to have a look at all the options with the command twilio serverless:start --help or read this article.

With only two commands, you were able to set up a new local serverless project that can be adjusted to specific requirements. But how do you extend the project, create new functions, and get some inspiration on how to control Twilio’s services in a serverless world?

Create new functions for other use cases

One way to add more functionality is to create additional files inside of the functions or assets directory. This process is somewhat manual, though. What if I told you that there was a quicker way to set up functions?

The command twilio serverless:new helps to reduce the number of repetitive tasks and provides a way to create new functions using pre-defined templates.

twilio serverless:new 
? Select a template
  Hello Voice - Function to get you started with Twilio Prog. Voice
  Hello Messaging - Function to get you started with Twilio Prog. Messaging
  Never gonna give you up - Never gonna let you down. Plays a song to a phone call
❯ Forward Call - Forwards an incoming call to another number
  Forward Message - Forwards incoming messages to another number
  Forward Message to Multiple Numbers - Forwards incoming messages to a set of numbers
  Forward Message to Email via SendGrid - Uses SendGrid to forward incoming messages via email
(Move up and down to reveal more choices)
Enter fullscreen mode Exit fullscreen mode

After picking a template and a namespace directory, the setup process will create new files and give hints on other setup actions. For example, the template below requires the definition of a certain environment variable.

twilio serverless:new
? Select a template Forward Call - Forwards an incoming call to another number
? What should be the namespace your function(s) are placed under? private
  ✔ Configuring Environment Variables in .env
  ✔ Installing Dependencies
  ✔ Creating function: forward-call.js
INFO Make sure to configure MY_PHONE_NUMBER in the .env file
SUCCESS Downloaded new template into the "new-service" subdirectories
Enter fullscreen mode Exit fullscreen mode

What function use cases would you like to see? All function templates are available and editable on GitHub – we’d love to hear your ideas!

After creating a new function, restart the local server by running twilio serverless:start again. The new endpoint will be available locally. For the above function, this endpoint is /private/forward-call.

Local development is only half of the story – how do you deploy functions to the cloud, ready to scale?

Showtime – deploy, deploy, deploy!

When you’re happy with your local functions and assets run twilio serverless:deploy to deploy them.

twilio serverless:deploy

Deploying functions & assets to the Twilio Runtime

Account         SK6b3e6df6812298f87594567895e55ede
Token           kegH****************************
Service Name    serverless-tryout
Environment     dev
Root Directory  /private/tmp/serverless-tryout
Dependencies
Env Variables   MY_PHONE_NUMBER

✔ Serverless project successfully deployed

Deployment Details
Domain: serverless-tryout-6774-dev.twil.io
Service:
   serverless-tryout (ZSc...)
Environment:
   dev (ZEa...)
Build SID:
   ZB8...
Functions:
   [protected] https://foo-6774-dev.twil.io/sms/reply
   https://serverless-tryout-6774-dev.twil.io/hello-world
   https://serverless-tryout-6774-dev.twil.io/forward-call/forward-call
   https://serverless-tryout-6774-dev.twil.io/private-message
Assets:
   [private] Runtime.getAssets()['/message.js']
   https://serverless-tryout-6774-dev.twil.io/index.html
   https://serverless-tryout-6774-dev.twil.io/style.css
Enter fullscreen mode Exit fullscreen mode

This one command deploys the code to the cloud and creates publicly available assets and function endpoints.

If you want to inspect the deployed runtime, there are two ways to do this. The first one is using the twilio serverless:list command:

twilio serverless:list functions --service-sid=ZSc7...
Account      SK6b...
Token        kegH****************************
Service      ZSc7...
Environment  dev

Functions for environment ZEa5...

│ /sms/reply [Visibility protected]
│ /hello-world
│ /private-message
│ /forward-call/forward-call
Enter fullscreen mode Exit fullscreen mode

This command accepts several configuration options so that you can inspect the exact area of your interest. If you want to see what flags are available, remember the --help flag will be your friend.

The other way is to head to the functions API area in your Twilio console and have a look there.

Twilio Console showing the read-only UI for Twilio API deployed functions

A more in-depth look at the created endpoints and their new domain explicitly shows how the new Function and Assets API is structured and how it differs from the UI-only Twilio functions. Let’s have a brief look.

New power and flexibility with environments

The domain of the freshly deployed service unveils one significant improvement that comes with the new API that was not available before.

                      Random number
                          \  /
https://serverless-tryout-6774-dev.twil.io/sms/reply
        \        /             \ /
       Service name        Environment
                          Domain suffix                                  
Enter fullscreen mode Exit fullscreen mode

The Serverless API supports environments. When you deployed your project a few minutes ago, the CLI used a default value as the environment – dev. Every environment is represented by its own domain. To deploy another environment, use the --environment flag with the serverless:deploy command.

The environment feature may not look like a big deal now, but in the future, it will be. When you run large projects with many developers working on the same serverless codebase, environments are crucial.

Thanks to environments, you can test and deploy changes in isolation to their own domain without affecting your production setup. Then, only when you’re ready to switch, you can promote one environment to another (e.g. dev to prod) using the command twilio serverless:activate. Environments are a big step towards automation and the implementation of proper CI/CD workflows – both, mandatory processes when you’re running on a bigger scale.

If you want to have a look at how all the pieces of the new API come together, have a look at the reference documentation or Dominik Kundels presentation around the topic.

The automation of your Twilio setup

The new Twilio Runtime API paired with the Serverless toolkit is the missing piece to automate tasks in your existing infrastructure and even create new installations from scratch.

What if I would tell you that you can now buy numbers, create sync services, connect your communication channels via functions by running a single command? In short, do all things Twilio-related by just running a shell script. Well… I did precisely this just a few days ago, and it made me get out of my chair saying, “Hell yeah!”. Watch the space, I’ll keep you posted about how to script Twilio setups in the following tutorials. 👋

Let me know if you're as excited as me about this new API. You can reach me under the following channels.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .