# Use the Run Function widget in Studio

With their lightweight nature and ability to execute JavaScript, Functions are an excellent companion to [Studio Flows](/docs/studio). Whether you need to gather some data from an API or run any other custom code to fit your business logic, Functions help to fill in the gaps in your application that existing [Studio widgets](/docs/studio/widget-library) may not cover.

In order to ease the integration of Functions into your Studio Flows, Studio provides the [Run Function](/docs/studio/widget-library/run-function) widget. This widget, as the name implies, allows you to run a Twilio Function; you may pass in any desired parameters, and leverage any generated values later on in your Studio Flow.

To test this out we'll create a Studio Flow that accepts incoming text messages, prompts the user for their desired dog breed, and returns an MMS containing some text and an image of their requested breed (assuming they provided a valid breed). The finished flow would look like this:

![Twilio Studio flow with steps: request-breed, get-doge-, and send-doge for dog request.](https://docs-resources.prod.twilio.com/fb6cbf887eec54bc01fa2777ec6bf5fe7c3d1f9e3732f00191103246ef5741fa.png)

## Create a Studio Flow and a user prompt

If you haven't created a Flow before, we suggest following the [Create Your Flow](/docs/studio/tutorials/how-to-build-a-chatbot#create-your-flow) steps in the chatbot tutorial to get one established.

Once you are inside of your newly created Studio Flow, create the prompt for dog breed by dragging a [Send & Wait For Reply](/docs/studio/widget-library/send-wait-reply) widget onto the Studio canvas. Name it and provide some text to prompt the user; the text can be anything you'd like for this example, something along the general lines of "which dog breed would you like to see?"

Here, we'll name the widget `request-breed`, and provide the following prompt:

```bash
Hello! Please respond with your requested dog breed to receive a photo! 🐶
```

Before we can proceed any further, we must first create the Function that we'll be calling in the next step of the Flow.

## Create and host a 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](/docs/labs/serverless-toolkit) as explained below:

## Console

If you prefer a UI-driven approach, creating and deploying a Function can be done entirely using the Twilio Console and the following steps:

1. Log in to the Twilio Console and navigate to the [Functions tab](https://www.twilio.com/console/functions/overview). If you need an account, you can sign up for a free Twilio account [here](https://www.twilio.com/try-twilio)!
2. Functions are contained within **Services**. Create a **[Service](/docs/serverless/functions-assets/functions/create-service)** by clicking the **[Create Service](https://www.twilio.com/console/functions/overview/services)** button and providing a name such as *test-function*.
3. Once you've been redirected to the new Service, click the **Add +** button and select **Add Function** from the dropdown.
4. This will create a new [Protected](/docs/serverless/functions-assets/visibility) Function for you with the option to rename it. The name of the file will be path it is accessed from.
5. Copy any one of the example code snippets from this page that you want to experiment with, and paste the code into your newly created Function. You can quickly switch examples by using the dropdown menu of the code rail.
6. Click **Save** to save your Function's contents.
7. Click **Deploy All** to build and deploy the Function. After a short delay, your Function will be accessible from: `https://<service-name>-<random-characters>-<optional-domain-suffix>.twil.io/<function-path>`\
   For example: `test-function-3548.twil.io/hello-world`.

## Serverless Toolkit

The [Serverless Toolkit](/docs/labs/serverless-toolkit) enables you with local development, project deployment, and other functionality via the [Twilio CLI](/docs/twilio-cli/quickstart). To get up and running with these examples using Serverless Toolkit, follow this process:

1. From the CLI, run `twilio serverless:init <your-service-name> --empty` to bootstrap your local environment.
2. Navigate into your new project directory using `cd <your-service-name>`
3. In the `/functions` directory, create a new JavaScript file that is named respective to the purpose of the Function. For example, `sms-reply.protected.js` for a [Protected](/docs/serverless/functions-assets/visibility) Function intended to handle incoming SMS.
4. Populate the file using the code example of your choice and save. **Note** A Function can only export a single handler. You will want to create separate files if you want to run and/or deploy multiple examples at once.

Once your Function(s) code is written and saved, you can test it either by running it locally (and optionally tunneling requests to it via a tool like [ngrok](https://ngrok.com/)), or by deploying the Function and executing against the deployed url(s).

### Run your Function in local development

Run `twilio serverless:start` from your CLI to start the project locally. The Function(s) in your project will be accessible from `http://localhost:3000/sms-reply`

* If you want to test a Function as a [Twilio webhook](/docs/usage/webhooks/getting-started-twilio-webhooks), run: `twilio phone-numbers:update <your Twilio phone number> --sms-url "http://localhost:3000/sms-reply"`\
  This will automatically generate an ngrok tunnel from Twilio to your locally running Function, so you can start sending texts to it. You can apply the same process but with the `voice-url` flag instead if you want to test with [Twilio Voice](/docs/voice).
* If your code does *not* connect to Twilio Voice/Messages as a webhook, you can start your dev server and start an ngrok tunnel in the same command with the `ngrok` flag. For example: `twilio serverless:start --ngrok=""`

### Deploy your Function

To deploy your Function and have access to live url(s), run `twilio serverless:deploy` from your CLI. This will deploy your Function(s) to Twilio under a development environment by default, where they can be accessed from:

`https://<service-name>-<random-characters>-dev.twil.io/<function-path>`

For example: `https://incoming-sms-examples-3421-dev.twil.io/sms-reply`

Your Function is now ready to be invoked by HTTP requests, set as the [webhook](/docs/usage/webhooks/getting-started-twilio-webhooks) of a Twilio phone number, invoked by a Twilio Studio **[Run Function Widget](/docs/studio/widget-library/run-function)**, and more!

## Install Dependencies and define the Function body

Studio Widgets can handle the elements of gathering user input and sending back a response text. However, custom logic like handling breed names that contain spaces lives best inside of a Function.

Let's add some code to this Function. Install `axios` as a [Dependency](/docs/serverless/functions-assets/functions/dependencies), copy the following code example into your Function, save, and deploy your Service so that we can look more closely at how to integrate the Run Widget into a Studio Flow.

Note that this Function expects an input of `breed`, and returns JSON that includes some `text` and an image `url`.

> \[!NOTE]
>
> If you're curious about why we're using `axios` and keywords such as `async` and `await`, be sure to read up on [how to make API requests in Functions](/docs/serverless/functions-assets/quickstart/api-request).

```js title="Return JSON to a Studio Flow based on input parameters"
const axios = require('axios');

exports.handler = async (context, event, callback) => {
  // Any parameters provided to the Function will be accessible from `event`.
  // In Function Parameters, we defined `breed` as the inbound Body from
  // our Send & Wait For Reply Widget. We can access that via `event.breed`.
  // To minimize the potential for errors, lowercase and trim the user input.
  let dogBreed = event.breed.toLowerCase().trim();

  // The Dog API also supports sub-breeds, so we need to handle that case.
  // For example, if the user requests "Golden Retriever", we need to format
  // the breed as "retriever/golden".
  if (dogBreed.includes(' ')) {
    const [subBreed, breed] = dogBreed.split(' ');
    dogBreed = `${breed}/${subBreed}`;
  }

  const dogApiUrl = `https://dog.ceo/api/breed/${dogBreed}/images/random`;

  try {
    // Make the request to the Dog API. Remember to use `await` since this
    // is an asynchronous request!
    const response = await axios.get(dogApiUrl);
    // Return the response to the Send & Wait For Reply Widget.
    return callback(null, {
      text: `Here's an image of a ${event.breed}! 🐶`,
      // The `message` property of the response is the URL of the dog image.
      url: response.data.message,
    });
  } catch (error) {
    // Remember to handle any errors that may occur!
    // In the case of a 404, the breed was not found.
    if (error.response && error.response.status === 404) {
      return callback(null, {
        text: `Sorry, we couldn't find any ${event.breed}s 🥲`,
      });
    }
    // Otherwise, there may have been a network or server error.
    return callback(error);
  }
};
```

## Use the Run Function widget

Once your prompt is complete, drag a [Run Function](/docs/studio/widget-library/run-function) widget onto the canvas, and connect it to the `Reply` condition of the `request-breed` widget.

You'll be able to provide a name for the widget (`get-doge-image`), a configuration that will point this widget at your intended Function, and any parameters or arguments that you'd like to pass from the Flow to the Function when it's executed.

For this example, we'll point the Run Function widget at our Function, which was deployed to the `doge` Service in a production environment, and the path to the Function is `/get-doge`. Replace the Service, Environment, and Function configuration options with the values specific to the Function you created earlier.

![Flow diagram with Run Function widget calling get-doge function using breed parameter.](https://docs-resources.prod.twilio.com/57d777cb1509522026cb3096a92a3504848d2466357e6108733f4d1cac1c1139.png)

The final important configuration to note is the section labeled **Function Parameters**. Here, we define the parameters that we will pass to the Function's `event` object.

Here, we want to provide a variable called `breed` which is equal to the user's response to the prompt. We can do this by creating a new parameter, naming it `breed`, and setting the value to the user's response to the `request-breed` widget.

> \[!NOTE]
>
> We are using the Liquid template language to set a variable to the value gathered by the `request-breed` widget. Read the [Studio guide on Liquid](/docs/studio/user-guide/liquid-template-language) to learn more about this syntax and what else you can do with these expressions!

## Consume the output of the Run Function widget

With our prompt and Run Function widgets in place, the last step is to generate a response to the user which incorporates the Function's result.

Drag a [Send Message](/docs/studio/widget-library/send-message) widget onto the canvas, and connect it to the `Success` condition of the `get-doge-image` widget.

The configuration for this widget is much shorter, and consists only of a name for the widget, the text body, and any media URL (s) you may want to attach. Luckily, the `/get-doge` Function returns `text` and `uri` values for us, so we can template these values into the config using [Liquid](/docs/studio/user-guide/liquid-template-language).

In order to access the return value of a Run Function widget, you will need to access a special property called `parsed`. This object will contain any and all contents returned by the targeted Function.

> \[!NOTE]
>
> The general syntax to access a property from the result of a Run Function widget is `{{widgets.<widget-name>.parsed.<property>}}`.

For example, to access the `text` and `url` returned from the `get-doge-image` widget, the respective Liquid template strings would be the following:

```bash
{{widgets.get-doge-image.parsed.text}}
{{widgets.get-doge-image.parsed.url}}
```

Once you have set **Message Body** to `{{widgets.get-doge-image.parsed.text}}` and **Media URL** to `{{widgets.get-doge-image.parsed.url}}` on the Send Message widget, your configuration should look like this:

![Flowchart showing get-doge- function and send-doge message configuration with liquid template values.](https://docs-resources.prod.twilio.com/c4d76302ce943d5b8a1bb59546da381516775118e8c4b20b847943c58a4dca93.png)

## Test it

With the Function deployed and all the widgets in the Studio Flow connected and configured, all that's left is to see this little application in action. To save all your progress on the Flow and ensure that its code is live, click **Publish** on the Studio canvas.

Next, [connect one of your Twilio phone numbers to this Flow](/docs/studio/user-guide/get-started#configure-a-twilio-phone-number-to-connect-to-a-studio-flow).

Once you have published your Flow and connected it to your Twilio phone number, send it a brief message to start the conversation. A simple "Ahoy!" will do. Respond to the incoming prompt with a breed of dog, and you will see an MMS of that breed after a momentary delay.

![Chatbot conversation showing a golden retriever request and response.](https://docs-resources.prod.twilio.com/739cdb68721dedba77ba90d69562c89cccfebb9de32c496ea8d9c3502e9b7721.jpg)

## Go further with loops and failure flows

So far, while the Function code does contain some catch logic, it otherwise doesn't really have any resilience to missing breed types or even network errors, and it definitely doesn't show that to the user. To improve the experience, let's see what happens if we expand our flow to handle the fail condition of `get-doge-image`.

To get started, drag a new Send Message widget onto the canvas, give it a name such as `send-fail-message`, and connect it to the `Fail` transition from `get-doge-image`. By doing this, we're introducing an alternative flow of logic for our application in case the Function runs into an error.

To take this a step further, connect the `Sent` condition of the newly made `send-fail-message` to `get-doge-image`. In doing so, you've just created a loop! If the Function fails to get a dog image, the flow will send the user a message then try to re-run the Function, and will do so until it succeeds.

Set the message body to `{{widgets.get-doge-image.body}} Trying again!`, click **Save**, and finally click **Publish** to publish this update to the flow.

These connections and the configuration for `send-fail-message` should appear as shown below:

![Flowchart showing a retry loop with request-breed, get-doge-, and send-fail-message widgets.](https://docs-resources.prod.twilio.com/30f6bc37a7548ad7297d4769d4d1500961b04befb6e4bf3bebdb2df22513ea56.png)

With the flow updated to handle failures from our Function, let's quickly edit our code to make it artificially error-prone; only for the sake of testing, of course!

```js title="Randomly return an error instead of JSON"
// !mark(20,21,33,34)
const axios = require('axios');

exports.handler = async (context, event, callback) => {
  // In Function Parameters, we defined `breed` as the inbound Body from
  // our Send & Wait For Reply Widget. We can access that via `event.breed`.
  // To minimize the potential for errors, lowercase and trim the user input.
  let breed = event.breed.toLowerCase().trim();

  // The Dog API also supports sub-breeds, so we need to handle that case.
  // For example, if the user requests "Golden Retriever", we need to format
  // the breed as "retriever/golden".
  if (breed.includes(' ')) {
    const [first, second] = breed.split(' ');
    breed = `${second}/${first}`;
  }

  const dogApiUrl = `https://dog.ceo/api/breed/${breed}/images/random`;

  try {
    // Let's introduce some inconsistency by randomly throwing an error
    if (Math.random() > 0.3) throw new Error('No doge~');
    // Make the request to the Dog API. Remember to use `await` since this
    // is an asynchronous request!
    const response = await axios.get(dogApiUrl);
    // Return the response to the Send & Wait For Reply Widget.
    return callback(null, {
      text: `Here's an image of a ${event.breed}! 🐶`,
      // The `message` property of the response is the URL of the dog image.
      url: response.data.message,
    });
  } catch (error) {
    // Remember to handle any errors that may occur!
    // This error message will be accessible as `widgets.get-doge-image.body`
    return callback(`Sorry, we couldn't find any ${event.breed}s 🥲`);
  }
};
```

> \[!NOTE]
>
> To get access to a returned error message, you will need to access the `body` property returned by the Run Function Widget. This will look like `{{widgets.<widget-name>.body}}` if used in a liquid template.

Deploy your Function with this updated code, and once completed, send a new message to your Twilio phone number. Between this code change and the new widget in the Studio flow, you will (most likely, this is random, of course) see one or more error messages, ultimately followed by an image of your requested dog breed!

![Chatbot conversation requesting a Vizsla , showing a Vizsla in an office.](https://docs-resources.prod.twilio.com/509282620f794e4dc6d2d862d733c1d5ce847dbddf08f9d57e26964488870927.jpg)

This is a very brief introduction to what is possible! Instead of a retry loop with a message, you could create an entirely new, logical flow of widgets where you ask the user for other information; your imagination is the only true limit here.
