<?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: Varun Raj</title>
    <description>The latest articles on DEV Community by Varun Raj (@zathvarun).</description>
    <link>https://dev.to/zathvarun</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%2F55562%2Fae469c25-5838-429b-92d3-3f47bb35d71f.jpg</url>
      <title>DEV Community: Varun Raj</title>
      <link>https://dev.to/zathvarun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zathvarun"/>
    <language>en</language>
    <item>
      <title>Building Gmail Addons</title>
      <dc:creator>Varun Raj</dc:creator>
      <pubDate>Mon, 30 Nov 2020 12:17:59 +0000</pubDate>
      <link>https://dev.to/skcript/building-gmail-addons-1e22</link>
      <guid>https://dev.to/skcript/building-gmail-addons-1e22</guid>
      <description>&lt;p&gt;Addons and integrations are the most impactful features when it comes to building SaaS products. The reason being the more your tool integrates with others, the more reach and user base it gets. Basically when you integrate with popular tools or products like Gmail which is already used by millions of people, your product just gets super charged.&lt;/p&gt;

&lt;p&gt;Today, you’ll learn how to build one such cool add-on for your app, and yes, it's gonna run on Gmail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: The Setup
&lt;/h3&gt;

&lt;p&gt;One new thing about this, is that you don't need to worry about your local environment when developing, as everything happens inside your browser on a platform called &lt;strong&gt;Google App Scripts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Navigate to &lt;a href="http://script.google.com/home"&gt;http://script.google.com/home&lt;/a&gt; and create a new project from the sidebar option.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image5-29.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image5-29.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A new editor window opens where you’re going to spend most of your time building the addon.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image8-9.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image8-9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the “&lt;strong&gt;Untitled project&lt;/strong&gt;” to edit the project name to your app name, in my case I'm going to create an addon to show the latest news.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image4-37.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image4-37.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you name the project, you need to create a manifest file. It's more like the manifest file we create for our Chrome Apps or an Outlook Plugin. It contains meta information, scope to access, and other such information about the app.&lt;/p&gt;

&lt;p&gt;Click on “View → Show manifest file” from the menu bar and it opens a new file named “&lt;strong&gt;appsscript.json&lt;/strong&gt;”&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image7-16.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image7-16.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The contents of the manifest file is in JSON format and will hold the below information by default,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timeZone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Asia/Kolkata"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exceptionLogging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"STACKDRIVER"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"runtimeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"V8"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Configuration
&lt;/h3&gt;

&lt;p&gt;Now that we’ve our base of the addon, let's configure it to work in Gmail.&lt;/p&gt;

&lt;p&gt;Under the dependencies section of the manifest add the gmail service with the following config,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"enabledAdvancedServices"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"userSymbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Gmail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"serviceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"gmail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"v1"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After defining that we’re going to use the Gmail service, we need to define the behaviour, appearance of the addon inside Gmail.&lt;/p&gt;

&lt;p&gt;Create a new block with the key “gmail” in the manifest root where you enter all the config of Gmail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"gmail"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Today's News"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"logoUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://www.gstatic.com/images/icons/material/system/1x/receipt_black_24dp.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contextualTriggers"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"unconditional"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;

        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

        &lt;/span&gt;&lt;span class="nl"&gt;"onTriggerFunction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"startApp"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"primaryColor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"#F47041"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"secondaryColor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"#2E8B57"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"TRUSTED_TESTER_V2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the config above, the main part to notice is the &lt;em&gt;contextualTriggers&lt;/em&gt; section. It’s an array of functions.&lt;/p&gt;

&lt;p&gt;Currently we’re going to use a simple trigger &lt;em&gt;onTriggerFunction&lt;/em&gt;, which as the name explains will get triggered when the app is opened in the addons section of Gmail. This will call a function defined in any of our .gs files.&lt;/p&gt;

&lt;p&gt;There’s also other cosmetic configurations like name, icon and colors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Creating the UI
&lt;/h3&gt;

&lt;p&gt;The UI is also created by the script in Gmail addon. Open the code.gs and create a new function called &lt;em&gt;startApp&lt;/em&gt;. This function will be triggered when we open the app from the addons section.&lt;/p&gt;

&lt;p&gt;Note: In app script the function names are unique no matter which file you write it.&lt;/p&gt;

&lt;p&gt;Lets create a simple card in the UI&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;startApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CardService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newCardBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NewsListCard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CardService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newCardHeader&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;setTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;News&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sectionNews&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CardService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newCardSection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;sectionNews&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CardService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newTextParagraph&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;News of the day&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sectionNews&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file and lets try to run and see the result&lt;/p&gt;

&lt;p&gt;To test the addon, click on “Publish → Deploy from manifest” in the menu bar,&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image10-7.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image10-7.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This brings up another window that lists all the versions of your addon. Click on the &lt;em&gt;Install add-on&lt;/em&gt; button in the “Latest Version (Head) Version 0” since this is the development version.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image6-21.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image6-21.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once installed, you can open your Gmail account (the one where the app script project was created) to see the addon in the sidebar.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image2-52.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image2-52.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the first run, you need to authorize access to the app to use it. After authorization you can see the cards that we created in the script.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image1-55.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image1-55.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Loading Data From API
&lt;/h3&gt;

&lt;p&gt;We’ve set up the basic card section to show the basic static information of the app. Now let's try to pull in some data from remote API to show in the addons section. Currently I'm going to use a public API for the demo purpose, but you can also use your own APIs to pull your app’s data.&lt;/p&gt;

&lt;p&gt;For this demo I'm going to use &lt;a href="https://newsapi.org/"&gt;&lt;strong&gt;https://newsapi.org/&lt;/strong&gt;&lt;/a&gt; API since it has a free plan and public.&lt;/p&gt;

&lt;p&gt;Sign up for the News API Service and get your API token.&lt;/p&gt;

&lt;p&gt;We’ll be using the UrlFetchApp class to make external API calls. For writing clean code, I’ve created a new file called “APIs.gs” from the file menu&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image11-4.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image11-4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Write the below function to make an API call to the new API with your token in the payload to get the news articles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getNews&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UrlFetchApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://newsapi.org/v2/top-headlines?country=us&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;muteHttpExceptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-Api-Key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR NEWS API KEY HERE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getContentText&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;responseText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getContentText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;responseJSON&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;responseJSON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that our API call is ready, let's call it and render the data in the UI. Open your Code.gs file and add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;startApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// .....&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;newsResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getNews&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;news&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newsResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;news&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;newsItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;news&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;newsBlock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CardService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newDecoratedText&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newsItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;sectionNews&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newsBlock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// …..&lt;/span&gt;
  &lt;span class="c1"&gt;// .....&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sectionNews&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will call the &lt;em&gt;getNews&lt;/em&gt; function and render each item into the sectionNews Card section.&lt;/p&gt;

&lt;p&gt;Save the file and refresh the addon from your Gmail addon panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image3-38.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image3-38.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After refreshing you’ll get the list of news title in the addon screen&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image9-9.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image9-9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And we’ve created a simple addon which can list your daily news inside Gmail! This can be your app’s addon too. The best part is that most of your business users can adopt it so quickly which helps your app grow faster.&lt;/p&gt;

&lt;p&gt;In the next article, I’ll write about how to use user credentials to get the current user info and also session storage. Until then, keep exploring! :D&lt;/p&gt;

</description>
      <category>gmail</category>
      <category>addons</category>
      <category>integrations</category>
      <category>googleappscript</category>
    </item>
    <item>
      <title>Building and Using Custom Entities in Dialogflow</title>
      <dc:creator>Varun Raj</dc:creator>
      <pubDate>Mon, 28 Sep 2020 16:28:36 +0000</pubDate>
      <link>https://dev.to/skcript/building-and-using-custom-entities-in-dialogflow-1g38</link>
      <guid>https://dev.to/skcript/building-and-using-custom-entities-in-dialogflow-1g38</guid>
      <description>&lt;p&gt;In this article, I'll cover how we can create custom entities that cover your business requirements.&lt;/p&gt;

&lt;p&gt;Before proceeding, I strongly recommend you to read my previous article in case if you missed it: &lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/"&gt;https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the entities? a quick recap.&lt;a href="https://www.skcript.com/svr/building-and-using-custom-entities-in-dialogflow/#what-are-the-entities-a-quick-recap"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Entities as something similar to your data types in a programming language that helps you define what sort of data is stored in a variable. Here, entities in chatbot language are nothing but the pattern or the meaning we classify certain parts or elements of the conversation.&lt;/p&gt;

&lt;p&gt;For example, in the below message, the user is asking for weather information in the city of Dubai. So, when configuring the chatbot we classify "Dubai" as the city, and post the training the bot will understand any city.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image6-15.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jMugAdAb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image6-15.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the limitation with inbuilt entities?&lt;a href="https://www.skcript.com/svr/building-and-using-custom-entities-in-dialogflow/#what-is-the-limitation-with-inbuilt-entities"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In Dialogflow, the inbuilt entities are trained based on the generic scenarios like date, city, and other standard units. But in most cases, we've to create our entities to satisfy the business requirements.&lt;/p&gt;

&lt;p&gt;For an instance consider the below statement in an HR chatbot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image4-29.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UgBZgoFD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image4-29.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, we can easily train the bot to extract the start date and end date since it's a very general information class. But the challenge comes when we try to extract the type of leave. The type of leave is information related to a specific requirement. Leave type could change between one organization to another.&lt;/p&gt;

&lt;p&gt;These are the cases that can't be solved with built-in entities and we need to depend on custom entities.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do we create custom entities?&lt;a href="https://www.skcript.com/svr/building-and-using-custom-entities-in-dialogflow/#how-do-we-create-custom-entities"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Let's take our leave application use case for this article. To Dialogflow classify the leave type, we need to create a new entity called "Leave".&lt;/p&gt;

&lt;p&gt;Navigate to the Entities section in the sidebar of the project console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image3-27.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4ST0CfEI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image3-27.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you get to see all the custom entities that you created in your project, let's create our first custom entity.&lt;/p&gt;

&lt;p&gt;If you notice, the Dialogflow gives us the option to create the Entity and various items under that entity. This works more like your enum in programming as I mentioned earlier.&lt;/p&gt;

&lt;p&gt;In our case, under the leave types, we've sick leave, annual leave, and vacation leave. So I create those under the entity items. Also providing more synonyms will help the bot to train for understanding better.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image1-40.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MjyCE8lr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image1-40.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can simply save after you created the required items for the entity. Post the training we can start using these new custom entities in the intent configuration page similar to system entities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image5-23.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FnKwmfE1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image5-23.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's ask the bot question to see if it can classify all the leaves properly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image7.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JkArRfXE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image7.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similar to this you can create any number of custom entities based on your requirements and use them together as well in the intent. Here is a small example from another chatbot project where I've used more than one custom entity in a statement.&lt;/p&gt;

&lt;p&gt;Here both the facility attribute as well as facility entities are custom built for this hotel chatbot where the user asks for details of a facility in the hotel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image2-41.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nNal-wWx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image2-41.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dialogflow</category>
      <category>chatbot</category>
      <category>serverless</category>
      <category>firebase</category>
    </item>
    <item>
      <title>Building a Serverless Telegram Chatbot with Dialogflow and Firebase Functions</title>
      <dc:creator>Varun Raj</dc:creator>
      <pubDate>Mon, 17 Aug 2020 03:18:55 +0000</pubDate>
      <link>https://dev.to/skcript/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions-cl3</link>
      <guid>https://dev.to/skcript/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions-cl3</guid>
      <description>&lt;p&gt;A couple of years back, I was struggling to manage my documents - tried all available cloud storages and even thumb drives. Nothing came handy and also searching documents in cloud storage was never easier for me. So, I decided to build a chatbot which can send me documents whenever I ask for it. That's when I built Nila, my first personal chatbot.&lt;/p&gt;

&lt;p&gt;Often people ask me how I built Nila. They were surprised when I said it is not a rule-based chatbot and it can understand my language. So, later I added more features to it, but that's a different story.&lt;/p&gt;

&lt;p&gt;Since it created a lot of interest among my friends and community, I thought of writing an article about how I built it. And, here it is.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#the-tech-stack"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I wanted it to be a very thin setup and without major maintenance. As soon as this requirement was decided, the first thing that popped into my mind was serverless architecture. The best thing about it is that I don't have to maintain a server - deploying code was a lot easier compared to server infrastructure. The next question that came to my mind was where to store all this information. This is where my 'Swiss army knife' of product development comes into play. In addition, I decided to use Firebase for everything other than the NLP part.&lt;/p&gt;

&lt;p&gt;So, the final tech stack was drilled down to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Firebase Cloud Functions - Backend Processing&lt;/li&gt;
&lt;li&gt; Firebase Storage - File Storage&lt;/li&gt;
&lt;li&gt; Firebase Firestore - For Database&lt;/li&gt;
&lt;li&gt; Dialogflow - For NLP&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Infrastructure&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#the-infrastructure"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The next step was to come up with an infrastructure to build an architecture design that becomes the core. Since the entire system is broken down into distributed modules, I came up with the below setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Use Case&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#the-use-case"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In this article, I'm going to set a simple use case of requesting weather information from the chatbot. And for this, we'll be using the &lt;a href="https://openweathermap.org/"&gt;OpenWeatherMap&lt;/a&gt; API. So in case, you're going to try the same, sign up for it and get yourself an API Key&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Telegram Bot&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#creating-the-telegram-bot"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Creating bots in telegram is pretty much fun but there is no fancy UI to do that. All you have to do is just ask another bot to create your bot.&lt;/p&gt;

&lt;p&gt;There is a bot in telegram called &lt;a href="https://t.me/botfather"&gt;Bot Father&lt;/a&gt; and you have to message the bot to create or manage your bots.&lt;/p&gt;

&lt;p&gt;Send &lt;code&gt;/start&lt;/code&gt; to bot father and it will show you the list of the available options.&lt;/p&gt;

&lt;p&gt;Just click on the &lt;code&gt;/newbot&lt;/code&gt; hyperlink and it will automatically send the slash command to create a new bot for you. Following that, you'll be asked for some basic information like Name for the bot, username (remember it should end with "bot").&lt;/p&gt;

&lt;p&gt;On completing, you'll get a token displayed in the final message from bot father. This token is very important so copy it safely somewhere. In the following sections, we'll refer to this token as the telegram bot token or shortly bot token.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Dialogflow&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#setting-up-dialogflow"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The user-facing piece is now ready. Let's now focus on the bridge part which is our Dialogflow. Setting up DialogFlow is as simple as setting up the telegram bot. All you've to do is to sign up for Dialogflow and create a new agent.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image5-19.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NZjzMwRX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image5-19.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it! You're all set with the Dialogflow project. Now, let's go ahead and connect our telegram to the Dialogflow project.&lt;/p&gt;

&lt;p&gt;Navigate to the integration option in the Dialogflow sidebar. This page will list all the possible platforms that Dialogflow can seamlessly integrate. You can navigate to Telegram and enable the platform. This will bring up an option to configure your bot with the help of the bot's token ID - the token that we got from telegram's bot father earlier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image1-33.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w27IP8kF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image1-33.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste the token in the telegram token field of the modal and click on start to complete your operation. As you connect both of these services, you're ready to talk to your bot.&lt;/p&gt;

&lt;p&gt;Click on the bot's link that's available in the last message from bot father to start the bot. Now, all you can send is just "Hi" and a few other basic greetings. This is because Dialogflow comes with basic greetings inbuilt and for anything more you need to configure it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the Weather intents&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#setting-up-the-weather-intents"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Let's make the bot more meaningful by making it understand what we're trying to ask. To do that we need to create something called Intents in Dialogflow (This is quite a common term used in chatbot domain). Intents are nothing but conversations that happen between the bot and the user. In our case, we're going to ask the bot to give us the weather information, so let's create an Intent called "AskWeather".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image3-22.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qmvwjL-I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image3-22.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The real magic happens when we configure the training phrase.&lt;/p&gt;

&lt;p&gt;The training phrases are nothing but the statements that the user asks or tells the bot in the conversation. In our cases, the phrases could be any of the following for weather information&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"What's the weather in Dubai?"
"What's the weather in Dubai tomorrow?"

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Also, if you notice there is certain information hidden inside these statements, which is nothing but the city of which we're asking the weather for and the time or date. Dialogflow is smart enough to identify these in our conversation and extract them as variables. In case, if the bot is missing it we can also configure ourselves by just selecting and mapping it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image10-4.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2KfTGyYt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image10-4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On scrolling down, you can see "Action and Parameters" which is where we define the properties required and action mapped to this specific intent.&lt;/p&gt;

&lt;p&gt;Actions in Dialogflow intents are nothing more than a namespace that we give to the action performed in webhook, as a result of this intent to get data from your customer services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image11-3.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zmMbqLwQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image11-3.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our case, the city and date are the possible params, but it could be more down the line which we can add on the fly. Also, I've made the city parameter as required field as we won't be able to get the weather information without a city or location. But, the date is optional since we can assume that the user is asking for today's weather, in case if it is not mentioned implicitly.&lt;/p&gt;

&lt;p&gt;Now, that we've configured the intent, we can start testing it. Before that, save the intent and then the system will take some time to retrain the agent. So once it's trained, you can try asking the bot in the interface to the right side.&lt;/p&gt;

&lt;p&gt;In the right section, after asking your question the DF system will parse the statement and show you the action and parameter for the corresponding user phrases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image2-32.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0urZvvfB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image2-32.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Cloud Functions&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#setting-up-cloud-functions"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The dialogs are set now! Time for the geeky stuff. Not every dialog can be answered with some static reply or a bunch of static questions. This is where the webhook/fulfilments come into the place where we can configure intents to be handled by your server. In our case, as our title says we're going to use firebase cloud functions as our backend.&lt;/p&gt;

&lt;p&gt;Let's get started by creating our new firebase project in our local system. In this article, I'm going to use an existing firebase project.&lt;/p&gt;

&lt;p&gt;Setting up the local project&lt;/p&gt;

&lt;p&gt;Create a new folder in a location in your machine and initialize a firebase project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g firebase-tools
mkdir WeatherKiosk
cd WeatherKiosk
firebase init

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The initializer will be a wizard which asks you the project and the modules we need for the project. I'll be selecting the project and the functions as the module.&lt;/p&gt;

&lt;p&gt;On completion, you'll be finding a functions folder where we have the server code. Let's write an endpoint for Dialogflow to use as webhook/fulfillment.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;functions/index.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const functions = require("firebase-functions");

exports.chatWebhook = functions.https.onRequest((request, response) =&amp;gt; {
  response.json({
    fulfillmentMessages: [
      {
        text: {
          text: ["Text response from webhook"],
        },
      },
    ],
  });
});

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, this endpoint will send back a simple text response. For now, I'm having this as a dummy text response. In the later stages, we'll configure the weather API for getting the expected weather data.&lt;/p&gt;

&lt;p&gt;Let's take it to live by deploying the functions with the below code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase deploy --only functions

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After deploying you can get the endpoint from the firebase function's console. Copy the URL, this will be our Webhook's URL in DF.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image7-9.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MbNJ-ZYL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image7-9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configuring the fulfillment in Dialogflow&lt;/p&gt;

&lt;p&gt;In the sidebar of the Dialogflow agent, you'll find the fulfillment section where you need to configure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image9-4.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xmwiPJOl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image9-4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Post that you can configure the intent to use the fulfillment like below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image8-5.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Be9F844b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image8-5.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's check if it works by sending a message to the bot. The bot has to reply "Text response from webhook" then we can confirm that it works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image6-10.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rQzG5PvW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image6-10.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Final Code with API Integration&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#the-final-code-with-api-integration"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I've updated the function to parse the params and actions and make the corresponding call to Weather API, and generate the text response that will be sent to the user as bot's reply.&lt;/p&gt;

&lt;p&gt;function/index.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const functions = require("firebase-functions");
const Axios = require("axios");

const WEATHER_API_KEY = "YOUR OPENWEATHERMAP HERE";

const responseBuilder = (msg) =&amp;gt; ({
  fulfillmentMessages: [{ text: { text: [msg] } }],
});

exports.chatWebhook = functions.https.onRequest((req, res) =&amp;gt; {
  let body = req.body;
  let { parameters, action } = body.queryResult;

  if (action !== "askWeather") return res.json(responseBuilder("Unable to process your query"));
  let city = parameters["geo-city"];
  let url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&amp;amp;appid=${WEATHER_API_KEY}`;

  return Axios.post(url)
    .then((result) =&amp;gt; result.data)
    .then((data) =&amp;gt; `The temperature is  ${Math.round(data.main.temp - 273.15)} °C`)
    .then((message) =&amp;gt; res.json(responseBuilder(message)))
    .catch((err) =&amp;gt; res.json(responseBuilder(err.message)));
});

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the above code, we're extracting the action and the parameters from the body which is sent by Dialogflow when the user asks the question.&lt;/p&gt;

&lt;p&gt;After deploying the function, the bot will be able to process the user's message with the help of the webhook.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image4-23.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Co5y6ln4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image4-23.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is just a very small example of what Dialogflow can do, but you can do a lot more with it. It also provides some custom formatting for telegram like inline buttons, links, etc.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>dialogflow</category>
      <category>chatbots</category>
      <category>telegrambot</category>
    </item>
    <item>
      <title>Indexing Firebase Data in Algolia For Full-Text Search</title>
      <dc:creator>Varun Raj</dc:creator>
      <pubDate>Sat, 01 Aug 2020 12:29:37 +0000</pubDate>
      <link>https://dev.to/skcript/indexing-firebase-data-in-algolia-for-full-text-search-1fkg</link>
      <guid>https://dev.to/skcript/indexing-firebase-data-in-algolia-for-full-text-search-1fkg</guid>
      <description>&lt;p&gt;Firebase being a BaaS solution comes with a bunch of features for developers to build their app faster and with real-time capabilities. But, there is one thing that is yet to be addressed by Firebase’s feature set - the ability to perform full-text search on the data that is stored in Firebase databases (like Firestore or Realtime Database). This creates a huge bottleneck for developers since search is one of the primary user experiences for any application we build.&lt;/p&gt;

&lt;p&gt;Thankfully we’ve got Algolia that can help us solve this problem. This is a service which helps you store the index of data from firebase, making it searchable. The important advantage of Algolia is that it’s supported in different platforms with a lot of UI components, which can be easily used to develop search modules for your apps.&lt;/p&gt;

&lt;p&gt;In this article, I’ll walk you through how to set up your Algolia and index your data when new data is created or modified in your Firebase Firestore. This article is split into the following sections, you can skip any, in case if you’re already aware of them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Creating an account in Algolia&lt;/li&gt;
&lt;li&gt; Setting up Firebase Cloud Function&lt;/li&gt;
&lt;li&gt; Index data from Firebase Firestore on create and edit.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Creating an account in Algolia#
&lt;/h3&gt;

&lt;p&gt;As the first step, you can navigate to Algolia and register your account by either signing up with Google or Github or just with email.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image6-9.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bZ2RC-et--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image6-9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve created your Algolia account, go to the dashboard and find a default project created under your account. Let’s use that project for this article.&lt;/p&gt;

&lt;p&gt;Similar to Firestore collections Algolia has an “Index” - the aggregation of data under a common umbrella. Create your index to store the data.&lt;/p&gt;

&lt;p&gt;In this case, I have created an index called “Recipes” to save food recipes&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image1-30.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BSur81pK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image1-30.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating an account, add data to the index. Among the 3 different options for adding the data, we’ll be using the API for importing data with help from the firebase cloud functions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image4-22.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xa-TE9cD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image4-22.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Firebase Cloud Functions#
&lt;/h3&gt;

&lt;p&gt;Let’s assume that you’re already having a firebase project and upgraded to &lt;strong&gt;Blaze Plan&lt;/strong&gt; since we have to call external APIs from functions. Then, initialize the functions in your project with the Firebase CLI tool and setup cloud functions.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ProjectFolder
firebase init 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On completion, you’ll find a folder named “&lt;strong&gt;functions&lt;/strong&gt;” in your project folder. Open the project folder in a text editor like VSCode.&lt;/p&gt;

&lt;p&gt;Now we’re going to index data in the “recipes” collection to our new Algolia index. So, let’s create two functions that listen to onCreate and onEdit of any document in the “recipes” collection.&lt;/p&gt;

&lt;p&gt;functions/index.js&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const functions = require('firebase-functions');
const onCreate = require('./triggers/recipes/onCreate');
const onEdit = require('./triggers/recipes/onEdit');

exports.onRecipeCreate = functions.firestore
                                   .document("recipes/{recipeId}")
                                   .onCreate(onCreate);

exports.onRecipeEdit = functions.firestore
                                   .document("recipes/{recipeId}")
                                   .onUpdate(onEdit);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create the handler functions for onCreate of recipe docs and onEdit of the same. So, I’ve created two files under the triggers folder of our functions&lt;/p&gt;

&lt;p&gt;&lt;em&gt;functions/triggers/recipes/onCreate.js&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = (snap, context) =&amp;gt; {
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;functions/triggers/recipes/onEdit.js&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = (change, context) =&amp;gt; {
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Index data from Firebase Firestore on create and update.#
&lt;/h3&gt;

&lt;p&gt;To index the documents in Algolia, configure Algolia keys in the firebase cloud functions. The secured way is to use firebase environment variables.&lt;/p&gt;

&lt;p&gt;To get the API keys from Algolia, go API Keys section in Algolia dashboard and copy your Application ID and the Admin API Key&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image5-18.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LEC0k1-K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image5-18.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These keys need to be configured to our Firebase Cloud function’s environment variables. You can do that with the help of the firebase CLI tool&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase functions:config:set algolia.app_id="THE APP ID" algolia.admin_key="THE ADMIN API KEY" 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After updating the config, we can start using it in the ‘functions’ code. In order to use Algolia, we need to install the npm package in our functions code base.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd functions
npm install --save algoliasearch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After installing the package, create a config file to setup Algolia with the API Keys&lt;/p&gt;

&lt;p&gt;&lt;em&gt;functions/config/algolia.js&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const functions = require('firebase-functions');
const algoliasearch = require('algoliasearch');

const ALGOLIA_ID = functions.config().algolia.app_id;
const ALGOLIA_ADMIN_KEY = functions.config().algolia.admin_key;

module.exports = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This file exports the Algolia Client which we can use to index data and delete the indexed data. Thus, we need to import this in our onCreate and onEdit file.&lt;/p&gt;

&lt;p&gt;With the client, you can initialize the index, in our case “Recipes” and we use &lt;code&gt;saveObject&lt;/code&gt; function to store the data inside the index.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;functions/triggers/recipes/onCreate.js&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const client = require("../../config/algolia");
const recipeIndex = client.initIndex('Recipes');

module.exports = (snap, context) =&amp;gt; {
 let data = snap.data();
 data.objectID = snap.id;
 recipeIndex.saveObject(data);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;functions/triggers/recipes/onEdit.js&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const client = require("../../config/algolia");
const recipeIndex = client.initIndex('Recipes');

module.exports = (change, context) =&amp;gt; {
 let data = change.after.data();
 data.objectID = change.after.id;
 recipeIndex.saveObject(data);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the above two files, we’ve extracted the data from the snap (in onCreate) and changed (in onEdit) to a variable called data. In Algolia, the primary key is stored in the attribute &lt;code&gt;objectID&lt;/code&gt; of data, so we’re storing the firebase document ID as the objectID.&lt;/p&gt;

&lt;p&gt;Let’s deploy the function and test the setup. Deploy the firebase functions by executing the below command from the project’s root folder.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase deploy --only functions
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After deploying, create a document under the **recipes **collection and see if it’s indexed in Algolia.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image2-31.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ewbyHcBh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image2-31.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As soon as you create the data in Firestore, the cloud functions will be triggered and the indexes will be created in your Algolia project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image3-21.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PaiK0pa8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image3-21.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similarly, the index will be updated every time you edit the data in Firestore. This happens in realtime and thus your search will be always updated.&lt;/p&gt;

&lt;p&gt;Thus, you can replicate the data from firebase to Algolia to create a full-text search index. Hope this article helped you to get started with Algolia setup for your firebase project.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>algolia</category>
      <category>search</category>
    </item>
    <item>
      <title>Hyperledger Fabric Architecture: Explained in detail</title>
      <dc:creator>Varun Raj</dc:creator>
      <pubDate>Mon, 29 Jan 2018 04:29:34 +0000</pubDate>
      <link>https://dev.to/skcript/hyperledger-fabric-architecture-explained-in-detail-32bb</link>
      <guid>https://dev.to/skcript/hyperledger-fabric-architecture-explained-in-detail-32bb</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fer42pv0dpzb9w2h1w2nw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fer42pv0dpzb9w2h1w2nw.jpg" alt="Hyperledger Fabric Architecture" width="800" height="596"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  DOMAIN
&lt;/h3&gt;

&lt;p&gt;This is the top-level namespace for your project. Say you’re building a network for a supply chain, then usually the project name or the domain name is used as the Hyperledger Fabric’s domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  ORDERERS
&lt;/h3&gt;

&lt;p&gt;Under a domain, there are orderers (can be multiple instances) who are responsible for making sure that all the peers in the network have committed a transaction. When a transaction is proposed and committed by a peer, the orderer is informed about the new transaction and it forwards and commits this block to all adjacent peers.&lt;/p&gt;

&lt;p&gt;Note: Orderers are not dependent on one organization. However, it is suggested to have multiple orderers to reduce failure rates.&lt;/p&gt;

&lt;h3&gt;
  
  
  ORGANIZATIONS
&lt;/h3&gt;

&lt;p&gt;Organizations are the containers for the peers and respective certificate authorities (CA). Each organization has its own CA and a list of peers. Usually, organizations are used for physical separation of the blockchain network where each organization who uses your product can set up their physical machines and join your network.&lt;/p&gt;

&lt;h3&gt;
  
  
  CERTIFICATE AUTHORITIES
&lt;/h3&gt;

&lt;p&gt;The certificate authority is responsible for creating users certificates. It is used for verifying ownership in the network. Each certificate authority is tied to an organization.&lt;/p&gt;

&lt;h3&gt;
  
  
  PEERS
&lt;/h3&gt;

&lt;p&gt;The peers are nodes which are connected to clients and are responsible for committing transactions to the world state. Each peer has its own copy of transactions in a &lt;code&gt;couchdb&lt;/code&gt; database. An organization can have more than one peer. Though it is advised to have multiple peers in an orderer to avoid data loss, having more than 3 or 4 peers might result in higher latency rates.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>hyperledger</category>
      <category>distributedledger</category>
    </item>
  </channel>
</rss>
