Azure Functions: Calling APIs with Slack slash commands

Torjus Hansen Sæthre
Bredvid
Published in
6 min readApr 21, 2021

--

An Azure Function is a quick and easy way to create a serverless backend. To demonstrate, we are going to create a Slack app with a slash command that consumes an external API with the help of an Azure Function.

Create your function

Before you can begin creating your Azure Function you will need an Azure subscription, or simply create a free one. This article will create a function using the Azure Portal.

Firstly we need a Function App:

Click on create a resource and locate the Function App.

Add the Function App to a resource group of your choice or create a new one. Give your function a globally unique name, runtime stack and a location close to your intended users. Our function will be made using Node.js. Finally, simply hit create and grab a coffee while your function app is being deployed.

Once your function app is deployed it is time to create our Azure Function. Locate Functions in the left menu and click Add,

Select your preferred development environment. This article will use the portal.

A Function needs a single trigger. The trigger decides when the function should run. A function can be called by a timer, by events in other Azure resources, or in this example, by an HTTP request.
Selecting the HTTP Trigger template, will give us a nice piece of code to get started.

Name your function and click Add.

Now let’s take a look at our function by pressing the Code + Test button. We now have two files: index.js and function.json.

index.js is where we will add our function logic, while function.json is our setup file where we can define our triggers, binding and other configurations.

We can test our function by clicking Test/Run or by getting the function URL in the top menu and make a request with a tool like curl. As we can see in our function code it looks for a query parameter name and gives us a custom response if it is provided.

Requesting the function

Creating a Slash command in Slack

Having confirmed that our Azure function is up and running it is time to create our Slack App. Go to https://api.slack.com/apps, sign in to your workspace and click Create New App.

Navigate to Slash Commands and create your command. Give the command a fitting name and paste the function url that you tested earlier into the request URL.

Go back to your app’s Basic Information and install it to your workspace. Optionally you can scroll further down on the page and give your app some display information like a nice looking icon.

Now head over to Slack and give your newly created App a go!

A simple request to the app works wonders!
..it does however not consider your input.

Receiving Slack Commands

Now we need to edit our function in order to receive and process the inputs from Slack.

From the Slack documentation we can read that Slack sends a HTTP POST to the url we specified above, containing detailed data about where it came from.

Highlighted in the example to the left are the two parameters we will consider in this example.

text : The user input after the command.
response_url : The url we will respond to.

Let us make some quick changes to our function code so that it reads the request parameters and sends the user input back.

Now it reads and responds to our input

Consuming an API

When Slack sends a request to our Azure function, it expects a response. If Slack does not receive that response within 3 seconds, it will timeout and send the user an ugly error message. Since we intend to call a third party API from our Azure function that may take more than 3 seconds we should:

  1. Acknowledge the Slack request.
  2. Make a request to third party API.
  3. Respond to slack with API results.

The first acknowledgement should, depending on the use case and expected response time from the API, be an empty HTTP 200 response or a simple message telling the user what is going on.

Let’s add some code to call our api and send a response to Slack.

For consuming the API and posting a response to Slack, this example uses axios. Adding dependencies to your app can be done in multiple ways, but I found the command line in Kudu to be a useful tool. It can be found at https://<func_app_name>.scm.azurewebsites.net.

Returning a nice, formatted message to Slack can be done using blocks. Blocks allow our bot to return markdown text or even interactive elements to further enhance the app experience. Their own guide on composing messages is a great place to start. Under is a “blockifying” function created for this project.

The complete index.js file can be found here and gives the user this neat response 🎉

Cold starts

A thing you might notice is that the app occasionally does not respond within the 3 seconds, even though your function code sends an acknowledgement immediately. This might be due to a cold start.

When a function app on a consumption plan has not been run in a while, its infrastructure is likely to be deallocated. Any subsequent request to that function will then experience a cold start.

A cold start will from my experience in most cases surpass the 3 second timeout of our Slack request. The only way of avoiding cold starts with 100% certainty is by running your functions on dedicated infrastructure, which again comes with a higher cost.

We can however seek to mitigate both the cold start time, and the chance of a cold start happening.

One idea is to create a pinger function in the same app to keep our function warm.

source: https://mikhail.io/serverless/coldstarts/azure/
Source: https://mikhail.io/serverless/coldstarts/azure/

There is no exact time for how long a function stays warm after a request, but this article provides a nice chart on the probability of a cold start happening after x minutes.

Create another Azure function with a Timer Trigger that fires every 5 minutes, and calls our other Http triggered function. A Timer trigger is controlled by a cron expression and can look something like this "0 */5 6–23 * *" which fires at 0 seconds of every 5 minutes between the hours of 6 and 23.

One might think that it is unnecessary to make a request to our other function as warming the app should be sufficient, but in my experience functions under the same app can be warm and cold at the same time.

Another way to reduce cold start times which Microsoft recognize in their documentation is by running you functions as a package file. Microsoft state that this can significantly improve the cold start times of JavaScript functions with large dependency trees in particular. This actually did wonders for my node application and I have not experienced a single timeout from the slack command since running the app from a package, as opposed to very frequent timeouts when only using the pinger function.

Cold starts are affected by language, operating system, deployment method, package size, dependencies and probably a lot more. It is a central part of serverless computing, and there are multiple articles, blog posts and documentation on the matter with often conflicting conclusions. Mitigating it is however very important for this use case.

--

--