My first Custom Slack App - Part 2
Tags: node, slack, googlespreadsheet, javascript
Published: 2019-05-20 07:22:29

---
title: My first Custom Slack App - Part 2
published: true
description: Creating your free Custom Polling Slack app using google spreadsheet as database and some server as our host for NodeJS Application.
tags: node #slack #googlespreadsheet #javascript
---
# Blogs in the Series
| Part 	| Description                                                   	|
|------	|---------------------------------------------------------------	|
| 1    	| [Setting the backend](https://dev.to/nabheet/my-first-custom-slack-app-part-1-4o6j)                                           	|
| 2    	| [Setting the API server to talk to Backend as well as frontend](https://dev.to/nabheet/my-first-custom-slack-app-part-2-28p5) 	|
| 3    	| [Setting the Frontend to talk to API server ](https://dev.to/nabheet/my-first-custom-slack-app-part-3-4ahh) 	|
| 4    	| Deploying the app to something permanent	|
| 5    	| Research on deploying to slack app store	|


# What we have done so far? 
In our previous [Blog](https://dev.to/nabheet/my-first-custom-slack-app-part-1-4o6j) we have set up our database [google spreadsheet](https://www.google.com/sheets/about/) and enabled the API's to interact with it. So lets now build our [NodeJS](https://nodejs.org/en/) application which will talk to frontend and backend. Although this part utilize some set up from the next blog which is slack set up lets hold on to that till part 3 is out.
![](https://thepracticaldev.s3.amazonaws.com/i/hpkh6ds1d9j4qenbakil.png)

# Setting up modules needed for our NodeJS App
Our NodeJS application will need some package to talk to Slack as well as spreadsheet.So luckily slack provides us with its npm package ** [@slack/bolt](https://www.npmjs.com/package/slack-bolt) ** and google spread sheet provides us with ** [google-spreadsheet](https://www.npmjs.com/package/google-spreadsheet) **. Lets first initialze a node project and install the two packages
```Node
npm init
npm i @slack/bolt
npm i google-spreadsheet
```


# Lets do some coding
Since now we have everything set up lets create an index.js file and use the modules.
```Node
const App               = require('@slack/bolt');
const GoogleSpreadsheet = require('google-spreadsheet');
```
Once we have the modules  lets add our excel spread sheet id as well as credential file and slack app token/secrets(hold on to this, we will be covering in next part). The tokens can be handled in a better way for sure, we were looking for a solution which is quick:)
```Javascript
const creds = require('./cred.json');
const spreadsheet = new GoogleSpreadsheet(<Spreadsheet id got in previous blog>);
const app = new App({
  signingSecret: "<secret1>",
  token: "<token>",
});
```

So now we have created two objects **app** for interacting with slack and **spreadsheet** for interacting with backend. Going forward we will be using the methods of these objects to get our work done.

Slack uses a concept called as command using which you can create dynamic things for example our poll as shown below.
![](https://thepracticaldev.s3.amazonaws.com/i/518hqp2jc2dz705lsnu6.png)

Whenever this command is fired from Slack we shall be able to listen it in our API, so adding the code to handle command /ourpoll. This will return a response which will be shown as poll like above using say method as shown below. 
The say method has a proper structure in which we need to pass the values as in response and buttons which is nothing but actions. We can use [slack bot kit builder](https://api.slack.com/block-kit) where can build our response and see the corresponding structure format. 
```Node
app.command('/ourpoll', async ({
  command,
  ack,
  say
}) => {
  // Acknowledge command request
  ack();
  say({
    blocks: [{
        "type": "section",
        "text": {
          "type": "mrkdwn",
          "text": command.text
        }
      },
      {
        "type": "actions",
        "elements": [{
            "type": "button",
            "text": {
              "type": "plain_text",
              "text": "Yes",
              "emoji": true
            },
            "action_id": "Yes"
          },
          {
            "type": "button",
            "text": {
              "type": "plain_text",
              "text": "No",
              "emoji": true
            },
            "action_id": "No"
          }
        ]
      }
    ]
  });

});

```
Once we have the response given back to slack we are also calling **spreadsheet.useServiceAccountAuth** to save the data in our google spreadsheet.
```Node
  spreadsheet.useServiceAccountAuth(creds, function (err) {
   spreadsheet.addRow(1, {
      Question: command.text,
      Yes: ' ',
      No: ''
    }, function (err) {
      if (err) {
        console.log(err);
      }
    });
    if (err) {
      console.log(err)
    }
  });
```
So now we know how to handle the commands from slack but what about the two button or actions yes/no which we have added in our response. When user provide his/her decision we should be able to handle it. That is app object has provided method action for the same. 
Lets first handle action Yes. The code can be enhanced in much much better way which i intend to do soon:). If you notice we are reading the rows of excel and then updating the relevant row with the decision.
```Node
app.action('Yes', ({
    body,
    ack,
    say
}) => {
    ack();
    spreadsheet.useServiceAccountAuth(creds, function(err) {
        spreadsheet.getRows(1, function(err, rows) {
            var filteredRows = rows.filter(function(el) {
                return el.question == body.message.blocks[0].text.text;
            });
            var sayConcatenated, yescount;
            filteredRows.forEach(row => {
                console.log('Row count is ' + row.yescount);
                if (row.yescount == "") {
                    row.yescount = 1;
                } else {
                    row.yescount = Number(row.yescount) + 1
                }
                yescount = row.yescount;
                if (row.yes == "" || row.yes == " ") {
                    row.yes = body.user.id;
                } else {
                    row.yes = row.yes + ',' + body.user.id;
                }
                if (row.yesusername == "") {
                    row.yesusername = body.user.name;
                } else {
                    row.yesusername = row.yesusername + ',' + body.user.name;
                }
                row.save();
                let users = row.yes.split(",");
                const say = users.map(user => '<@' + user + '>');
                sayConcatenated = say.reduce((acc, sayone) => acc + sayone);
            });
            say(`${sayConcatenated} ${yescount} geeks said Yes for ${body.message.blocks[0].text.text}`);
        });
        if (err) {
            console.log(err)
        }
    });
});
```
Now we handle action No
```Node
app.action('No', ({
    body,
    ack,
    say
}) => {
    ack();
    spreadsheet.useServiceAccountAuth(creds, function(err) {
        spreadsheet.getRows(1, function(err, rows) {
            console.log(body.message.blocks);
            var filteredRows = rows.filter(function(el) {
                return el.question == body.message.blocks[0].text.text;
            });
            var sayConcatenated, nocount;
            filteredRows.forEach(row => {
                if (row.nocount == "") {
                    row.nocount = 1;
                } else {
                    row.nocount = Number(row.nocount) + 1
                }
                nocount = row.nocount;
                if (row.no == "" || row.no == " ") {
                    row.no = body.user.id;
                } else {
                    row.no = row.no + ',' + body.user.id;
                }
                if (row.nousername == "") {
                    row.nousername = body.user.name;
                } else {
                    row.nousername = row.nousername + ',' + body.user.name;
                }
                row.save();
                let users = row.no.split(",");
                const say = users.map(user => '<@' + user + '>');
                sayConcatenated = say.reduce((acc, sayone) => acc + sayone);
            });
            say(`${sayConcatenated} ${nocount} geeks said No for ${body.message.blocks[0].text.text}`);
        });
        if (err) {
            console.log(err)
        }
    });
```

# What is next?

So now we have our API which is talking to backend as well frontend ready. In the next blog we will set up the slack part so that Slack can talk to our NodeJS app which in turn can talk to the backend. Off course we will have a demo video also for the same:)