Building Slack Apps with Tines: Part 3
Recap
Other posts in this series:
We've covered quite a bit of ground by now. We understand the basics of Slack Apps and are well acquainted with the infrastructure they require. It's about time we see what a full-fledged application looks like, wouldn't you say? If it still seems a little daunting, don't worry! This is all stuff you've seen already, we're just tying a bow on it.
App Overview
This app uses the Dog CEO API (on which we touched briefly over in Part 2). If you love dogs, you'll love this API. Described as 'The internet's biggest collection of open source dog pictures', it is a veritable treasure trove of pup-related content. On top of that, the API is public and operates off of donations. I highly encourage giving their website a look when you have a moment.
We'll serve up three primary functions:
- Get random dog photos
- Get a list of all available breeds
- Get a list of all available sub-breeds
These are exposed to our end users via the corresponding Slash Commands:
/retrieve-photo
/retrieve-breeds
/retrieve-sub-breeds
Additionally, when using the /retrieve-photo
command, users have the ability to 'Accept', 'Shuffle', and 'Cancel' their requests for dog photos. This functionality is implemented using a set of three Interactive Slack Blocks (button elements, specifically).
All of this involves some back-and-forth between Slack, Tines, and the Dog CEO API. A rough overview of the architecture looks something like this:
The Story
Let's start with Tines, which is where our business logic lives and the heavy lifting is done. We needed four total Webhooks - One for each Slash Command and one to which Interactive Payloads are sent. Each Webhook is responsible for receiving user input, processing it accordingly, and relaying the response to the end user.
One Action to pay close attention to is Build URL
. A user can request dog photos without any arguments or by using a breed/sub-breed combination. You can implement something like this using a branch pattern and a Trigger action to distinguish request types, but it's often more concise by using Tines Functions instead:
This action leverages the Local Values
feature - Basically performing a series of calculations and transformations against the Slack payload ahead of time, which yields a dynamically-generated API URI. If you want to examine this action in greater detail, copy the below JSON and paste it right into your Story Board:
{"standardLibVersion":"40","actionRuntimeVersion":"5","agents":[{"disabled":false,"name":"Build URL","description":null,"options":"{\"mode\":\"message_only\",\"loop\":false,\"payload\":{\"url\":\"https://dog.ceo/api/<<LOCAL.uri |>\\nREPLACE(%, \\\"//\\\", \\\"/\\\")>>\"},\"local\":{\"breed\":\"=retrieve_photo.body.text |>\\nSPLIT(%, \\\" \\\") |>\\nSLICE(%, 0, 2) |>\\nJOIN(%, \\\"/\\\") |>\\nIF(IS_BLANK(%), %, % & \\\"/\\\") |>\\nDOWNCASE(%)\",\"resource\":\"<<IF(IS_BLANK(LOCAL.breed), \\\"breeds\\\", \\\"breed\\\") |> % & \\\"/\\\">>\",\"images_resource\":\"<<IF(INCLUDES(LOCAL.resource, \\\"breeds\\\"), \\\"image\\\", \\\"images\\\")>>\",\"uri\":\"<<LOCAL.resource>><<LOCAL.breed>><<LOCAL.images_resource>>/random\"}}","position":{"x":690,"y":210},"type":"eventTransformation","timeSavedUnit":"minutes","timeSavedValue":0,"monitorAllEvents":false,"monitorFailures":false,"monitorNoEventsEmitted":null,"recordType":null,"recordWriters":[],"form":null,"cardIconName":null,"createdFromTemplateGuid":null,"createdFromTemplateVersion":null,"originStoryIdentifier":"cloud:98bf19cf1391e1805daf0cbdc3239e4a:6169096c1f23582bc523560f0ca8a4d3"}],"links":[],"diagramNotes":[]}
Our finished Story looks a little something like this:
Slack Config
With the arguably-trickier part of our app's implementation out of the way, let's get into the Slack configuration. Remember, best practice suggests one Slash Command = one Webhook. So with our Tines Story all set, we wind up with several commands that look like so:
This just leaves our Interactivity URL and our remaining Webhook, which we configure via the Interactivity & Shortcuts
section here:
See it in Action
When all is said and done, our users are able to retrieve dog photos at will right from Slack. If they don't like the photo they get, or just want to see more, all they have to do is click 'Shuffle'. The best part? The build time to get this puppy (no pun intended) off the ground only took a few hours. All thanks to Tines's powerfully simple
DIY
Interested in tinkering with this Tines Story yourself? Get it from Github here. Tines makes this part very, very easy. Simply go to the Team in which you'd like this Story to live, click 'Import', and follow the prompts:
For a complete implementation, you'll have to add the corresponding Slash Commands to your app's configuration, as well as the Webhook URL to enable App Interactivity. If you need any help getting this part in order, head on back to Building Slack Apps with Tines: Part 2 for detailed examples.
Partial to Code?
Want to build your bot using Python instead of Tines? I've got you covered - feel free to use RoverRetriever, a Python wrapper built to abstract all of the Dog CEO API's available methods. This wrapper can be installed using setup.py
, or simply by using pip:
pip install RoverRetriever
Closing Thoughts, Parting Bots
So there we have it - Our first start-to-finish, fully-functional Slack App. Our users will surely be delighted and productivity will no doubt skyrocket. So what's next?
There's still the not-insignificant issue of distribution, which is a topic all on its own. Basically, our App works perfectly so long as it lives on in our own Workspace. For many this will be perfectly sufficient, but if you're interested in expanding to other Workspaces, there are a few things we'll need to tackle first. Until Part 4 - Be curious, build frequently, and iterate often.