<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Phoebe</title>
    <description>The latest articles on DEV Community by Phoebe (@totorosyd).</description>
    <link>https://dev.to/totorosyd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F470102%2F60a01f6d-1a49-4759-a37f-0dac13b2daca.png</url>
      <title>DEV Community: Phoebe</title>
      <link>https://dev.to/totorosyd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/totorosyd"/>
    <language>en</language>
    <item>
      <title>How to find and read API/ or Technical Docs</title>
      <dc:creator>Phoebe</dc:creator>
      <pubDate>Tue, 17 Nov 2020 02:16:58 +0000</pubDate>
      <link>https://dev.to/totorosyd/how-to-find-and-read-api-technical-docs-2b83</link>
      <guid>https://dev.to/totorosyd/how-to-find-and-read-api-technical-docs-2b83</guid>
      <description>&lt;p&gt;In this article, I will share my strategy on how to find and read technical documentation. While most articles help you read well-written, well-maintained docs, I will share my approach on how to navigate a not-so-friendly docs (&lt;a href="https://microsoft.github.io/monaco-editor/"&gt;Monaco Code editor&lt;/a&gt; with an example from my project &lt;a href="https://www.query.cafe/"&gt;query.cafe&lt;/a&gt;.&lt;br&gt;
For this topic, I also made a &lt;a href="https://www.youtube.com/watch?v=aRxzMpj4iZY&amp;amp;feature=youtu.be&amp;amp;ab_channel=PhoebeNguyen"&gt;Youtube video&lt;/a&gt; to show you some examples!&lt;br&gt;
.....&lt;br&gt;
Unfortunately, I can only see a few comprehensive articles and videos to learn the “reading strategy”.&lt;br&gt;
So, now there is one more article to help beginner developers. Let’s dive in!&lt;/p&gt;

&lt;h1&gt;
  
  
  Why “read the manual” skill is essential but underestimated?
&lt;/h1&gt;

&lt;p&gt;Most people can read, and it is &lt;strong&gt;the brain assuming it can read anything easily&lt;/strong&gt;. Therefore, most beginner developers don’t even realise they don’t know how to read the technical documentation effectively. Reading is handled by default by our &lt;a href="https://www.scientificamerican.com/article/kahneman-excerpt-thinking-fast-and-slow/"&gt;System 1&lt;/a&gt; because it is a habit and a primary skill.&lt;/p&gt;

&lt;p&gt;Also, generally, &lt;strong&gt;technical documentation is dry and not visually attractive&lt;/strong&gt;; even though I believe the team behind the documentation devote lots of effort to make it as straightforward as possible. Because it is boring to read those materials, we tend to skip them. (My favourite Docs are MDN Web Docs and Google API Docs).&lt;/p&gt;

&lt;p&gt;That is why we ignore the “read the manual” skill. However, only in real work, we know its importance. Those documents are &lt;strong&gt;the most reliable, updated source of information&lt;/strong&gt; regarding the technology (&lt;em&gt;language, framework, modules, library&lt;/em&gt;) we are working on. If the technology is mature, there are many tutorials and unofficial articles to go to; so we can compare and don’t rely much on the docs. Yet, if the technology is newly developed, the official documentation is the only choice.&lt;/p&gt;

&lt;h1&gt;
  
  
  My strategy to find and read technical documentation
&lt;/h1&gt;

&lt;p&gt;This is not the “one size fits all” strategy because different materials are written differently. Yet, there are some common things and patterns you can rely on to navigate the docs. Moreover, most docs assume that readers have a reasonable level of understanding of technology and syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  KNOW THE DOCS
&lt;/h2&gt;

&lt;p&gt;Similar to reading a map, you must get yourself familiar with the legends and navigation. There are many things in the docs homepage, some are descriptive, some aren’t, but I usually care about a few things first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scan the page and remember the navigation
&lt;/h3&gt;

&lt;p&gt;As mentioned, there are many things on the homepage with tabs, links, sections. They are very descriptive; so to save time for your next visit; you should let your mind wander and scan through those sections to remember briefly what each section is about.&lt;/p&gt;

&lt;h3&gt;
  
  
  Version
&lt;/h3&gt;

&lt;p&gt;Most cases the version you downloaded are the latest version, so the docs by default support the latest version. However, for example, Python 2 and Python 3 are equally popular, so you should check your project specs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tab “Docs”, “API Docs”, “Getting Started”, “What is…”, “About”
&lt;/h3&gt;

&lt;p&gt;These are things you come to the page for. You want to know what this doc is about and if there are solutions for what you are working on. They also show some use-cases in tutorials so you can get some hints on what function you should look for.&lt;br&gt;
You can’t miss these tabs, and they are usually used universally across docs.&lt;/p&gt;

&lt;h3&gt;
  
  
  “Tutorials”, “Playground”
&lt;/h3&gt;

&lt;p&gt;In these tutorials, you can build small applications using technology. These tutorials cover the basics, but you can learn the documentation pretty fast just by completing the tutorials.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search bar of the page and Brower search (Ctrl + F)
&lt;/h3&gt;

&lt;p&gt;The simple yet powerful tool! I usually have a specific thing to look for in the documentation page. I don’t want to be dragged away by the details on the page.&lt;/p&gt;

&lt;p&gt;Firstly, I use the Browser search to see if what I look for is available on the main page (most likely not but it’s worth trying). Then, I use the Search bar of the page to find from the page directory.&lt;/p&gt;

&lt;p&gt;For example, on Monaco code editor, I want to find a function to help me with “value” displayed in the code editor on query.cafe. So the keyword is “value” or “setvalue” or “set” or “update”.&lt;br&gt;
&lt;strong&gt;With search bar, you should be creative and play the keyword game like you do with Google.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  STRATEGY
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Read with a purpose. Know what is the expected behaviour/ output of the code you want to write.
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;What problem are you trying to solve? There are two scenarios here to consider before diving deeper into the documentation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are looking for &lt;strong&gt;feature-oriented or problem-oriented solutions&lt;/strong&gt;, you should go to complimentary (Google, Stackoverflow, Github Repo, Youtube tutorials) sources first. For example, you want to build a code editor in your web application. Documentation can’t guide you through the process on how to build it, where to start.&lt;/p&gt;

&lt;p&gt;Documentation is &lt;strong&gt;only useful&lt;/strong&gt; when you have a bug to fix, or you look for technical instruction to write a function to do a certain thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Know what you are working on
&lt;/h3&gt;

&lt;p&gt;A string, an array, displaying value issue, handling output value of a method, request from/to the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Some common categories “Event”, “Functions”, and “Classes” are used to group the information.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  4. For &lt;strong&gt;Functions&lt;/strong&gt;, you should look for what &lt;em&gt;Parameters&lt;/em&gt; you need to give, &lt;em&gt;Syntax&lt;/em&gt;, what &lt;em&gt;Output&lt;/em&gt; and what &lt;em&gt;Type of Output&lt;/em&gt; it gives back.
&lt;/h3&gt;

&lt;p&gt;It is essential to know the output from a function because it will link to what you can do next with it.&lt;br&gt;
Also, remember to look for &lt;em&gt;“Events”&lt;/em&gt;, &lt;em&gt;“Classes”&lt;/em&gt;, &lt;em&gt;“Functions”&lt;/em&gt; tab referred from the current section you are in.&lt;/p&gt;

&lt;p&gt;If you have other tips on how to read a technical document, please comment. I think others will find it helpful too.&lt;/p&gt;

</description>
      <category>beginners</category>
    </item>
    <item>
      <title>How I’m learning about APIs by building a Slackbot — Part 2</title>
      <dc:creator>Phoebe</dc:creator>
      <pubDate>Sun, 27 Sep 2020 12:52:10 +0000</pubDate>
      <link>https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-part-2-9mc</link>
      <guid>https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-part-2-9mc</guid>
      <description>&lt;p&gt;Continuing on my &lt;a href="https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-part-1-2hmf"&gt;HelloWorld&lt;/a&gt; version, I completed my HelloGalaxy version. This journal article is to share the development process of heybot’s HelloGalaxy version, and one of my favourite challenges which there was no official documentation and I figured out my own solution (using private_metadata).&lt;/p&gt;

&lt;p&gt;My full code is available &lt;a href="https://github.com/TotoroSyd/heybot/blob/master/heybot_v2.py"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Roadmap
&lt;/h1&gt;

&lt;h5&gt;
  
  
  &lt;a href="https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-14h2"&gt;&amp;gt;&amp;gt;Project Overview&lt;/a&gt;
&lt;/h5&gt;

&lt;h5&gt;
  
  
  &lt;a href="https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-part-1-2hmf"&gt;&amp;gt;&amp;gt; Part 1: Hello World version&lt;/a&gt;
&lt;/h5&gt;

&lt;h5&gt;
  
  
  &amp;gt;&amp;gt; Part 3: Final version (coming up next)
&lt;/h5&gt;

&lt;p&gt;Recalling from my original roadmap, this is where we stand.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F11rqjc5c5syeyn3a2asn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F11rqjc5c5syeyn3a2asn.jpg" alt="Alt Text" width="800" height="1511"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Demo
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2720l916xkqgdak0sw20.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2720l916xkqgdak0sw20.gif" alt="Alt Text" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Objectives
&lt;/h1&gt;

&lt;p&gt;In this version, my goals were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To connect to BambooHR API by creating a trial account and Token key.&lt;/li&gt;
&lt;li&gt;When I say “Hello”, heybot replies with action options (buttons).&lt;/li&gt;
&lt;li&gt;When I click on a button to choose the service, heybot askes for employee ID via a &lt;code&gt;Modal&lt;/code&gt;.
Heybot returns answers to me.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;
&lt;h4&gt;
  
  
  BambooHR API
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://documentation.bamboohr.com/docs"&gt;Documentation&lt;/a&gt; is clear and well organized; APIs are grouped by activities (Report, Login, Employees).&lt;br&gt;
I wanted to build heybot for one single customer, so all I needed was &lt;strong&gt;(1)&lt;/strong&gt; an account (&lt;strong&gt;NOTE: a trial account is valid in 7 days only&lt;/strong&gt;), &lt;strong&gt;(2)&lt;/strong&gt; subdomain is “&lt;em&gt;mycompany&lt;/em&gt;” which I created when I opened my trial account (My company is &lt;strong&gt;monsterinc&lt;/strong&gt; :D), &lt;strong&gt;(3)&lt;/strong&gt; an API key which I made from my trial account “&lt;em&gt;Settings&lt;/em&gt;”.&lt;br&gt;
How I create an API key:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb0t1heniptc0x05vvl33.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb0t1heniptc0x05vvl33.gif" alt="How I create an API key" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
I recommend copying the API key and saving it in a note because we have to use it frequently.&lt;br&gt;
One more important thing that you should note is the AUTHORIZATION_TOKEN (&lt;strong&gt;"Basic NDJim&lt;/strong&gt;******** *&lt;em&gt;) in *headers&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why do we need this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can't use the API key to send an HTTP Request to BambooHR directly. An API key will have to be converted into an authorization token.&lt;br&gt;
Before running the Flask app, we have to "&lt;code&gt;export AUTHORIZATION_TOKEN= "NDJim**********&lt;/code&gt;" to be an environment variable (similar to what I did to &lt;code&gt;SLACK_TOKEN&lt;/code&gt; and &lt;code&gt;SLACK_SIGNING_SECRET&lt;/code&gt; which I explained in &lt;a href="https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-part-1-2hmf"&gt;Step 3.1 here&lt;/a&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How to use BambooHR API Key to find &lt;code&gt;AUTHORIZATION TOKEN&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Go to the &lt;a href="https://documentation.bamboohr.com/reference#get-employee"&gt;API Reference&lt;/a&gt; page and choose an API and "&lt;em&gt;Try It&lt;/em&gt;". &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fudj3cfdnlgfa4veacwlb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fudj3cfdnlgfa4veacwlb.gif" alt="Alt Text" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Challenges and Solutions
&lt;/h1&gt;
&lt;h4&gt;
  
  
  Find the right documentations on Slack API
&lt;/h4&gt;

&lt;p&gt;Slack has been upgrading its API, and because of that, some features or methods were either discontinued or were still in use, but their support resources were deprecated.&lt;br&gt;
In HelloGalaxy version, I needed to build:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;rich-text messages containing buttons/ menu/ date picker&lt;/li&gt;
&lt;li&gt;a modal.
For &lt;strong&gt;#1&lt;/strong&gt;, Slack introduced &lt;a href="https://api.slack.com/block-kit"&gt;&lt;code&gt;Blocks&lt;/code&gt;&lt;/a&gt; (supported by &lt;strong&gt;Block Kit Builder&lt;/strong&gt; to replace &lt;code&gt;attachments&lt;/code&gt; according to this &lt;a href="https://api.slack.com/messaging/attachments-to-blocks"&gt;post&lt;/a&gt;. The purpose of this upgrade is to support more interactive features (vote, buttons, menu) or rich contents (video, link, image).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is my action message built with &lt;code&gt;Blocks&lt;/code&gt; and sent to the user by &lt;code&gt;chat_postMessage()&lt;/code&gt; method. &lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx011vjutzmaukih2536m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx011vjutzmaukih2536m.png" alt="Alt Text" width="492" height="94"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see my &lt;a href="https://github.com/TotoroSyd/heybot/blob/master/messages.py"&gt;Block payload here&lt;/a&gt; under &lt;code&gt;def understood_greeting(self, user)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;#2&lt;/strong&gt;, &lt;code&gt;Modal&lt;/code&gt; replaced &lt;code&gt;Dialogs&lt;/code&gt; according to this &lt;a href="https://api.slack.com/block-kit/dialogs-to-modals"&gt;post&lt;/a&gt;. This change led to the retirement of &lt;a href="https://api.slack.com/methods/dialog.open"&gt;&lt;code&gt;dialog.open()&lt;/code&gt;&lt;/a&gt; method and the introduction of &lt;a href="https://api.slack.com/reference/surfaces/views"&gt;&lt;code&gt;views.open()&lt;/code&gt;&lt;/a&gt; method to open Modal (we can't use &lt;code&gt;chat_postMessage()&lt;/code&gt; or other regular methods to open a &lt;code&gt;Modal&lt;/code&gt;).&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7uc3mo47s34qqbbks631.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7uc3mo47s34qqbbks631.gif" alt="A pop-up modal" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Get content from request body with &lt;code&gt;Content-type = application/x-www-form-urlencoded&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Normally, working with &lt;code&gt;Content-type = application/JSON&lt;/code&gt; is very easy and straightforward. We can use &lt;code&gt;request.data&lt;/code&gt;, &lt;code&gt;request.get_data&lt;/code&gt;, &lt;code&gt;request.json&lt;/code&gt;, &lt;code&gt;request.get_json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt; is a bytestring type file. So, if we use &lt;strong&gt;&lt;code&gt;request.data&lt;/code&gt;&lt;/strong&gt; (the common solution), we will get an empty string.&lt;br&gt;
This &lt;a href="https://stackoverflow.com/questions/10434599/get-the-data-received-in-a-flask-request"&gt;StackOverflow post&lt;/a&gt; is a comprehensive answer. My full answer with details was in here too. Below is my solution for your quick look.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ app.route('/slack/request_handler', methods=['POST'])
def request_handler():
   # return an ImmutableMultiDict with 1 pair
   payload = request.form 

   # get value of key 'payload'
   a1 = payload['payload']  

   # Note that if you have single quotes as a part
   # of your keys or values, this will fail due to
   # improper character replacement.
   # Convert a string (representation of a Dict))
   # to a Dict
   a2 = json.loads(a1)

   # Get value of key "channel"
   channel = a2["channel"] 
   print(channel) 
   # {'id': 'D01ACC2E8S3', 'name': 'directmessage'}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Using private_metadata to solve view_submission payload's limitations.
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: When a button clicked, it sends back a &lt;code&gt;block_actions&lt;/code&gt; payload8 containing &lt;code&gt;channel_id&lt;/code&gt;, &lt;code&gt;action_id&lt;/code&gt;. When a modal is closed (made submission), a &lt;code&gt;view_submission&lt;/code&gt; payload is sent.&lt;br&gt;
I save samples of &lt;code&gt;block_actions&lt;/code&gt; payload and &lt;code&gt;view_submission&lt;/code&gt; payload &lt;a href="https://github.com/TotoroSyd/heybot/blob/master/payload.py"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;Modal&lt;/code&gt; appears to get Employee ID input from a user. Once the user provided the ID and clicked "&lt;em&gt;Submit&lt;/em&gt;", a &lt;code&gt;view_submission&lt;/code&gt; payload was sent to my server.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I used that ID to get the answer from BambooHR.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I wanted to reply to the user.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Problem:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To call the correct function to send a &lt;code&gt;GET&lt;/code&gt; request to BambooHR and build a right template message, need an &lt;a href="https://api.slack.com/messaging/attachments-to-blocks#callback_id_replacement"&gt;&lt;code&gt;action_id&lt;/code&gt;&lt;/a&gt; which I set when I created the &lt;code&gt;Block&lt;/code&gt; message. &lt;code&gt;view_submission&lt;/code&gt; payload &lt;strong&gt;doesn't have&lt;/strong&gt; &lt;code&gt;action_id&lt;/code&gt;.&lt;br&gt;
In order to reply, a &lt;code&gt;channel_id&lt;/code&gt; is a must. &lt;code&gt;view_submission&lt;/code&gt; payload &lt;strong&gt;doesn't have&lt;/strong&gt; &lt;code&gt;channel_id&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Solution:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There was no official documentation on this from Slack. However, I utilized &lt;a href="https://api.slack.com/block-kit/dialogs-to-modals#state"&gt;&lt;code&gt;private_metadata&lt;/code&gt;&lt;/a&gt; to store the &lt;code&gt;action_id&lt;/code&gt; received from the &lt;code&gt;block_actions&lt;/code&gt; payload.&lt;br&gt;
This &lt;a href="https://api.slack.com/block-kit/dialogs-to-modals#responding"&gt;Slack doc&lt;/a&gt; suggested storing &lt;code&gt;channel_id&lt;/code&gt; in &lt;code&gt;private_metadata&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pseudocode&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2nn14637n81fwtedceco.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2nn14637n81fwtedceco.png" alt="Alt Text" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Code&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# build view payload
def get_employee_id_modal(self, channel_id, action_id):
    private_metadata = {
       "channel_id": channel_id,
       "action_id": action_id
    }
    # jsonify a dict into a string 
    # (required type for private_metadata)
    json_private_metadata = 
    json.dumps(private_metadata)

    # return a block
    return ({
      "type": "modal",
      "private_metadata": json_private_metadata,
      "callback_id": "employee_id_modal",
      [....]
      })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Thanks for reading!&lt;br&gt;
Phoebe&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>python</category>
      <category>wecoded</category>
      <category>slackbot</category>
    </item>
    <item>
      <title>How I’m learning about APIs by building a Slackbot</title>
      <dc:creator>Phoebe</dc:creator>
      <pubDate>Mon, 21 Sep 2020 05:35:14 +0000</pubDate>
      <link>https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-14h2</link>
      <guid>https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-14h2</guid>
      <description>&lt;h1&gt;
  
  
  Project Context
&lt;/h1&gt;

&lt;p&gt;I have an HR background and with my experiences as an HR Partner in tech and banking industry, I see so much potential to improve the HR field with technology. Some areas to start with: communication, data management, data analytics, paperless process, automation workflow, knowledge management system and smart decision making using AI.&lt;/p&gt;

&lt;p&gt;There have been so many great products to transform HR such as CultureAmp, Workday, Zendesk, Trello but I’ll say &lt;strong&gt;“We can do more!”&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I chose to build a &lt;strong&gt;Slackbot&lt;/strong&gt; because a smart virtual assistant helps to improve productivity for both employees and HR team. For example, an employee is going to have a secondment wants to know about their journey (host-country’s culture, law, tax, company benefits, project details…). Traditionally, HR prepares lots of materials and training. But when employees want to check on certain things, either they have to read the materials again or ask HR again…and again. Both ways waste time and repeat communications.&lt;/p&gt;

&lt;p&gt;Also, I finished my first project Eatthefrog, and it is a client-side web app. It runs on users’ browser and uses local storage to store tasks made by them, so it doesn’t “talk” to any server. With this Slackbot project (the bot’s name is &lt;strong&gt;heybot&lt;/strong&gt; :), I will know how to answer those questions. Because I will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Be a SERVER receiving/responding requests from a user (via heybot on Slack) aka CLIENT.&lt;/li&gt;
&lt;li&gt;Be a CLIENT sending requests and receiving responses from a SERVER (BambooHR in this case).&lt;/li&gt;
&lt;li&gt;Practice working with APIs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;So, what is heybot?&lt;/strong&gt;&lt;br&gt;
heybot is a Slackbot that integrates with BambooHR, and it assists employees (1) to know information about their time off, (2) to request time off on BambooHR from Slack and get request update.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/TotoroSyd/heybot"&gt;Github repo&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Roadmap
&lt;/h1&gt;

&lt;p&gt;This project is more complicated, so I broke it down to multiple versions. For each version (milestone), I have separated post to give you more insights about that version’s development story.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;a href="https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-part-1-2hmf"&gt;&amp;gt;&amp;gt; Part 1: Hello World version&lt;/a&gt;
&lt;/h5&gt;

&lt;h5&gt;
  
  
  &amp;gt;&amp;gt; Part 2: Hello Galaxy version (coming up next)
&lt;/h5&gt;

&lt;h5&gt;
  
  
  &amp;gt;&amp;gt; Part 3: Final version (coming up next)
&lt;/h5&gt;

&lt;p&gt;Here is the bird’ s-eye view of the project.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9f4erdy7kgp5t8z5mkij.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9f4erdy7kgp5t8z5mkij.jpg" alt="Alt Text" width="800" height="917"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Technology Choices
&lt;/h1&gt;

&lt;h4&gt;
  
  
  Python or Nodejs
&lt;/h4&gt;

&lt;p&gt;While choosing Nodejs is a rational choice because I don’t have to face “environment change” issue and not to mention Slack API’s well-supported libraries and tools, I chose Python.&lt;/p&gt;

&lt;p&gt;Inspired by Alexa, I want heybot to have conversations as natural as possible with a user, and it can “understand” the user’s intention/ request without fixed commands. Therefore, Python is a better choice. It has several popular and commonly used (Natural Language Processing) NLP libraries.&lt;/p&gt;

&lt;h4&gt;
  
  
  Flask vs Django
&lt;/h4&gt;

&lt;p&gt;These are two popular frameworks for Python. According to some references &lt;a href="https://medium.com/@SteelKiwiDev/flask-vs-django-how-to-understand-whether-you-need-a-hammer-or-a-toolbox-39b8b3a2e4a5"&gt;#1&lt;/a&gt;, &lt;a href="http://www.mindfiresolutions.com/blog/2018/05/flask-vs-django/#:~:text=Django%20is%20a%20full%2Dstack%20web%20framework%2C%20whereas%20Flask%20is,by%20providing%20the%20required%20functionality."&gt;#2&lt;/a&gt;, &lt;a href="https://hackr.io/blog/flask-vs-django"&gt;#3&lt;/a&gt;, and the fact that I don’t need to build a web interface for heybot, Flask is a suitable framework. It provides enough functionalities for me to run heybot. Also, &lt;a href="https://slack.dev/python-slackclient/"&gt;slackclient&lt;/a&gt; — Slack Developer Kit uses Flask.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;br&gt;
Phoebe&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>python</category>
      <category>wecoded</category>
      <category>slackbot</category>
    </item>
    <item>
      <title>How I’m learning about APIs by building a Slackbot — Part 1</title>
      <dc:creator>Phoebe</dc:creator>
      <pubDate>Mon, 21 Sep 2020 05:07:45 +0000</pubDate>
      <link>https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-part-1-2hmf</link>
      <guid>https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-part-1-2hmf</guid>
      <description>&lt;p&gt;This is my journal article for the development process of heybot’s Hello world version. I will write from a beginner’s perspective so it can be lengthy (a bit), but I hope other beginners will find it useful.&lt;/p&gt;

&lt;p&gt;The project overview is &lt;a href="https://dev.to/totorosyd/how-i-m-learning-about-apis-by-building-a-slackbot-14h2"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/TotoroSyd/heybot/blob/master/heybot_v1.py"&gt;fullcode&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Objective
&lt;/h1&gt;

&lt;p&gt;In this version, my purposes were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect heybot (the back-end is stored in my laptop) to Slack server&lt;/li&gt;
&lt;li&gt;When I say “Hello”, heybot replies “Hello ”&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Know the resources
&lt;/h1&gt;

&lt;p&gt;These resources are all I need to build the Helloworld version and upgrade it to the final version.&lt;/p&gt;

&lt;h4&gt;
  
  
  General knowledge about API
&lt;/h4&gt;



&lt;h4&gt;
  
  
  Flask
&lt;/h4&gt;

&lt;p&gt;I didn’t have a server, so using Flask I can create my webserver. With Flask I can handle web requests quickly (with no configuration).&lt;/p&gt;

&lt;h4&gt;
  
  
  ngrok
&lt;/h4&gt;

&lt;p&gt;Thanks to Flask, I technically have a server on my Mac. But I am still invisible to other web services (servers) — in this case, they are Slack and BambooHR.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wait! Why? Don’t you usually still access those services via your browser?&lt;/strong&gt;&lt;br&gt;
Ok! I can “talk” to them because I am one of their &lt;strong&gt;clients&lt;/strong&gt;. They are visible in public web with a static address (domain). So, I can find them, ask them to give me the services whenever I want. They are going nowhere(unless they shut down their businesses).&lt;/p&gt;

&lt;p&gt;Back to “&lt;em&gt;But I am still invisible to other web services (servers)&lt;/em&gt;”, I’m having heybot as a service provider. According to the explanation above, if I want to “run my business”, I need to have a static address, too. This means I need to have a public address that can be found by other clients (can be another service provider (Slack, BambooHR) or a regular user).&lt;/p&gt;

&lt;p&gt;In a nutshell, ngrok helps to create a tunnel so those web services can “see/ find” me. And, when they send me requests, thanks to ngrok’s tunnel, I can receive and respond to those requests.&lt;/p&gt;
&lt;h4&gt;
  
  
  Slack API
&lt;/h4&gt;

&lt;p&gt;They have a few core APIs — Web API, Event API and other APIs.&lt;/p&gt;
&lt;h4&gt;
  
  
  Developer Kit for Python — slackclient
&lt;/h4&gt;

&lt;p&gt;Slack prepares some tool kits for different programming languages to work with their server.&lt;/p&gt;
&lt;h4&gt;
  
  
  Slack Events API adapter for Python — python-slack-events-api
&lt;/h4&gt;

&lt;p&gt;After hours of internet browsing and reading tutorials and docs, to build the Helloworld version, using Slack Events API adapter is a recommended and preferred approach. It is also easy to use too.&lt;br&gt;
&lt;strong&gt;Hint&lt;/strong&gt;: You might find some tutorials using RTM — Real Time Messaging API. According to this tutorial, &lt;em&gt;“you can stream events through a websocket connection with our RTM API. The RTM API is only recommended if you’re behind a firewall and cannot receive incoming web requests from Slack. ⚠️ The RTM API isn’t available for default Slack apps. If you need to use RTM (possibly due to corporate firewall limitations), you can do so by creating a classic Slack app”&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Step-by-step
&lt;/h1&gt;

&lt;p&gt;There are plenty of materials to help you create a simple Slackbot. So, I won’t repeat what they said. Instead, I follow the same steps, link to what materials I found useful, and I only write what I figured out.&lt;/p&gt;

&lt;p&gt;⚠️Before starting, remember to set up a virtual environment. It is a &lt;strong&gt;MUST&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Create a Slack app
&lt;/h4&gt;

&lt;p&gt;This step is straightforward on Slack API docs and also in &lt;a href="https://github.com/slackapi/python-slackclient/blob/main/tutorial/01-creating-the-slack-app.md"&gt;this step of this tutorial&lt;/a&gt;. &lt;/p&gt;
&lt;h4&gt;
  
  
  2. Build the message
&lt;/h4&gt;

&lt;p&gt;In &lt;a href="https://github.com/slackapi/python-slackclient/blob/main/tutorial/02-building-a-message.md"&gt;step 2 of this tutorial&lt;/a&gt;, they prepared a complex message, but Helloworld version only needs heybot to say “&lt;em&gt;Hello &lt;/em&gt;”. So, I skipped that step.&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Prepare to pass URL verification challenge from Slack
&lt;/h4&gt;

&lt;p&gt;The URL generated by ngrok must pass this test.&lt;br&gt;
You should print the request to see what it has. Trust me, it helps a lot, knowing what is sending to you.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuhcdlunt1q5qa0oi15r6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuhcdlunt1q5qa0oi15r6.png" alt="Alt Text" width="630" height="389"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
 &lt;span class="c1"&gt;# print(request.headers)
&lt;/span&gt; &lt;span class="c1"&gt;# print(request.data)
&lt;/span&gt; &lt;span class="c1"&gt;# print(request.args)
&lt;/span&gt; &lt;span class="c1"&gt;# print(request.form)
&lt;/span&gt; &lt;span class="c1"&gt;# print(request.endpoint)
&lt;/span&gt; &lt;span class="c1"&gt;# print(request.method)
&lt;/span&gt; &lt;span class="c1"&gt;# print(request.remote_addr)
&lt;/span&gt;
 &lt;span class="c1"&gt;# get ready to receive and respond HTTP POST
&lt;/span&gt; &lt;span class="c1"&gt;# request from Slack to verify bot's endpoint URL
&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;challenge_parse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 
                   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;challenge&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;# print(challenge_parse)
&lt;/span&gt;  &lt;span class="c1"&gt;# respond URL verification from Slack  
&lt;/span&gt;  &lt;span class="c1"&gt;# with 'challenge' value
&lt;/span&gt;  &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;challenge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;challenge_parse&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3.1 Respond to Slack Event
&lt;/h4&gt;

&lt;p&gt;This step is the key to make heybot alive. It is in &lt;a href="https://github.com/slackapi/python-slackclient/blob/main/tutorial/03-responding-to-slack-events.md"&gt;step 3 of this tutorial&lt;/a&gt;.&lt;br&gt;
&lt;em&gt;Explanation:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# import dependencies to obtain the environment variable values
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt; 
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;slack&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;slackeventsapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SlackEventAdapter&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsonify&lt;/span&gt;

&lt;span class="c1"&gt;# Import environment var by retrieving exported token https://slack.dev/python slackclient/auth.html
&lt;/span&gt;&lt;span class="n"&gt;SLACK_BOT_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SLACK_BOT_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;SLACK_SIGNING_SECRET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SLACK_SIGNING_SECRET&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  What is os?
&lt;/h6&gt;

&lt;p&gt;The OS module in Python provides functions for interacting with the operating system. In this case, I had to use SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET. They are confidential, so we shouldn’t set them as variables in our code. I made them as &lt;em&gt;environment variables&lt;/em&gt; (use &lt;code&gt;export&lt;/code&gt; command) =&amp;gt; if I share the code, no one can see unless I gave them the tokens. So, os helps to call out &lt;em&gt;environment variables&lt;/em&gt;.&lt;/p&gt;

&lt;h6&gt;
  
  
  What is json module?
&lt;/h6&gt;

&lt;p&gt;Data in a request that a server sends/ receives is a JSON object. I need to parse JSON (in Python, parse JSON means &lt;code&gt;json.loads&lt;/code&gt;)&lt;br&gt;
                      ----------&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# create the Flask server
&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize a Slack Event Adapter for receiving actions 
&lt;/span&gt;&lt;span class="n"&gt;slack_events_adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SlackEventAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SLACK_SIGNING_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/slack/events&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Instantiate a Web API client
&lt;/span&gt;&lt;span class="n"&gt;slack_web_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WebClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SLACK_BOT_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;slackclient v2 separated WebClient and RTMClient. You can read about the differences in this &lt;a href="https://github.com/slackapi/python-slackclient/wiki/Migrating-to-2.x"&gt;Migration guide&lt;/a&gt;.&lt;br&gt;
                       ----------&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Routing
&lt;/span&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All functions go under this route.&lt;/p&gt;

&lt;p&gt;In Flask docs, you see they create multiple &lt;em&gt;routes&lt;/em&gt;, which is for building a website where you have multiple pages, and each page has its &lt;em&gt;path&lt;/em&gt; (&lt;em&gt;route&lt;/em&gt;). We are building a chatbot, and we only need one end-point handling requests sent from Slack.&lt;br&gt;
                      ----------&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# When a user sends a DM, the event type will be
# 'message'.
# Link the message callback to the 'message' event.
# Choose to use Event API (handled by
# SlackEventAdapter) instead of RTM API.
&lt;/span&gt;
&lt;span class="nd"&gt;@slack_events_adapter.on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
     &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;event&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

     &lt;span class="c1"&gt;# if the incoming message contains "hello" 
&lt;/span&gt;     &lt;span class="c1"&gt;# NOT CASE SENSITIVE, respond with a message
&lt;/span&gt;     &lt;span class="c1"&gt;# check if the message is from a bot or not.  
&lt;/span&gt;     &lt;span class="c1"&gt;# If Yes, do nothing. If No, reply.
&lt;/span&gt;     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bot_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; 
     &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
          &lt;span class="n"&gt;channel_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;channel&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello &amp;lt;@%s&amp;gt;! :tada:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
          &lt;span class="n"&gt;slack_web_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat_postMessage&lt;/span&gt; 
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;channel_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt;

&lt;span class="c1"&gt;# Error events
&lt;/span&gt;&lt;span class="nd"&gt;@slack_events_adapter.on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;error_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
     &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;slack_events_adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The syntax for this code you can read from &lt;a href="https://github.com/slackapi/python-slack-events-api/blob/main/example/example.py"&gt;this example&lt;/a&gt;, &lt;a href="https://api.slack.com/methods/chat.postMessage"&gt;&lt;code&gt;chat_postmessage&lt;/code&gt;&lt;/a&gt; method.&lt;/p&gt;

&lt;h1&gt;
  
  
  Challenges and Solutions
&lt;/h1&gt;

&lt;h4&gt;
  
  
  heybot can’t distinguish between its messages and user’s messages
&lt;/h4&gt;

&lt;p&gt;Because of that, it replies non-stop.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1ugoeq4m480q7tgar2pc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1ugoeq4m480q7tgar2pc.png" alt="Alt Text" width="393" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Solution on &lt;a href="https://stackoverflow.com/questions/59489908/slack-events-api-events-are-posted-multiple-times-for-responses-of-own-bot-us/59519428#59519428"&gt;this StackOverflow post&lt;/a&gt; was the most relevant and well-described, but it mentioned a solution checking for &lt;code&gt;subtype&lt;/code&gt; in the request’s &lt;code&gt;event&lt;/code&gt;, which wasn’t there.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F81c6sdqpqpy7enpn8e6w.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F81c6sdqpqpy7enpn8e6w.jpg" alt="Alt Text" width="800" height="600"&gt;&lt;/a&gt;&lt;br&gt;
My solution was to check for &lt;code&gt;bot_id&lt;/code&gt; from &lt;code&gt;event&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# some code
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bot_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="p"&gt;.....:&lt;/span&gt;
&lt;span class="c1"&gt;# some code
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  [Errno 48] Address already in use
&lt;/h4&gt;

&lt;p&gt;Occasionally, when you run ngrok, this error comes because sometimes the system didn’t kill the program process properly when you asked.&lt;/p&gt;

&lt;p&gt;The solution is to use &lt;code&gt;kill -9&lt;/code&gt;, which is &lt;a href="https://unix.stackexchange.com/questions/8916/when-should-i-not-kill-9-a-process"&gt;not very recommended&lt;/a&gt; but it worked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# list of processes using the port if any &lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;lsof &lt;span class="nt"&gt;-i&lt;/span&gt;:5000   
&lt;span class="c"&gt;# or &lt;/span&gt;
ps &lt;span class="nt"&gt;-a&lt;/span&gt; 

&lt;span class="c"&gt;# use the id on the PID column to terminate the process use &lt;/span&gt;
&lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;PID&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# if the above doesnt solve the problem, use this. Not very recommended :D. &lt;/span&gt;
&lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="nt"&gt;-9&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;PID&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Phew! Thanks for reading this lengthy post. You are awesome! I explained the technical work with my own knowledge, so if they aren’t correct, please tell me.&lt;/p&gt;

&lt;p&gt;Phoebe&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>python</category>
      <category>wecoded</category>
      <category>slackbot</category>
    </item>
  </channel>
</rss>
