DEV Community

Liran Tal for Snyk

Posted on • Originally published at snyk.io on

How to build a Slack bot with Zapier and JavaScript to fetch trending topics on Reddit

Reddit is a good place to stay in the loop when it comes to web development news, and if you’re like me, you probably follow subreddits like r/node or r/javascript. I recently found a great way to build a Zapier Reddit integration with just my JavaScript knowledge — so I can share those trending Reddit posts in my team’s channel.

In this article you’ll learn:

  • How to build a Slack bot integration.
  • How to create Triggers and Actions workflows in Zapier to post messages to a Slack channel.
  • How to use a Reddit API key to access posts using native Reddit Access Tokens and Refresh Tokens.
  • How to access Reddit posts using the anonymous JSON endpoint.
  • Writing JavaScript code (compatible with Node.js version 10, notice it’s End of Life) to fetch Reddit information with the node-fetch HTTP client.

What can you do with a Slack bot?

This tutorial teaches you how to write a Slack bot in JavaScript, but Zapier’s feature rich API ecosystem allows you to connect many other sources of information to the Slack bot API. While this Slack bot tutorial focuses on JavaScript, you can also write a Slack bot Node.js application with Zapier’s HTTP web hooks if you host your Node.js applications in the cloud.

Building a Zapier Reddit integration to process new trending topics

What is Zapier?

Zapier is an automation platform that allows you to integrate with many other platforms, in order to connect them and produce a workflow. It’s mostly used for APIs and native integrations when those are available in the Zapier marketplace, but it further shines by providing you with raw input and output from the integration points, and allowing you to customize the workflow process through code.

To facilitate the Slack bot integration we will be using Zapier, which already has its own native integration with Slack — meaning we don’t need to host our bot in a dedicated server or create yet another separate Slack bot integration.

Since we have the Slack bot integration with Zapier, our next steps will be to:

  1. Define a schedule for the integration to run. This can be a recurring schedule in which the Zapier task will fire off and start processing.
  2. Define a custom JavaScript code task in Zapier, to fetch our trending topics of interest from Reddit’s JSON endpoint.
  3. Format the trending topics to our liking, and send them to a Slack channel through the native Slack bot integration Zapier has built-in.

In the Zapier workflow UI, this entire process looks like:

Zapier workflow to build a slack bot automation that fetch Reddit trending topics and sends them to a Slack channel.

The Trigger: Every Week in Schedule by Zapier

We begin by setting up the recurring schedule for the Zapier workflow. Specifically, I’ve chosen to run it every Monday at 8AM UTC time:

Every Week in Schedule by Zapier to define a trigger for our Slack bot integration.

How do you automate Slack messages?

In this Slack bot tutorial, we’ve chosen to use a timely schedule triggered by Zapier. However, the Zapier API platform has many other triggers that can drive Slack automations. Some examples are: Twitter mentions, Google Sheets updates, Google Calendar event updates, RSS feed updates, and others which you can plug in to your Slack bot JavaScript automation. You can even automate Snyk security notifications for your team’s vulnerability tracking!

Action: Run JavaScript in Code by Zapier

Now that we’ve defined the time-based trigger to fire off the workflow, we can begin creating actions to perform some tasks. The Zapier integration allows us to connect the data processed from these tasks, and feed it into the next action in the chain.

Choose a Run JavaScript in Code by Zapier type of actions. In the Event configuration, choose Run JavaScript. The initial setup should look as follows:

Run JavaScript in Code by Zapier.

Then, expand the Setup up action configuration, where we’ll add the relevant JavaScript code that fetches information from the Reddit API endpoint for our trending topics.

How to use Reddit API key

There are several ways to retrieve reddit news. We’ll to cover two ways to receiving updates on interesting Reddit threads:

  1. Using a Reddit API key, which requires signing up with a Reddit user account.
  2. Using a publicly available Reddit API endpoint.

If you only need read access to subreddits and trending posts, use the simpler workflow that doesn’t involve the Reddit oAuth API workflow — and jump to the 2nd part of this Reddit API access chapter.

Register for Reddit API key

Start with navigating to the Reddit API application preferences and click the Create an app button on the bottom of the screen. Then, enter the information for your API use-case. You’ll need to set the type of application to webapp and provide a redirect URI to process the access tokens.

Reddit oauth application creation screen to generate a Reddit API token

You will then receive your ClientID and ClientSecret, with which you can make API calls. If you’re unsure how to query the Reddit API and work through the Reddit oAuth workflow, review the other getting started tutorials such as this one about scraping Reddit.

It’s important to note that you’re expected to read through Reddit’s API Access terms to familiarize yourself with Reddit API rules and conditions you must meet.

Reddit API JavaScript example

We’ll focus on fetching the interesting Reddit threads using JavaScript. To do so, we’ll need the ClientID and ClientSecret credentials mentioned above as well as the refresh_token value, which exists if you’ve opted-in to create a permanent Reddit oAuth access token.

The following is a good example of a Reddit API key that queries subreddit posts using native JavaScript code. Replace the ABCD text below with the above mentioned Reddit credentials for the code snippet to function properly:

js
  // start -- get access token
   const clientId = ‘ABCD’;
   const clientSecret = ABCD’;

   const dataSecrets = `${clientId}:${clientSecret}`;
   const text = Buffer.from(dataSecrets).toString("base64");

   var url = new URL('https://www.reddit.com/api/v1/access_token');
   var params = {grant_type: 'refresh_token', refresh_token: ‘ABCD'};

   url.search = new URLSearchParams(params).toString();

    const settings = {
        method: 'POST',
        headers: {
            'User-Agent': 'query-api 1.0',
            'Accept': 'application/json',
            'Authorization': `Basic ${text}`,
        },
        credentials: 'omit'
    };

    const res = await fetch(url.href, settings);
    const body = await res.json();
    const accessToken = body.access_token;

    // -----------------------------------------------------
    // make reddit api request
    const params2 = {'limit': 3, 't': 'week'};
    const url2 = new URL('https://oauth.reddit.com/r/node/top');
    url2.search = new URLSearchParams(params2).toString();

    const settings2 = {
        method: 'GET',
        headers: {
            'User-Agent': 'query-api 1.0',
            'Accept': 'application/json',
            'Authorization': `Bearer ${accessToken}`,
        },
        credentials: 'omit'
    };

    const res2 = await fetch(url2.href, settings2);
    const body2 = await res2.json();

    let data = [];
    let message = `Top Node.js posts this week:\n\n`;

    const topPosts = body2.data.children;
    topPosts.forEach((post) => {
        data.push({
          link: post.data.url,
          redditLink: post.data.permalink,
          text: post.data.title,
          score: post.data.score,
          replies: post.data.num_comments
        });

        const text = post.data.title;
        const redditLink = post.data.permalink;

        message = message + `<https://reddit.com${redditLink}|${text}> \n`;
    });

    return {id: 1, message: message};
Enter fullscreen mode Exit fullscreen mode

This Reddit API JavaScript code snippet uses the refresh_token to query the Reddit API and request an access_token. Once we obtain the Reddit API access token, we can create a new HTTP request — which fetches trending Reddit posts submitted to the r/node subreddit. Finally, we loop through all the post data and create a message string that will be passed to our next action.

Two important observations from the previous code snippet:

  1. You’ll note that the correct, and up to date, API to query the Reddit data is the use of t query parameter used in params2. However, some outdated tutorials and guides still mention the use of time instead.

  2. Another interesting point is that, since Zapier limits us to an old version of node-fetch running on an End of Life version of the Node.js runtime (Node.js v10), you can actually use the URL object directly to make HTTP requests:

js
    const url2 = new URL('https://oauth.reddit.com/r/node/top');
    const res2 = await fetch(url2, settings2);
Enter fullscreen mode Exit fullscreen mode

For other API operations, you may refer to the complete and up to date Reddit API documentation page for all the available endpoints about Reddit accounts, history, subreddit moderation, and other capabilities.

Querying Reddit information with the public JSON endpoint

Before moving on with the other JavaScript Zapier action, let’s quickly cover how you can query a Reddit API, without needing to authenticate using oAuth, or any other type of API key.

Reddit makes the subreddit thread information available in a JSON format using the following endpoint, which is public and unauthenticated:

sh
https://www.reddit.com/r/node/top.json
Enter fullscreen mode Exit fullscreen mode

You can even request the Top posts from this subreddit, and provide a timeframe for that, by appending the following query parameters:

sh
https://www.reddit.com/r/node/top.json?limit=1&t=month
Enter fullscreen mode Exit fullscreen mode

The JSON response from Reddit will be something similar to the following:

json
{
  "kind": "Listing",
  "data": {
    "after": "t3_vuyxes",
    "dist": 1,
    "modhash": "6v201d03619751a685b19dcf05febbf88ed6d115afa5d16b78",
    "geo_filter": "",
    "children": [
      {
        "kind": "t3",
        "data": {
          "approved_at_utc": null,
          "subreddit": "node",
          "selftext": "",
          "author_fullname": "t2_7eb9a4k5",
          "saved": false,
          "mod_reason_title": null,
          "gilded": 0,
          "clicked": false,
          "title": "Deno in 2022",
          "link_flair_richtext": [],
          "subreddit_name_prefixed": "r/node",
          "hidden": false,
          "pwls": 6,
          "link_flair_css_class": null,
          "downs": 0,
          "top_awarded_type": null,
          "hide_score": false,
          "name": "t3_vuyxes",
          "quarantine": false,
          "link_flair_text_color": "dark",
          "upvote_ratio": 0.92,
          "author_flair_background_color": null,
          "subreddit_type": "public",
          "ups": 745,
          "total_awards_received": 0,
          "media_embed": {},
          "author_flair_template_id": null,
          "is_original_content": false,
          "user_reports": [],
          "secure_media": null,
          "is_reddit_media_domain": true,
          "is_meta": false,
          "category": null,
          "secure_media_embed": {},
          "link_flair_text": null,
          "can_mod_post": false,
          "score": 745,
          "approved_by": null,
          "is_created_from_ads_ui": false,
          "author_premium": false,
          "thumbnail": "",
          "edited": false,
          "author_flair_css_class": null,
          "author_flair_richtext": [],
          "gildings": {},
          "content_categories": null,
          "is_self": false,
          "mod_note": null,
          "created": 1657363081,
          "link_flair_type": "text",
          "wls": 6,
          "removed_by_category": null,
          "banned_by": null,
          "author_flair_type": "text",
          "domain": "i.redd.it",
          "allow_live_comments": true,
          "selftext_html": null,
          "likes": null,
          "suggested_sort": null,
          "banned_at_utc": null,
          "url_overridden_by_dest": "https://i.redd.it/hjv8r84ttia91.jpg",
          "view_count": null,
          "archived": false,
          "no_follow": false,
          "is_crosspostable": true,
          "pinned": false,
          "over_18": false,
          "all_awardings": [],
          "awarders": [],
          "media_only": false,
          "can_gild": true,
          "spoiler": false,
          "locked": false,
          "author_flair_text": null,
          "treatment_tags": [],
          "visited": false,
          "removed_by": null,
          "num_reports": null,
          "distinguished": null,
          "subreddit_id": "t5_2reca",
          "author_is_blocked": false,
          "mod_reason_by": null,
          "removal_reason": null,
          "link_flair_background_color": "",
          "id": "vuyxes",
          "is_robot_indexable": true,
          "report_reasons": null,
          "author": "m_ax__",
          "discussion_type": null,
          "num_comments": 184,
          "send_replies": true,
          "whitelist_status": "all_ads",
          "contest_mode": false,
          "mod_reports": [],
          "author_patreon_flair": false,
          "author_flair_text_color": null,
          "permalink": "/r/node/comments/vuyxes/deno_in_2022/",
          "parent_whitelist_status": "all_ads",
          "stickied": false,
          "url": "https://i.redd.it/hjv8r84ttia91.jpg",
          "subreddit_subscribers": 215851,
          "created_utc": 1657363081,
          "num_crossposts": 0,
          "media": null,
          "is_video": false
        }
      }
    ],
    "before": null
  }
}
Enter fullscreen mode Exit fullscreen mode

Format the JavaScript response of the Zapier Action

However you obtained and formatted the Reddit JSON data, we’ll need to prepare it for consumption by the next Slack bot integration. You could do that in the prior JavaScript Zapier Action as a whole, or run it as its own dedicated Zapier Action — so you can re-use it if the Reddit format method changes.

The code snippet is rather simple, and shows you how to accept input into a JavaScript Zapier Action using the inputData variable, and also provide it as an output:

js
const slackMessage = inputData.message
output = [{id: 123, message: slackMessage}];
Enter fullscreen mode Exit fullscreen mode

The array representation isn’t strictly needed, but it’s a way of letting Zapier know that it needs to repeat subsequent Actions following this one, multiple times, with each payload (or object values) in the array.

The following is a screenshot for reference:

JavaScript in Code Zapier Action showing how to accept input from previous actions, process them, and create a new output response for the next Zapier Action which in our case is a Slack bot integration.

Send Channel Message in Slack

We’ve finally reached the last step of building the Slack bot Reddit automation — posting the message we’ve processed in the former steps to a Slack channel.

To do so, be sure you’ve authenticated Zapier as a general integration application into Slack, and given it access to list your Slack channels and other permissions, such as message posting.

Add a new Zapier Action, and choose Slack as the option for Application. In the Event form field, choose Send Channel Message. Then, go to the Choose Account option, and ideally, enter your Slack account so that the messages will come from your user profile. Otherwise, you can use the Slack box integration account as a general user.

At the moment, this should look as follows:

Setup the Slack bot integration to Send Channel Message in Slack for the Reddit top posts.

Then, proceed to Set up action and enter the following information:

  • The channel to post the message to (denoted as Channel option in the UI)
  • The Message Text option, which should be pre-populated by the prior Zapier Action Message field

The setup should look similar to the following:

Zapier Set up Action integration for Slack bot.

Lastly, you can trigger a manual test execution of this Zapier workflow, which should look as follows:

Zapier reset & review action.

After reviewing and running a test of the Zapier workflow, click the Publish Zap button — which will enable the workflow and start automating based on the recurring schedule we’ve set as a trigger.

How do you connect Slack API to other APIs?

You can build Slack bot APIs beyond just sending a channel message with Zapier. Here are some Slack bot JavaScript ideas that you can build on top of Zapier: sending a Slack message when a Google Sheet row is updated, send approaching Google Calendar events to a Slack channel, share new Twitter mentions in Slack, or even just update your Slack status during Google Calendar events or based on other activities that you can connect with Zapier APIs.

You built a Zapier Reddit integration!

Today, we learned how to build a Slack bot that automatically sends a channel message from top trending Reddit news, using a publicly accessible JSON endpoint or Reddit oAuth API key.

As a closing note, if you’re building a Slack bot integration that is powered by a JavaScript code, be sure you’re following up on relevant JavaScript security practices, and understand the risks associated with that, so that you don’t endanger your business with security issues.

Top comments (0)