<?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>Forem: Pipedream</title>
    <description>The latest articles on Forem by Pipedream (@pipedream_staff).</description>
    <link>https://forem.com/pipedream_staff</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%2F323021%2Fecd3c142-4135-4e69-968e-14c3475ac6f9.jpg</url>
      <title>Forem: Pipedream</title>
      <link>https://forem.com/pipedream_staff</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/pipedream_staff"/>
    <language>en</language>
    <item>
      <title>Automate customer support with Dialogflow</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Fri, 03 Jun 2022 15:46:25 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/automate-customer-support-with-dialogflow-1ne0</link>
      <guid>https://forem.com/pipedream_staff/automate-customer-support-with-dialogflow-1ne0</guid>
      <description>&lt;p&gt;In this week's Speed Run, we learn how to connect Dialogflow with Pipedream and generate dynamic responses to customer support requests without code.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/FmblKiM5G4g"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;With Dialogflow, we can build chat bots that use Natural Language Processing or NLP for short. &lt;/p&gt;

&lt;p&gt;Just give Dialogflow examples of training phrases and how to respond to them, and it will automatically train and build a dedicated bot for you.&lt;/p&gt;

&lt;p&gt;Then we use Pipedream to customize responses and reply with real dynamic data.&lt;/p&gt;

&lt;p&gt;In this example, we automatically reply with the current stock in our inventory.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>ai</category>
      <category>nlp</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Real time data check notifications with MongoDB</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Thu, 12 May 2022 15:58:50 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/real-time-data-check-notifications-with-mongodb-1bln</link>
      <guid>https://forem.com/pipedream_staff/real-time-data-check-notifications-with-mongodb-1bln</guid>
      <description>&lt;p&gt;Sometimes error logs don't pick up serious logic problems in your apps and your database's integrity is compromised.&lt;/p&gt;

&lt;p&gt;This week's Speed Run shows you how to quickly build a data integrity monitoring system to alert you whenever you have malformed or incorrect data in your MongoDB database.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/kVTeL9Pkwxo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;"Check ups" were coined by Ryan Laughlin at RailsConf 2018. You can watch his entire presentation on how they helped him and his team at SplitWise to detect logic bugs in their code:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gEAlhKaK2I4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This same pattern will work with relational databases as well, like MySQL, Postgres and others.&lt;/p&gt;

&lt;p&gt;We'll send ourselves a Slack message if impossible data is present in our database, so we can investigate and fix before more data causes downstream issues in our apps.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>tutorial</category>
      <category>mongodb</category>
      <category>database</category>
    </item>
    <item>
      <title>Send delayed welcome emails to new users with Postmark</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Fri, 06 May 2022 16:32:56 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/send-delayed-welcome-emails-to-new-users-with-postmark-3mol</link>
      <guid>https://forem.com/pipedream_staff/send-delayed-welcome-emails-to-new-users-with-postmark-3mol</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/UvBsafQrWfw"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This week we released the ability to delay your workflows with both a pre-built action and a helper function in your Node.js code steps.&lt;/p&gt;

&lt;p&gt;In this weeks Speed Run, we give a 5 minute example on how to use Delay to create an email drip campaign after new users sign up for your app.&lt;/p&gt;

&lt;p&gt;We integrate with Postmark, an email provider in this workflow and delay it a full 30 minutes before sending an email to the customer with a Calendly link to book a call with us.&lt;/p&gt;

&lt;p&gt;You can use delay in Node.js steps as well, using the built in function $.flow.delay(miliseconds).&lt;/p&gt;

&lt;p&gt;Read more about delaying workflows in our docs:&lt;br&gt;
&lt;a href="https://pipedream.com/docs/workflows/built-in-functions/#delay"&gt;https://pipedream.com/docs/workflows/built-in-functions/#delay&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>beginners</category>
      <category>productivity</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to send promotion emails with Shopify Orders at random, with a Pipedream workflow</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Fri, 29 Apr 2022 14:35:35 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/how-to-send-promotion-emails-with-shopify-orders-at-random-with-a-pipedream-workflow-465a</link>
      <guid>https://forem.com/pipedream_staff/how-to-send-promotion-emails-with-shopify-orders-at-random-with-a-pipedream-workflow-465a</guid>
      <description>&lt;p&gt;Discount codes are a great way to build customer loyalty. Even better, adding a layer of chance adds an element of excitement to the order.&lt;/p&gt;

&lt;p&gt;In this episode we show you how to generate promotional emails from your Shopify orders without adding any apps to your store.&lt;/p&gt;

&lt;p&gt;You can control how chances each order has of triggering a discount code in an email. Or you can remove this random portion altogether for a post-purchase email message.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ogTFZXiibTQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Here's the random number generator code step you can use in your workflows:&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineComponent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&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="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&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;const&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;min&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;min&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more and get connected!&lt;/p&gt;

&lt;p&gt;🔨  Start building at &lt;a href="https://pipedream.com"&gt;https://pipedream.com&lt;/a&gt;&lt;br&gt;
📣  Read our blog &lt;a href="https://pipedream.com/blog"&gt;https://pipedream.com/blog&lt;/a&gt;&lt;br&gt;
💬  Join our community &lt;a href="https://pipedream.com/community"&gt;https://pipedream.com/community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>tutorial</category>
      <category>node</category>
    </item>
    <item>
      <title>Connect a Webflow Form to an Airtable Database</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Fri, 22 Apr 2022 15:09:44 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/connect-a-webflow-form-to-an-airtable-database-3f9g</link>
      <guid>https://forem.com/pipedream_staff/connect-a-webflow-form-to-an-airtable-database-3f9g</guid>
      <description>&lt;p&gt;Add interactivity to your Webflow website by collecting contact information from your customers using a Pipedream workflow - in 5 minutes without code!&lt;/p&gt;

&lt;p&gt;Contact forms are a vital part of building websites, they're the first layer of interaction between you and your audience, and we'll show you how to start building your own database of contacts using Airtable.&lt;/p&gt;

&lt;p&gt;Airtable is a great way to store data and view it in different ways. &lt;/p&gt;

&lt;p&gt;After you have stored your contacts in Airtable, you can customize the view to make a Trello type Kanban board, and much more.&lt;/p&gt;

&lt;p&gt;We'll show you how to connect your Webflow forms to a Pipedream workflow, so you can leverage the power of data collection from your customers.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/FUPRQWeNYU0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Have an idea for a Speed Run? Let us know!
&lt;/h3&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://www.jotform.com/220694247042049" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gy4T_glI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jotform.com/uploads/Pierce_Dylan/form_files/Pipedream-logo_1%2520%281%29.622b59be618114.13722840.png" height="512" class="m-0" width="512"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://www.jotform.com/220694247042049" rel="noopener noreferrer" class="c-link"&gt;
          ⚡️ Request a Pipedream Speed Run ⚡️
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--6Sp7fQSE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.jotfor.ms/assets/img/favicons/favicon-2021.svg" width="144" height="144"&gt;
        jotform.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;We're always looking for new Speed Run ideas to feature on the show, fill out the 3 question form below for a chance to have a shout out &amp;amp; and your idea brought to life with a Pipedream workflow!&lt;/p&gt;

&lt;h3&gt;
  
  
  Learn more and get connected!
&lt;/h3&gt;

&lt;p&gt;🔨  Start building at &lt;a href="https://pipedream.com"&gt;https://pipedream.com&lt;/a&gt;&lt;br&gt;
📣  Read our blog &lt;a href="https://pipedream.com/blog"&gt;https://pipedream.com/blog&lt;/a&gt;&lt;br&gt;
💬  Join our community &lt;a href="https://pipedream.com/community"&gt;https://pipedream.com/community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Trigger an Algolia Crawler to reindex on Github Repository Releases</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Fri, 15 Apr 2022 15:59:40 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/trigger-an-algolia-crawler-to-reindex-on-github-repository-releases-3onm</link>
      <guid>https://forem.com/pipedream_staff/trigger-an-algolia-crawler-to-reindex-on-github-repository-releases-3onm</guid>
      <description>&lt;p&gt;Here at Pipedream, you may have noticed that our &lt;a href="https://pipedream.com/docs"&gt;documentation&lt;/a&gt; is powered by Algolia. &lt;/p&gt;

&lt;p&gt;In this Speed Run, we'll automate the reindexing of the Pipedream docs on every Github release.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/dDClQTQG9f4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;By automating the crawler, we ensure that the search bar in the docs is always up to date with the latest content.&lt;/p&gt;

&lt;p&gt;By default, Algolia will only crawl our site once per week. By creating a Pipedream workflow to automate this process, we'll know on every new docs release that the search engine will be up to date!&lt;/p&gt;

&lt;p&gt;In this episode we're going to show you how to do this without any code, and leverage a brand new feature here at Pipedream: pre-built native HTTP actions, right in the app.&lt;/p&gt;

&lt;p&gt;Learn more and get connected!&lt;/p&gt;

&lt;p&gt;🔨  Start building at &lt;a href="https://pipedream.com"&gt;https://pipedream.com&lt;/a&gt;&lt;br&gt;
📣  Read our blog &lt;a href="https://pipedream.com/blog"&gt;https://pipedream.com/blog&lt;/a&gt;&lt;br&gt;
💬  Join our community &lt;a href="https://pipedream.com/community"&gt;https://pipedream.com/community&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Request to have your idea come to life (and get a shout out too) in a Pipedream Speed Run video:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jotform.com/220694247042049"&gt;https://www.jotform.com/220694247042049&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>automation</category>
      <category>node</category>
      <category>github</category>
    </item>
    <item>
      <title>Automate a weekly new Twitter Followers Shoutout with Pipedream</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Fri, 08 Apr 2022 14:44:55 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/automate-a-weekly-new-twitter-followers-shoutout-with-pipedream-28d9</link>
      <guid>https://forem.com/pipedream_staff/automate-a-weekly-new-twitter-followers-shoutout-with-pipedream-28d9</guid>
      <description>&lt;p&gt;Engage your Twitter audience with an automatic weekly shout out to your new followers. We'll show you how to build this workflow in 5 minutes on Pipedream.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4MzE5JGfsLU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this episode we're featuring a brand new pre-built action for Pipedream Data Stores to store a list of new Twitter followers on your account in a given week.Learn more and get connected!&lt;/p&gt;

&lt;p&gt;🔨  Start building at &lt;a href="https://pipedream.com"&gt;https://pipedream.com&lt;/a&gt;&lt;br&gt;
📣  Read our blog &lt;a href="https://pipedream.com/blog"&gt;https://pipedream.com/blog&lt;/a&gt;&lt;br&gt;
💬  Join our community &lt;a href="https://pipedream.com/community"&gt;https://pipedream.com/community&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Request to have your idea come to life (and get a shout out too) in a Pipedream Speed Run video:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jotform.com/220694247042049"&gt;https://www.jotform.com/220694247042049&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>productivity</category>
      <category>tutorial</category>
      <category>node</category>
    </item>
    <item>
      <title>Build a Slack music playlist with YouTube channels</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Fri, 01 Apr 2022 13:35:51 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/build-a-slack-music-playlist-with-youtube-channels-964</link>
      <guid>https://forem.com/pipedream_staff/build-a-slack-music-playlist-with-youtube-channels-964</guid>
      <description>&lt;p&gt;In this speed run we'll create an automated new music discovery tool by piping new music videos fresh from YouTube straight into your Slack workspace.&lt;/p&gt;

&lt;p&gt;We'll create a Pipedream workflow that will notify you whenever new videos are uploaded to your favorite channels - all in less than 5 minutes:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ZoWWeBuu5z0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Learn more and get connected&lt;br&gt;
🔨 Start building at &lt;a href="https://pipedream.com"&gt;https://pipedream.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📣 Read our blog &lt;a href="https://pipedream.com/blog"&gt;https://pipedream.com/blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💬 Join our community &lt;a href="https://pipedream.com/community"&gt;https://pipedream.com/community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>productivity</category>
      <category>node</category>
    </item>
    <item>
      <title>Real Time Shopify Partner Revenue Tracker</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Fri, 25 Mar 2022 12:36:07 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/real-time-shopify-partner-revenue-tracker-3jao</link>
      <guid>https://forem.com/pipedream_staff/real-time-shopify-partner-revenue-tracker-3jao</guid>
      <description>&lt;p&gt;In this Speed Run we'll be building a real time physical count of our Shopify Partner revenue with an official Shopify Counter.&lt;/p&gt;

&lt;p&gt;This counter is perfect for feedback on how your apps are earning for you 💵 and give that extra motivation to keep building!&lt;/p&gt;

&lt;p&gt;We'll also cover a brand new feature in Pipedream called Data Stores.  Data Stores can hold data between workflow runs, which become our database for keeping track of total revenue for the physical Smiirl counter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jotform.com/form/220694247042049"&gt;Want to see a specific workflow tutorial? We're taking submissions!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/XQrcWf1cSPo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;🔨 Start building at &lt;a href="https://pipedream.com"&gt;https://pipedream.com&lt;/a&gt; &lt;br&gt;
📣 Read our blog &lt;a href="https://pipedream.com/blog"&gt;https://pipedream.com/blog&lt;/a&gt;&lt;br&gt;
💬 Join our community &lt;a href="https://pipedream.com/community"&gt;https://pipedream.com/community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>node</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Automatically commit your Dev.to articles to your personal GitHub repo</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Fri, 18 Mar 2022 15:06:19 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/automatically-commit-your-devto-articles-to-your-personal-github-repo-o55</link>
      <guid>https://forem.com/pipedream_staff/automatically-commit-your-devto-articles-to-your-personal-github-repo-o55</guid>
      <description>&lt;p&gt;As you know, Dev.to is one of the biggest Developer communities on the web.&lt;/p&gt;

&lt;p&gt;One of the killer features that is that your posts are natively in Markdown with frontmatter that's common static site generators like Jekyll. &lt;/p&gt;

&lt;p&gt;Every post you make on Dev.to is actually compatible with static site generators.&lt;/p&gt;

&lt;p&gt;In this tutorial, I'll show you how to use Pipedream to build a workflow that will automatically sync your Dev.to articles to your GitHub repository.&lt;/p&gt;

&lt;p&gt;That way your posts are backed up in version control, and you can automatically publish them onto your own statically generated site built with Netlify or Vercel.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/5m-RIXELV8A"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>pipedream</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Get the latest count of confirmed cases, recoveries and deaths from the COVID-19 Coronavirus via an HTTP API</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Thu, 06 Feb 2020 00:54:30 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/http-api-for-latest-wuhan-coronavirus-2019-ncov-data-20jj</link>
      <guid>https://forem.com/pipedream_staff/http-api-for-latest-wuhan-coronavirus-2019-ncov-data-20jj</guid>
      <description>&lt;p&gt;A few days ago I started searching for an API to programmatically get the latest data about the global coronavirus outbreak. I came across several visualization and scraping projects, but I couldn't find a simple way to query the latest data programmatically — so I created an HTTP API that returns the latest data in JSON format using a &lt;a href="https://pipedream.com/@pravin/http-api-for-latest-jhu-csse-2019-ncov-wuhan-coronavirus-data-set-p_G6CLVM/edit" rel="noopener noreferrer"&gt;Pipedream workflow&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;The API fetches the latest number of confirmed cases, recoveries and deaths from a public &lt;a href="https://docs.google.com/spreadsheets/u/1/d/1wQVypefm946ch4XDp37uZ-wartW4V7ILdg-qYiDXUHM/htmlview?usp=sharing&amp;amp;sle=true" rel="noopener noreferrer"&gt;Google Sheet&lt;/a&gt; published by the team at the &lt;a href="https://gisanddata.maps.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6" rel="noopener noreferrer"&gt;Center for Systems Science and Engineering (CSSE) at John Hopkins University&lt;/a&gt;, and returns both the raw regional breakouts as well as summary stats in JSON format. It also caches the data for up to 5 minutes to improve performance. The raw data is aggregated by the team at the CSSE from multiple sources including the &lt;a href="https://www.who.int/emergencies/diseases/novel-coronavirus-2019/situation-reports" rel="noopener noreferrer"&gt;WHO&lt;/a&gt;, &lt;a href="https://www.cdc.gov/coronavirus/2019-ncov/index.html" rel="noopener noreferrer"&gt;CDC&lt;/a&gt;, &lt;a href="https://www.ecdc.europa.eu/en/geographical-distribution-2019-ncov-cases" rel="noopener noreferrer"&gt;ECDC&lt;/a&gt;, &lt;a href="http://www.nhc.gov.cn/yjb/s3578/new_list.shtml" rel="noopener noreferrer"&gt;NHC&lt;/a&gt; and &lt;a href="https://3g.dxy.cn/newh5/view/pneumonia?scene=2&amp;amp;clicktime=1579582238&amp;amp;enterid=1579582238&amp;amp;from=singlemessage&amp;amp;isappinstalled=0" rel="noopener noreferrer"&gt;DXY&lt;/a&gt;, and updates are published to Google Sheets multiple times per day.&lt;/p&gt;
&lt;h2 id="using-the-api"&gt;Using the API&lt;/h2&gt;
&lt;p&gt;To use the API, just make an HTTP request to the following endpoint URL:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://coronavirus.m.pipedream.net/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can test it by loading the URL &lt;a href="https://coronavirus.m.pipedream.net/" rel="noopener noreferrer"&gt;in your browser&lt;/a&gt; or app, by running &lt;code&gt;curl &lt;a href="http://coronavirus.m.pipedream.net/" rel="noopener noreferrer"&gt;https://coronavirus.m.pipedream.net/&lt;/a&gt;&lt;/code&gt; in a terminal, or by &lt;a href="https://pipedream.com/@pravin/test-http-api-for-2019-ncov-coronavirus-data-published-by-jhu-csse-p_zACR6x" rel="noopener noreferrer"&gt;copying and running this workflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The API returns:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Global, Mainland China and Non-Mainland China summary stats&lt;/strong&gt; (count of cases, recoveries and deaths)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raw data &lt;/strong&gt;(counts by region as published in the Google Sheet)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata&lt;/strong&gt; (including when data was last published and the cache status)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Note: &lt;/strong&gt;Data is cached using &lt;a href="https://docs.pipedream.com/workflows/steps/code/#managing-state" rel="noopener noreferrer"&gt;$checkpoint&lt;/a&gt; to improve performance. The cache is updated if it's more than 5 minutes old (&lt;a href="https://pipedream.com/@pravin/http-api-for-latest-jhu-csse-2019-ncov-wuhan-coronavirus-data-set-p_G6CLVM/edit" rel="noopener noreferrer"&gt;view the workflow code&lt;/a&gt; or read more below).&lt;/p&gt;
&lt;h2 id="sample-api-response"&gt;Sample API Response&lt;/h2&gt;
&lt;p&gt;Following is a sample of the data returned by the API. &lt;strong&gt;Note:&lt;/strong&gt; the &lt;code&gt;rawData&lt;/code&gt; array is truncated in this example to only show a single result — query the endpoint URL to retrieve the full response.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  "apiSourceCode": "https://pipedream.com/@/p_G6CLVM",
  "cache": {
    "lastUpdated": "2 minutes ago",
    "expires": "in 3 minutes",
    "lastUpdatedTimestamp": 1580925783250,
    "expiresTimestamp": 1580926083250
  },
  "summaryStats": {
    "global": {
      "confirmed": 24630,
      "recovered": 1029,
      "deaths": 494
    },
    "mainlandChina": {
      "confirmed": 24405,
      "recovered": 1020,
      "deaths": 492
    },
    "nonMainlandChina": {
      "confirmed": 225,
      "recovered": 9,
      "deaths": 2
    }
  },
  "rawData": [
    {
      "Province/State": "Hubei",
      "Country/Region": "Mainland China",
      "Last Update": "2/5/20 16:43",
      "Confirmed": "16678",
      "Deaths": "479",
      "Recovered": "538"
    },
  ],
  "dataSource": {
    "googleSpreadsheetId": "1wQVypefm946ch4XDp37uZ-wartW4V7ILdg-qYiDXUHM",
    "range": "Feb05_1220PM!A1:F1000",
    "dataLastPublished": "44 minutes ago",
    "googleSheetLastModified": "2020-02-05T17:27:39.593Z",
    "publishedBy": "John Hopkins University Center for Systems Science and Engineering",
    "ref": "https://gisanddata.maps.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6"
  }
}e&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="capabilities"&gt;Capabilities&lt;/h2&gt;
&lt;p&gt;The workflow behind this API uses the following capabilities and it runs on Pipedream for free (&lt;a href="https://pipedream.com/@pravin/http-api-for-latest-jhu-csse-2019-ncov-wuhan-coronavirus-data-set-p_G6CLVM/edit" rel="noopener noreferrer"&gt;view, copy, modify and run the workflow code&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.pipedream.com/workflows/steps/triggers/#http" rel="noopener noreferrer"&gt;HTTP trigger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.pipedream.com/workflows/steps/code/#code" rel="noopener noreferrer"&gt;Node.js code steps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/googleapis" rel="noopener noreferrer"&gt;Google&lt;/a&gt; and &lt;a href="https://momentjs.com/" rel="noopener noreferrer"&gt;Moment.js&lt;/a&gt; &lt;a href="https://docs.pipedream.com/workflows/steps/code/#using-npm-packages" rel="noopener noreferrer"&gt;npm pacakges&lt;/a&gt; (to use any npm package, just &lt;code&gt;require&lt;/code&gt; it — no &lt;code&gt;package.json&lt;/code&gt; or &lt;code&gt;npm install&lt;/code&gt; required)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.pipedream.com/workflows/steps/code/auth/#auth-in-code-steps" rel="noopener noreferrer"&gt;Auth managed by Pipedream&lt;/a&gt; (for Google Sheets and Drive)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.pipedream.com/workflows/steps/code/#managing-state" rel="noopener noreferrer"&gt;$checkpoint&lt;/a&gt; (maintains state across workflow executions)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.pipedream.com/workflows/steps/triggers/#http" rel="noopener noreferrer"&gt;$respond() &lt;/a&gt;(returns an HTTP response to a client)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.pipedream.com/workflows/steps/#step-exports" rel="noopener noreferrer"&gt;Step exports&lt;/a&gt; (provides observability into data and enables workflows to pass data to later steps via the &lt;code&gt;steps&lt;/code&gt; object)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-it-works"&gt;How It Works&lt;/h2&gt;
&lt;p&gt;The HTTP API works by &lt;a href="https://pipedream.com/@pravin/http-api-for-latest-jhu-csse-2019-ncov-data-set-p_G6CLVM/edit" rel="noopener noreferrer"&gt;triggering the Node.js code in this workflow&lt;/a&gt; on every request to &lt;a href="http://coronavirus.m.pipedream.net/" rel="noopener noreferrer"&gt;&lt;code&gt;https://coronavirus.m.pipedream.net/&lt;/code&gt;&lt;/a&gt;.  The workflow consists of multiple steps to fetch and cache new data, transform and aggregate it, and finally respond to the client.&lt;/p&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.pipedream.com%2Fcontent%2Fimages%2F2020%2F02%2Fcoronavirusworkflowdemo.gif"&gt;&lt;p&gt;Next, I'll explain some of the key steps in the workflow.&lt;/p&gt;
&lt;h3 id="steps-trigger"&gt;steps.trigger&lt;/h3&gt;
&lt;p&gt;When you select an HTTP / Webhook trigger, Pipedream automatically generates a unique endpoint URL to trigger your workflow code. Since I'm sharing the endpoint URL publicly (&lt;a href="http://coronavirus.m.pipedream.net/" rel="noopener noreferrer"&gt;&lt;code&gt;https://coronavirus.m.pipedream.net/&lt;/code&gt;&lt;/a&gt;), anyone can make a request to execute the code and get the response.&lt;/p&gt;
&lt;h3 id="steps-filter_favicon_requests"&gt;steps.filter_favicon_requests&lt;/h3&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.pipedream.com%2Fcontent%2Fimages%2F2020%2F02%2Fpipedream.com_%40pravin_http-api-for-latest-jhu-csse-2019-ncov-wuhan-coronavirus-data-set-p_G6CLVM_edit_e-1XOsWT8mQeeER7cB9AIgVSMEJhK.png"&gt;&lt;p&gt;The first code step filters out duplicate requests caused by web browsers requesting a &lt;code&gt;favicon.ico&lt;/code&gt; asset when loading the endpoint URL  — if the the triggering URL contains &lt;code&gt;favicon.ico&lt;/code&gt;, the workflow execution ends early and no additional steps or code are executed.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (steps.trigger.event.url.indexOf('favicon.ico') !== -1) {
  $end('Terminating workfow for favicon request')
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="steps-get_data"&gt;steps.get_data&lt;/h3&gt;
&lt;p&gt;Next, we either refresh the cache with the latest data from both Google Sheets and Google Drive (&lt;a href="https://www.npmjs.com/package/googleapis" rel="noopener noreferrer"&gt;using the &lt;code&gt;googleapis&lt;/code&gt; npm package&lt;/a&gt; with auth managed by Pipedream), or we return the data cached to &lt;code&gt;this.$checkpoint&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First, we initialize &lt;code&gt;this.checkpoint&lt;/code&gt; if it is &lt;code&gt;undefined&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (typeof this.$checkpoint === 'undefined') {
  // initialize this.$checkpoint
  this.$checkpoint = {}
  this.$checkpoint.data = {}
  this.$checkpoint.ts = 0
  this.$checkpoint.lastModified = ''
  this.$checkpoint.range = ''
  this.$checkpoint.spreadsheetId = ''
  this.$checkpoint.lastPublished = 0
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we determine whether the cache should be updated. There are two processes that will trigger a cache refresh:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I'm running &lt;a href="https://pipedream.com/@pravin/update-cache-for-jhu-csse-2019-ncov-data-set-p_LQCJb8/edit?e=1XOoQ8yqtbkRYXh79ypF7Tv0xqh" rel="noopener noreferrer"&gt;a separate workflow on a schedule to update the cache every 4 minutes&lt;/a&gt;. That workflow simply makes a request to the endpoint URL for this workflow and passes &lt;code&gt;refresh&lt;/code&gt; as the value of the query parameter &lt;code&gt;action&lt;/code&gt;, and the &lt;a href="https://docs.pipedream.com/environment-variables/#environment-variables" rel="noopener noreferrer"&gt;environment variable&lt;/a&gt; &lt;code&gt;process.env.CSSE_NCOV_REFRESH_TOKEN&lt;/code&gt; as the value for of the query parameter &lt;code&gt;token&lt;/code&gt;. The goal for this secondary process is to improve performance for end users, since it's slower to fetch and process live data from Google Sheets (ideally, the only time the cache is updated is via this out of band process).&lt;/li&gt;
&lt;li&gt;However, if a user attempts to retrieve data by making a request to the API and the cache is older than 5 minutes, then that should also trigger a real-time lookup to Google Sheets will be triggered (this should only happen if #1 above fails)&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;this.dataExpiry = 5 * 60 * 1000

if (((new Date().getTime() - this.$checkpoint.ts) &amp;gt; (this.dataExpiry)) || 
    (event.query.action === 'refresh' &amp;amp;&amp;amp; event.query.token === 
     process.env.CSSE_NCOV_REFRESH_TOKEN)) {
  this.updateCache = true
} else {
  this.updateCache = false
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I'm using the step export &lt;code&gt;this.updateCache&lt;/code&gt; to determine whether to fetch new data because I'm going to reference this value in a later step (I'll be able to reference this value as &lt;code&gt;steps.get_data.udpateCache&lt;/code&gt;). Using step exports also provides default observability into exported data, so I can easily see what condition was triggered for each event:&lt;/p&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.pipedream.com%2Fcontent%2Fimages%2F2020%2F02%2Fpipedream.com_%40pravin_http-api-for-latest-jhu-csse-2019-ncov-wuhan-coronavirus-data-set-p_G6CLVM_edit_e-1XP5x0MtupiurQ0pHOBYtzbHvJB--2-.png"&gt;Select an event to inspect the execution and exports for each step&lt;p&gt;Finally, if &lt;code&gt;this.updateCache&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;, then we fetch the latest data using the &lt;code&gt;googleapis&lt;/code&gt; npm package and save it to &lt;code&gt;this.$checkpoint&lt;/code&gt; (which maintains state across workflow executions). Otherwise, we simply return the value of &lt;code&gt;this.$checkpoint&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (this.updateCache === true) {
  // fetch the latest data from the Google Sheet
  console.log('Fetching new data')
  const {google} = require('googleapis') 

  const auth = new google.auth.OAuth2()
  auth.setCredentials({ 
    access_token: auths.google_sheets.oauth_access_token 
  })
  const sheets = await google.sheets({
    version: 'v4', 
    auth
  });

  this.$checkpoint.spreadsheetId = params.spreadsheetId

  let response = await sheets.spreadsheets.values.get({
    spreadsheetId: this.$checkpoint.spreadsheetId,
    range: params.range
  })
  this.$checkpoint.data = response.data
  this.$checkpoint.ts = new Date().getTime()
  
  // get the date/time the file was last modified
  auth.setCredentials({ 
    access_token: auths.google_drive.oauth_access_token 
  })
  const drive = await google.drive({version: 'v3', auth});
  this.$checkpoint.lastModified = (await drive.files.get({
    fileId: this.$checkpoint.spreadsheetId,
    fields: params.fields
  })).data.modifiedTime

  // check if the tab name was updated
  // which indicates new data was published
  if (response.data.range !== this.$checkpoint.range) {
    this.$checkpoint.range = response.data.range
    this.$checkpoint.lastPublished = this.$checkpoint.lastModified
  }
} else {
  console.log('Return cached data')
}

return this.$checkpoint&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I connected my Google Sheets and Drive accounts to this step and used the &lt;code&gt;auths&lt;/code&gt; object in code to securely pass the oauth access token to Google's API for authentication. E.g.,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const auth = new google.auth.OAuth2()
auth.setCredentials({ 
  access_token: auths.google_sheets.oauth_access_token 
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you copy the workflow into your account to modify and run it yourself, then you'll need to connect your own accounts.&lt;/p&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.pipedream.com%2Fcontent%2Fimages%2F2020%2F02%2Fimage-3.png"&gt;&lt;h3 id="steps-transform_data"&gt;steps.transform_data&lt;/h3&gt;
&lt;p&gt;The data returned from Google Sheets in the previous step is an array of arrays representing the rows and columns of data in the sheet. This step makes the data more ergonomic by transforming the data into an array of JSON objects, with each value matched with its respective key (based on the value in the header).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const transformedData = [], originalData = steps.get_data.$return_value.data.values
let rowCount = 0

originalData.forEach(function(row){
  if (rowCount &amp;gt; 0) {
    let obj = {}
    for (let i=0; i&amp;lt;row.length; i++) {
      obj[originalData[0][i]] = row[i] 
    }
    transformedData.push(obj)
  }
  rowCount++
})

return transformedData&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="steps-summarize_data"&gt;steps.summarize_data&lt;/h3&gt;
&lt;p&gt;This step returns a JSON object with the total count of confirmed cases, recoveries and deaths, as well as subtotals for Mainland China and non-Mainland China. The data is cached to &lt;code&gt;this.$checkpoint&lt;/code&gt; and it uses the &lt;code&gt;updateCache&lt;/code&gt; export from &lt;code&gt;steps.get_data&lt;/code&gt; to determine whether to update the cache, or return previously cached data.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (steps.get_data.updateCache === true) {
  console.log('updating cached stats')

  // initialize the stats object
  const stats = {
    global: { confirmed: 0, recovered: 0, deaths: 0 },
    mainlandChina: { confirmed: 0, recovered: 0, deaths: 0 },
    nonMainlandChina: { confirmed: 0, recovered: 0, deaths: 0 },
  }

  function incrementTotals(statsObj, regionObj) {
    statsObj.confirmed += parseInt(regionObj.Confirmed)
    statsObj.recovered += parseInt(regionObj.Recovered)
    statsObj.deaths += parseInt(regionObj.Deaths)
    return statsObj
  }

  steps.transform_data.$return_value.forEach(function(region){
    // increment global totals
    stats.global = incrementTotals(stats.global, region)
    if (region['Country/Region'] === 'Mainland China') {
      // calculate totals for mainland china
      stats.mainlandChina = incrementTotals(stats.mainlandChina, region)
    } else {
      // calculate totals for non-mainland china regions 
      stats.nonMainlandChina = incrementTotals(stats.nonMainlandChina, region)
    }
  })

  this.$checkpoint = stats
} else {
  console.log('using cached stats')
}

return this.$checkpoint&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="steps-respond_to_client"&gt;steps.respond_to_client&lt;/h3&gt;
&lt;p&gt;Finally, we construct the body based on data exported and returned from previous steps, and use the &lt;a href="https://momentjs.com/" rel="noopener noreferrer"&gt;moment.js&lt;/a&gt; npm package to provide human readable relative dates/times. We use $respond() to issue the response, set the &lt;code&gt;content-type&lt;/code&gt; header to &lt;code&gt;application/json&lt;/code&gt; and &lt;code&gt;JSON.stringify()&lt;/code&gt; the data before returning it as the response body.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const moment = require('moment')

const body = {}
const lastUpdatedTimestamp = steps.get_data.$return_value.ts
const expiresTimestamp = steps.get_data.dataExpiry 
                         + steps.get_data.$return_value.ts

body.apiSourceCode = `https://pipedream.com/@/${steps.trigger.context.workflow_id}`
body.cache = {
  lastUpdated: moment(lastUpdatedTimestamp).fromNow(),
  expires: moment(expiresTimestamp).fromNow(),
  lastUpdatedTimestamp,
  expiresTimestamp
}
body.summaryStats = steps.summarize_data.$return_value
body.rawData = steps.transform_data.$return_value
body.dataSource = {
  googleSpreadsheetId: steps.get_data.$return_value.spreadsheetId,
  range: steps.get_data.$return_value.range,
  googleSheetLastModified: steps.get_data.$return_value.lastModified,
  dataLastPublished: moment(steps.get_data.$return_value.lastPublished).fromNow(),
  dataPublishedBy: `John Hopkins University Center for Systems Science and Engineering`,
  ref: `https://gisanddata.maps.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6`
}

await $respond({
  immediate: true,
  status: 200,
  headers: {
    'content-type': 'application/json'
  },
  body: JSON.stringify(body)
})&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="feedback"&gt;Feedback&lt;/h2&gt;
&lt;p&gt;Try out the public endpoint at &lt;a href="http://coronavirus.m.pipedream.net/" rel="noopener noreferrer"&gt;&lt;code&gt;https://coronavirus.m.pipedream.net/&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://pipedream.com/@pravin/http-api-for-latest-jhu-csse-2019-ncov-wuhan-coronavirus-data-set-p_G6CLVM" rel="noopener noreferrer"&gt;copy, modify and run it yourself for free on Pipedream&lt;/a&gt;. Please let us know if you have any feedback – you can join our public Slack at &lt;a href="https://pipedream.com/community" rel="noopener noreferrer"&gt;https://pipedream.com/community&lt;/a&gt;. And &lt;a href="https://gisanddata.maps.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6" rel="noopener noreferrer"&gt;be sure to check out the great work the team at CSSE is doing&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>serverless</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Use any API in seconds with auth managed by Pipedream</title>
      <dc:creator>Pipedream</dc:creator>
      <pubDate>Sat, 25 Jan 2020 03:25:52 +0000</pubDate>
      <link>https://forem.com/pipedream_staff/use-any-api-in-seconds-with-auth-managed-by-pipedream-1p6a</link>
      <guid>https://forem.com/pipedream_staff/use-any-api-in-seconds-with-auth-managed-by-pipedream-1p6a</guid>
      <description>&lt;p&gt;&lt;a href="https://pipedream.com"&gt;Pipedream&lt;/a&gt; makes it easy to write Node.js and use any API in seconds! We securely manage auth for 100+ apps (with &lt;a href="https://github.com/PipedreamHQ/roadmap/issues?utf8=%E2%9C%93&amp;amp;q=is%3Aissue+is%3Aclosed+"&gt;more added daily&lt;/a&gt;) – just connect your app accounts and use the &lt;code&gt;auths&lt;/code&gt; object in code to reference tokens and keys.&lt;/p&gt;
&lt;h2 id="github-http-api"&gt;Github HTTP API&lt;/h2&gt;
&lt;p&gt;For example, to use Github's HTTP API,  just connect your account using a browser-based oauth flow and and pass &lt;code&gt;auths.github.access_token&lt;/code&gt; as the value of the &lt;code&gt;Bearer&lt;/code&gt; token (check out the &lt;code&gt;octokit&lt;/code&gt; section below for an example of how to use &lt;code&gt;auths&lt;/code&gt; with an npm package).&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-javascript"&gt;const axios = require('axios')

const response = await axios({
  url: `https://api.github.com/user`,
  headers: {
    Authorization: `Bearer ${auths.github.oauth_access_token}`,
  }, 
})

return response.data&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's a GIF that demonstrates how to use the Github API in 30-seconds:&lt;/p&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OB3spZrT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.pipedream.com/content/images/2020/01/githubdemo.gif" class="kg-image"&gt;&lt;p&gt;In ~30-seconds, I add a code step with Github auth, paste in the code above, connect my account, query the API and inspect the results. &lt;a href="https://pipedream.com/@pravin/github-demo-p_brCnan"&gt;Copy this template&lt;/a&gt; to try it yourself .&lt;/p&gt;
&lt;h2 id="github-via-octokit"&gt;Github via Octokit &lt;/h2&gt;
&lt;p&gt;You're not limited to using Pipedream managed auth with HTTP APIs – it works with npm packages too! Here's an example of the same API request as above, but using Github's &lt;code&gt;octokit&lt;/code&gt; package:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-javascript"&gt;const Octokit = require('@octokit/rest')

const octokit = new Octokit({
  auth: auths.github.oauth_access_token
})

return (await octokit.users.getAuthenticated()).data&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pipedream transparently installs any npm packages you require in your code when you deploy. To try it yourself, &lt;a href="https://pipedream.com/@pravin/github-demo-p_brCnan"&gt;copy this template&lt;/a&gt;, enable &lt;code&gt;steps.octokit&lt;/code&gt;, connect your account and run the code.&lt;/p&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zu6sXdnJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.pipedream.com/content/images/2020/01/octokitdemo.gif" class="kg-image"&gt;&lt;h2 id="scaffolding-api-auth-code"&gt;Scaffolding API + Auth Code&lt;/h2&gt;
&lt;p&gt;Pipedream also supports actions, which are re-usable code steps. Actions provides scaffolding for popular APIs and functions. To scaffold a generic API for an app, just click the plus (+) button &lt;strong&gt;, &lt;/strong&gt;select the app and choose &lt;strong&gt;Run Node.js with [App Name]&lt;/strong&gt;:&lt;/p&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wZcITPWy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.pipedream.com/content/images/2020/01/basicscaffolding-1.gif" class="kg-image"&gt;&lt;p&gt;To scaffold a specific API for an app, just click the plus (+) button , select the app and choose the action that you want to scaffold. Try editing the code and confirm that you want to customize it:&lt;/p&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u-YCwSzW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.pipedream.com/content/images/2020/01/actionscaffold-1.gif" class="kg-image"&gt;&lt;h2 id="triggering-your-code"&gt;Triggering Your Code&lt;/h2&gt;
&lt;p&gt;Trigger your code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Manually&lt;/li&gt;
&lt;li&gt;On an interval or cron schedule&lt;/li&gt;
&lt;li&gt;On HTTP request (Pipedream will generate a unique URL — any requests to this URL will trigger your code)&lt;/li&gt;
&lt;li&gt;On an email (Pipedream will generate a unique email address — any emails sent to this address will trigger your code)&lt;/li&gt;
&lt;li&gt;Via the Pipedream Node.js or Ruby SDKs&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="getting-started"&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;To get started, just sign in with your Google or Github account at &lt;a href="https://pipedream.com"&gt;https://pipedream.com&lt;/a&gt;. Check out the project templates at &lt;a href="https://pipedream.com/explore"&gt;https://pipedream.com/explore&lt;/a&gt;, and join our public Slack at &lt;a href="https://pipedream.com/community"&gt;https://pipedream.com/community&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>github</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
