Due to the ephemeral nature of Functions, application state for purely serverless apps has previously been difficult to manage, or required storing such information in a remote database. Luckily, with access to cookies with Runtime Handler version 1.2.1 and later, you can now maintain limited state in your apps through cookies!
Let's create a Function named state
that leverages per-phone number cookies to store some application state, just like you would with a more traditional, server-based solution! Use the following directions to create a Service and your state
Function:
In order to run any of the following examples, you will first need to create a Function into which you can paste the example code. You can create a Function using the Twilio Console or the Serverless Toolkit as explained below:
If you prefer a UI-driven approach, creating and deploying a Function can be done entirely using the Twilio Console and the following steps:
https://<service-name>-<random-characters>-<optional-domain-suffix>.twil.io/<function-path>
test-function-3548.twil.io/hello-world
.
Your Function is now ready to be invoked by HTTP requests, set as the webhook of a Twilio phone number, invoked by a Twilio Studio Run Function Widget, and more!
_30exports.handler = (context, event, callback) => {_30 // Initialize a new Response and some TwiML_30 const response = new Twilio.Response();_30 const twiml = new Twilio.twiml.MessagingResponse();_30_30 // Cookies are accessed by name from the event.request.cookies object_30 // If the user doesn't have a count yet, initialize it to zero. Cookies are_30 // always strings, so you'll need to convert the count to a number_30 const count = Number(event.request.cookies.count) || 0;_30_30 // Return a dynamic message based on if this is the first message or not_30 const message =_30 count > 0_30 ? `Your current count is ${count}`_30 : 'Hello, thanks for the new message!';_30_30 twiml.message(message);_30_30 response_30 // Add the stringified TwiML to the response body_30 .setBody(twiml.toString())_30 // Since we're returning TwiML, the content type must be XML_30 .appendHeader('Content-Type', 'text/xml')_30 // You can increment the count state for the next message, or any other_30 // operation that makes sense for your application's needs. Remember_30 // that cookies are always stored as strings_30 .setCookie('count', (count + 1).toString());_30_30 return callback(null, response);_30};
For Twilio SMS, cookies are scoped to the "conversation" between two parties — you can have a unique cookie for each To/From phone number pair. For example, you can store a unique cookie for any messages sent between 415-555-2222 (your number, for example) and 415-555-1111 (the phone number your Function is a webhook for), which will be different from the cookie used between 415-555-3333 and 415-555-1111.
The code here is accepting an incoming Message webhook request, and checking for an incoming cookie named count
. If that cookie is not present, count
is initialized to 0, the user message is formatted to indicate the start of a conversation, and the count is incremented then set as a cookie along with the response to the sender. If count
is already present, its value is included in the message, incremented, and set so that subsequent messages can continue to store the ever-increasing value of count
.
To test this and observe your stateless Function managing to track state with cookies, you'll need to set your deployed state
Function as the webhook for your Twilio phone number, as shown next.
Cookies created in this specific scenario (Twilio forwarding SMS messages to your Function or server) are limited to a maximum lifetime of four hours, so if a conversation remains idle for more than four hours, it will be automatically cleared. If you require longer-lasting state, you will need to store it in an external source such as a database.
In any other scenario, cookies set by your Function are only subject to the usual limitations.
In order for your Function to react to incoming SMS and/or voice calls, it must be set as a webhook for your Twilio number. There are a variety of methods to set a Function as a webhook, as detailed below:
You can use the Twilio Console UI as a straightforward way of connecting your Function as a webhook:
ui
unless you have created
custom domains
), and finally
Function Path
of your Function from the respective dropdown menus.