funcy — a Serverless Slack App using Fn

Abhishek Gupta
Fn Project
Published in
6 min readApr 9, 2019

I love the extensibility that Slack provides via Apps — it’s a rich ecosystem consisting of Bots, (Incoming) Webhooks, Slash Commands, etc. One such app is the awesome Giphy for Slack, which is something I enjoy using on a daily basis.

This post demonstrates how to develop a Serverless Fn function as a Webhook, that serves as an API for a trimmed down version of the Giphy app for Slack.

You can also check out the following blog posts which also covers interesting Webhook-related use cases

The original Giphy app returns a bunch of GIFs for a search term and the user can pick one of them (notice the Shuffle option below)

/giphy cat

funcy tweaks it a bit by simply returning a (single) random image for a search keyword using the Giphy Random API — for your viewing pleasure only!

/funcy cat

Sounds interesting? Let’s dive in…

Overview

funcy is built as a Slash Command within Slack. As a user, you can invoke it from within your workspace using /funcy <your search term> . Once you deploy the Fn function (as per steps outlined in subsequent section), all you need to do is create a Slack app and configure a Slash Command which points to the function’s invoke endpoint.

The function has the logic to invoke the GIPHY Random API and will get invoked when the /funcy command is triggered by the user from the workspace.

Here is a diagram demonstrating the flow

funcy — high level flow

The code is available on GitHub, but let’s walk through it real quick.

Code…

The serverless function is written in Go — its entry point is via main which delegates to the funcy function.

Safety first

We start off by verifying that the request is indeed from Slack by using the Signing Secret of our Slack App. The details are in the Slack documentation — here is how it’s implemented in our function using Go.

  • We get the signing secret from our function application configuration (SLACK_SIGNING_SECRET)
  • Value of the X-Slack-Request-Timestamp header from the HTTP request
  • The HTTP payload (application/x-www-form-urlencoded data sent by Slack)
signature verification

The above information is used to match the signature sent by Slack in the form of X-Slack-Signature header in the HTTP request — this is the signature created by combining the signing secret with the body of the request using a standard HMAC-SHA256 keyed hash.

We proceed further only if the signatures match:

matching the signatures

Extracting the Search Term

The funcy Slack Slash command works on the basis of the search term/keyword entered by the user. This is done by first parsing the application/x-www-form-urlencoded data sent by Slack and then reading the value of the text attribute

Here is an example of the data sent by the Slack Slash command when it is invoked:

read/parse Slack payload

The parsing logic was taken from the Go standard library:

Invoking GIPHY (Random) API

Once we have the search term, we invoke the GIPHY Random API and the response is unmarshaled into the GiphyResponse struct — this consists of information related to the (random) GIF. For the scope of this function, we just care about the title and the GIF URL (downsized version).

invoke GIPHY

Responding to Slack

If all goes well, we construct a JSON response and send an HTTP 200 response back to Slack as per guidelines — the response contains the GIF title and its URL. The GIF is directly rendered to the caller in the Slack workspace window:

respond back to Slack

Please note that Slack expects an HTTP 200 response within 3 seconds — the function is able to adhere to this SLA

You need to take care of a few things before you deploy and have fun with funcy.

Pre-requisites

Fn setup

Download (or update) the Fn CLI

curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh

Please ensure that Fn server can be accessed from the public internet (e.g. install it on a public VM), or use ngrok on your local machine

fn start

Switch to the correct context e.g. to use the default context which gets installed out of the box

fn use context default

Slack workspace (sign-in or create one)

Sign into your Slack workspace — if you don’t have one, please create it

Giphy API key

Adapted from the Giphy documentation

Start by creating a GIHPY account (it’s free!) and create an app. Each application you create will have it’s own API Key.

Please note down your API key as you will be using it later

GIPHY dashboard

Configuration and Deployment

Create application and deploy the function

Create the Fn application using the command below:

fn create app funcy

Deploy the function to the application

fn -v deploy --app funcy --local

Get invoke endpoint — this will be used as a configuration input to the Slash Command

fn inspect function funcy fun --endpoint//e.g. http://localhost:8080/invoke/01D60BXYFRNG8G00GZJ0000002

Configure Slack

These steps have been adapted from the Slack documentation

Create a Slack App

Before you start, you’ll need a Slack App — click here to get started

Create Slack App

Create a Slash Command

Once you’re done creating the app, head to your app’s settings page, and then click the Slash Commands feature in the navigation menu.

Create Slash Command — 1

You’ll be presented with a button marked Create New Command, and when you click on it, you’ll see a screen where you’ll be asked to define your new Slash Command with the required information:

Create Slash Command 2

Enter the following info — make sure to enter your function invoke endpoint for Request URL e.g. http://[host-ip]:[port]/invoke/[your-function-id]

Create Slash Command 3

Install app to workspace

Once you’re done creating the Slash Command, head to your app’s settings page, click the Basic Information feature in the navigation menu, choose Install your app to your workspace and click Install App to Workspace — this will install the app to your Slack workspace to test your app and generate the tokens you need to interact with the Slack API.

Install Slack App

Make a note of your app Signing Secret

As soon as you finish installing the app, the App Credentials will show up on the same page. You need to grab your Slack Signing Secret from there

Slack Signing Secret

You’re almost there! You just need to update your application.

Update application

Update the (function) app to set Slack Signing Secret and GIPHY API key in the configuration

fn update app funcy --config SLACK_SIGNING_SECRET=<fill-in-secret> --config GIPHY_API_KEY=<fill-in-apikey>

fun(cy) time!

From your workspace, invoke the command using /funcy <search term> e.g. /funcy serverless

https://media.giphy.com/media/MGdfeiKtEiEPS/giphy.gif

or maybe another cat using /funcy cat

https://media.giphy.com/media/13HBDT4QSTpveU/giphy.gif

Thanks for reading ! I hope this was fun and you learned something along the way as well. Please drop in a comment if you have questions, feedback or just want to say hello. :-)

Don’t forget to …

Cheers!

--

--

Abhishek Gupta
Fn Project

Principal Developer Advocate at AWS | I ❤️ Databases, Go, Kubernetes