Published: May 14, 2019
Updated: January 31, 2022
We've just released Block Kit, a UI framework that enables you to build rich and interactive experiences in Slack. This gives your apps more options to display information in each message. As an example, you can list information like tasks or poll results.
With Block Kit, you can prototype with a visual tool, the Block Kit Builder, as well as actually build messages sent by your app using the JSON string generated by the tool.
This tutorial walks you through building messages with Block Kit to improve the user experience of search results in your app.
This instruction uses Node.js to show you how to build a slash command that displays results in a rich messaging format. Basic coding experience with JavaScript or other programming languages is recommended to complete this tutorial.
The source code you'll need is on Glitch, which you can "remix" and run without deploying code!
🎏🍴 Remix (fork) the Glitch repo
Also, to make the example app more interesting, we'll use the Yelp API, which requires you to sign up to obtain a Yelp Client ID and an API key. Detailed information on Yelp's API can be found here.
Let's get started with a walkthrough of how a user might interact with this app:
/find-food [a type of food], [location proximity]
(e.g. /find-food burrito, Mission San Francisco
)In this exercise, we are going to create a slash command where a user can send the /find-food
command to get a list of a few restaurants as the result.
First, go to Slack App Management to create an app by clicking the button:
Then add the slash command feature and define your command at Features > Slash Commands at the App Management page. For this tutorial, let's call it /find-food
. The parameters a user can pass with the command will be a type of food and a location, separated by a comma, as in /find-food bao, Chinatown NYC
.
This will automatically create a bot user and add the commands
bot scope for you.
Your Request URL should be https://your-server/route
. If you "remix" the project on Glitch, where you will have a generated project name consisting of two random words, your request URL would be something like https://sassy-shrimp.glitch.me/command
Then, get your Signing Secret key at Settings > Basic information.
The key should be stored in the .env file, along with Yelp credentials.
SLACK_SIGNING_SECRET=fca39e3de...
YELP_CLIENT_ID=sIskJpLm5f...
YELP_API_KEY=ySz84qKNl...
(If you're trying on the remixed Glitch example, rename the .env.sample in the repo to .env, and fill it out with your credentials!)
Go to Settings > Install App to install the app on your workspace.
In your Node.js code, include dependencies and run an Express server, also get the raw request payload to verify your Signing Secret. (For more details about this security feature, please refer to the Verifying the Requests section in the previous tutorial):
const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const signature = require('./verifySignature');
const app = express();
const rawBodyBuffer = (req, res, buf, encoding) => {
if (buf && buf.length) req.rawBody = buf.toString(encoding || 'utf8');
};
app.use(bodyParser.urlencoded({verify: rawBodyBuffer, extended: true }));
app.use(bodyParser.json({ verify: rawBodyBuffer }));
const server = app.listen(process.env.PORT || 5000);
Next, use an HTTP POST method route to create an endpoint to receive the slash command payload. Once you receive a payload, check if the request is coming from Slack (otherwise, you may be under attacks from some malicious source!). If it is a valid and safe request, parse the user-send params to get queries, in this case, food type, and location.
Then, pass the queries to Yelp API to get the results.
app.post('/command', async (req, res) => {
if(!signature.isVerified(req)) {
res.sendStatus(404);
return;
} else {
const query = req.body.text ? req.body.text : 'lunch, San Francisco';
const queries = query.split(',');
const term = queries.shift(); // "Pizza"
const location = queries; // "San Francisco, CA"
const places = await getPlaces(query, location);
}
const message = { // will generate it }
res.json(message);
}
The getPlaces()
returns the results in an array. (See the source code for the function.)
The returned array from the Yelp REST API would look like this (Note: the result shown here is simplified for this tutorial):
[{
name: 'Zero Zero',
image_url:
'https://s3-media2.fl.yelpcdn.com/bphoto/JB5XNOgdQHocE4nI9DHWkA/o.jpg',
url:'https://www.yelp.com/biz/zero-zero-san-francisco',
review_count: 3128,
rating: 4,
price: '$$',
location:
{
display_address: [ '826 Folsom St', 'San Francisco, CA 94107' ] },
phone: '+14153488800'
}...
]
Replying the user with a simple message publicly, you just send an HTTP 200 with a simple JSON. For example, to simply respond with a restaurant name from the result array:
const message = {
response_type: 'in_channel',
text: places[0].name,
};
res.json(message);
This JSON response will display a message like this:
Now, let's take advantage of the new Block Kit elements to send a more contextual message.
Block Kit consists of stackable blocks that you can mix and match layout blocks and block elements to build a message.
We are going to re-format the JSON message we just created to display a plain text into this rich message format using Block Kit:
You can design a message using a visual prototyping sandbox, Block Kit Builder, or by picking and arranging all available blocks on a browser.
If you click each block from the left side, the JSON array is generated for you on the right side to use in your code:
Let's bring the JSON array into your message
object to replace the previous one. Replace the line where it says text: places[0].name
with the array of blocks:
const message = {
response_type: 'in_channel',
blocks: [
// Result 1
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*<${places[0].url}|${places[0].name}>* \n${places[0].location.display_address.join(' ')} \n\nRating: ${places[0].rating} \nPrice: ${places[0].price}`
},
accessory: {
type: 'image',
image_url: `${places[0].image_url}`,
alt_text: 'venue image'
}
},
{
'type': 'context',
'elements': [
{
'type': 'plain_text',
'text': `${places[0].review_count} Yelp reviews`,
'emoji': true
}
]
},
{
'type': 'divider'
},
}
]
};
When you set the text type as mrkdwn
, you can format your text using some of the markdown features, such as bold and italic text, and hyper-linked text, etc. You can read more about text formatting at An overview of message composition.
Now try the slash command on Slack client, and tada, now you have a nicer and more contextual message as the response!
Ta-da! Now the Yelp results are displayed nicely!
Now that you've created a rich message as a response to a slash command, you can send messages with a variety of methods such as incoming webhooks, as well as in-app via WebAPI with either chat.postMessage
and chat.postEphemeral
, including the responses for message actions and rich interactions.
We encourage you to build creative and imaginative message blocks with the Block Kit Builder, however, you must always consider your users first. Above all else, your messages must be easy to read. Avoid cluttering up the conversation and do not to load with a lot of content into a single message. Also, use interactive UI elements like buttons and menus effectively.
First, prototype a message UI using the Block Kit Builder, try multiple patterns and test with mobile devices too.
I hope this tutorial helped you to get some ideas on what to build, or modify your existing Slack app!
If you run into any trouble, find us on Twitter, or reach out our developer support team at feedback@slack.com. Happy developing! 🤖