Slack Development: Part 2

This is part 2 of creating a Slack app! Here I will be discussing how to set up a Bolt for Javascript backend with Node.js and what steps are necessary for your app to receive events and respond back to them. This again will serve as a compressed version of existing documentation and as a way to better explain certain topics. 

If you have not read part 1 of this series, feel free to take a look at that first and then come back here to continue the journey! If you’re familiar with creating a Slack app and just need a refresher for how to set up the server, then come along for the ride! 

What is Bolt? 

Our definition here will be the definition found in the Bolt for Javascript documentation. Bolt is a Javascript framework that allows the user to build Slack apps with the latest platform features.

So what does this mean for us? It means that Bolt allows us to create a Slack app that listens to the “slack/events” endpoint to get all incoming requests. This is important because when we set up request URLs for our events, we should set it to end in “slack/events”. So when we do an action in the app and the action fires off an event, that event request is sent to the request URL that we set it to. Our app will be able to receive that request, and as a result we will be able to respond to it. 

Now that we know this, we also want to know what type of events we will have access to. Well we will be describing this in the “How to subscribe to events” section, but for now let’s get our backend set up. 

Steps to get set up:

We start off with installing Node as shown here

Next we will do an npm init and create our app. 

We can install Bolt with:

Npm install @slack/bolt

We will then take the example code from the documentation: 

const { App } = require('@slack/bolt');
const app = new App({
signingSecret: process.env.SLACK_SIGNING_SECRET,
token: process.env.SLACK_BOT_TOKEN,
);
/* Add functionality here */
(async()=>{
// start the app
await app.start(process.env.PORT || 3000);
console.log('⚡️ Bolt app is running!');
})();
async () => {
/ Start the app
 await app.start(process.env.PORT || 3000);
console.log('⚡️ Bolt app is running!');
)();

Now we will create an env file to store our environment variables which in this case are the signing secret and bot token. We can go back to our app’s management page and get these from the Basic Information page and OAuth & Permissions page, respectively. 

With those two parts stored, we can now start our app by running:

node [app_name]

But, now that we have a working app, how do we make it communicate with Slack? Our app is currently running locally, so we will need a tunnel such as ngrok to be available to share the app publicly. Here is the link to download it or we can just do npm install ngrok in the command line. 

When installed, we can create a tunnel by running on your terminal:

./ngrok http [custom_port_number]

Source: tunneling with Ngrok (https://api.slack.com/tutorials/tunneling-with-ngrok)

Then we can use the response url given in our next step “how to subscribe to events”. 

How to subscribe to events: 

We currently have a running app, so now we want to add some functionality to it. 

As I previously mentioned, our app is able to listen to any event requests and with this information, we can now take a look at the various event types that are available within a Slack app, here

After taking a look, we can enable event subscription by heading over to our app management page and clicking on “Event Subscriptions”. 

When we get there, we will toggle the switch and we will see the following: 

We can enter our ngrok response URL and concatenate “/slack/events” for all our subscribed event requests to be sent over to the URL we just input. 

Since we know our app listens to any event types with the request url ending in “slack/events”, then we know our app will now be listening to the events we just subscribed to. 

How to respond to events: 

Now that we have subscribed to events, we want our app to not only listen to the request but also be able to respond to them. Here we will go over a single event type and will provide links to API docs for the others. This is due to the large number of events and the subtle but important differences that come with every one of them. 

Anyways, we will now jump into responding to the “‘app_home_opened” event, which is the most used event type. This event type fires off a request every time a user navigates to either the home, about, or message tabs. I will provide the structure and then explain them one by one. 

Structure: 

app.event('app_home_opened', async ({ event, client, context }) => {
  try {
    /* view.publish is the method that your app uses to push a view to the Home tab */
    const result = await client.views.publish({

      /* the user that opened your app's app home */
      user_id: event.user,

      /* the view object that appears in the app home*/
      view: {
        type: 'home',
        callback_id: 'home_view',

        /* body of the view */
        blocks: [
          {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": "*Welcome to your _App's Home_* :tada:"
            }
          },
          {
            "type": "divider"
          },
          {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": "This button won't do much for now but you can set up a listener for it using the `actions()` method and passing its unique `action_id`. See an example in the `examples` folder within your Bolt app."
            }
          },
          {
            "type": "actions",
            "elements": [
              {
                "type": "button",
                "text": {
                  "type": "plain_text",
                  "text": "Click me!"
                }
              }
            ]
          }
        ]
      }
    });
  }
  catch (error) {
    console.error(error);
  }
});

The first thing you see is the app.event(), this means that our application is listening for events instead of, for example, app.command() which listens to commands. 

Then in the first parameter position we see “app_home_opened”, which is the type of event that it is.

In the second position we see async({event, client, context})=>{}); which is an async function that describes what will happen as a response to the app event type. Inside the JSON object within the async function, we see three variables: event, client, context. Event will hold the attributes type (specific name of event), event_ts (event timestamp), user (user ID of user that created this action), ts (timestamp of what the event describes), and item (data specific to the underlying object type being described). Usually, you will only care about the user here, but feel free to read up more on “event”: here. The client is the web api client which serves as a way for us to publish new content or to respond to someone in a group message, etc. The context here is the event context. 

In the example above, the user is using the client to publish a new view and then grabs the user id. Inside the view, the user uses Slack blocks to create the UI for the view. We can see that in this case, context is not used so it can be left out. This is also true of event, since the user never utilizes the user id grabbed from event. 

As you can tell, with any event, we will receive a certain set of parameters that we will use inside our response. Here is a list of parameters and descriptions of each. 

TLDR:

To summarize the above, we can use Bolt for Javascript to make our app be able to listen and respond to events. To do this we install node, @slack/bolt, and ngrok. We use ngrok as a way for our app to be publicly shared so Slack’s event requests can get to our app. We subscribe to events by going to our app management then heading over to Event Subscriptions and toggling Enable App Events. After this, we can input our ngrok url + “/slack/events” so that our app knows to send the event requests to this URL. We scroll down and pick the events we want to subscribe to. Finally, we can respond to the requests inside our app. We see that the structure will be “app.event([event_type], async({param1, param2, param3,..,etc} =>{ functionality and response});”. Inside functionality, we can create new views, update views, message someone back, and a plethora of other actions. 

What’s next?

This will conclude my series on getting a Slack app up and running. At this point, you can create any functionality needed by understanding what each event type will send in each request fired to your app. Additionally, you can learn more about different requests like actions, commands, etc and use these to make your app more dynamic, however all of these are similar in nature and explaining these will become redundant. 

I hope you all have liked this series and learned more than things listed in the documentation given by Slack. I will be updating these two parts at some point, but for the meantime, I will be exploring different topics in this blog. See you all soon! 

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *