<?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: rachel</title>
    <description>The latest articles on DEV Community by rachel (@ohhoe).</description>
    <link>https://dev.to/ohhoe</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%2F617500%2F308a9e59-2815-4aec-a57a-ae88773174df.jpg</url>
      <title>DEV Community: rachel</title>
      <link>https://dev.to/ohhoe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ohhoe"/>
    <language>en</language>
    <item>
      <title>Monitoring UX in Single Page Applications</title>
      <dc:creator>rachel</dc:creator>
      <pubDate>Tue, 06 Jul 2021 17:49:22 +0000</pubDate>
      <link>https://dev.to/ohhoe/monitoring-ux-in-single-page-applications-2dej</link>
      <guid>https://dev.to/ohhoe/monitoring-ux-in-single-page-applications-2dej</guid>
      <description>&lt;p&gt;This is a crosspost from my personal blog, &lt;a href="https://rachelisaweso.me/posts/purrybooth/"&gt;rachelisaweso.me&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A seamless user experience is the key to success for all modern web applications, but sometimes tracking user behavior is a bit difficult when you’re dealing with single page applications (SPAs). Let’s learn about Real User Monitoring (RUM) to get some insight into our users’ behavior so we can continue crafting the best journey. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h52nSpJK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6o38k6bomr4s3mol4ydb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h52nSpJK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6o38k6bomr4s3mol4ydb.png" alt="purikura photo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First we’re going to start with an application I built over the past year. One thing we all struggled with during the pandemic was connecting with our friends, and one of the things my friends and I love doing in normal circumstances is taking photobooth pictures. Specifically, Japanese style photo booths called purikura. In Japan, &lt;strong&gt;&lt;em&gt;purikura&lt;/em&gt;&lt;/strong&gt; (プリクラ) refers to a photo sticker booth or the product of such a photo booth. The name is a shortened form of the registered trademark &lt;em&gt;Purinto Kurabu&lt;/em&gt;. The term derives from the English &lt;em&gt;print club&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Purikura booths start off like any photo booth that you might see in the US, by taking your photos in a photo booth. Once you’re done, you move around to another side of the machine, where an interactive screen allows you to decorate your photos with filters, stickers, writing, and stamps. Finally, you move outside the booth to wait for your photos to be printed in sticker form, so you can share them with your friends. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2KdklaxN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/52fsbu97siaf0xaz78a2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2KdklaxN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/52fsbu97siaf0xaz78a2.png" alt="purrybooth logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I knew I wanted to build a web application that would enable myself and others to recreate that experience, but completely in the browser. Since I love a challenge, I decided to use only technologies that were new to me. That project is called &lt;a href="http://www.purrybooth.com"&gt;Purrybooth&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Purrybooth is a React application utilizing WebAssembly for ultra fast image filtering, and HTML5 canvas for the photo decorating. It’s hosted on Netlify, so any time I push changes to my main GitHub repository, the build automatically kicks off and everything is generated and deployed and I don’t have to worry about a thing. &lt;/p&gt;

&lt;p&gt;Let’s walk through the technical specifications so you can have an understanding of how this was built. I knew that I was going to be building a fairly simple React application, and that all of my components were going to be React hooks. It would be a single page application with no routing. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vZGutS16--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fj7nri601oqltigito2k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vZGutS16--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fj7nri601oqltigito2k.png" alt="purrybooth filters"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the image, you are able to either use your webcam to take a photo, or upload a photo of your own before moving onto the filters. Image filtering is included in most image manipulation libraries. I had used ImageMagick before, but had a terrible time with it.  I wanted to find a better way to do Instagram-like filtering. I came across &lt;a href="https://silvia-odwyer.github.io/photon/"&gt;Photon&lt;/a&gt;, a high performance image processing library written in Rust and can be compiled to WebAssembly, and there was already a &lt;a href="https://github.com/silvia-odwyer/photon/tree/master/react_app_demo"&gt;React demo&lt;/a&gt; so it was easy to integrate. Once you choose the filter you want, you move onto the decoration stage. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lYxtd5ex--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ve7tp2uo4yc4uy4k7qiy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lYxtd5ex--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ve7tp2uo4yc4uy4k7qiy.png" alt="purrybooth stickers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was the trickiest part to solve! I knew I needed to use a canvas element, and I would be placing the filtered image as the background, but I also needed a way to add the stickers. I ended up using &lt;a href="http://fabricjs.com/"&gt;Fabric.js&lt;/a&gt; to achieve this, with some additional custom interactions I had to integrate—such as changing the z-index of the stickers and the capabilities for removing them. Once you’re done decorating with the stickers, you go to the final page where the canvas is rendered as an image, which you can save and share with your friends.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sJmTXOrD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yw8cqrcz5mdgknxzhxym.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sJmTXOrD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yw8cqrcz5mdgknxzhxym.png" alt="Purrybooth Final Output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that I had a fully working app, as well as a base set of stickers and filters, I wanted a way to keep track of how my users were interacting with the photo booth. How could I know which stickers and filters were popular? I needed to have these kinds of insights in order to continue to make the best possible experience. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ecqlSfvL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ergicv5gpt9j2iftsqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ecqlSfvL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ergicv5gpt9j2iftsqt.png" alt="RUM Integration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next thing I did was integrate my app with Datadog’s Real User Monitoring. You only need a few lines of code in your main &lt;code&gt;index.js&lt;/code&gt; file. Out of the box it gives you a lot of visibility into where your users are clicking, performance info, errors, and the usual analytics  This was a good start, but It was missing something. Since I made the decision to create a routeless SPA, I only knew generally where users were clicking, but there was a way to improve on this data!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RLZVcleZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o21ty5z2nrfmmfact9cs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RLZVcleZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o21ty5z2nrfmmfact9cs.png" alt="Custom User Actions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.datadoghq.com/real_user_monitoring/guide/send-rum-custom-actions/"&gt;Custom User Actions&lt;/a&gt; allow you to collect additional events and data from your application. I wanted to be able to know what stickers were the most popular as well as what filters people were using. By adding Custom User Actions, I’m able to add or remove features depending on usage without having to A/B test, which really saved me a lot of time. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2oi5xitZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1fsrhxi3ay7tbvuw7rv4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2oi5xitZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1fsrhxi3ay7tbvuw7rv4.png" alt="RUM Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more info on &lt;a href="http://www.purrybooth.com"&gt;Purrybooth&lt;/a&gt; please try out the app for yourself at purrybooth.com, and check out the code on &lt;a href="https://github.com/rachelnicole/purrybooth"&gt;github.com/rachelnicole/purrybooth&lt;/a&gt;. For more info on Datadog Real User Monitoring, check out &lt;a href="https://docs.datadoghq.com/real_user_monitoring/"&gt;Datadog's RUM documentation&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>react</category>
      <category>serverless</category>
      <category>netlify</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Part 2 : How to Monitor a Serverless Application</title>
      <dc:creator>rachel</dc:creator>
      <pubDate>Tue, 20 Apr 2021 18:00:32 +0000</pubDate>
      <link>https://dev.to/ohhoe/part-2-how-to-monitor-a-serverless-application-nak</link>
      <guid>https://dev.to/ohhoe/part-2-how-to-monitor-a-serverless-application-nak</guid>
      <description>&lt;p&gt;&lt;em&gt;This post originates from &lt;a href="https://rachelisaweso.me/posts/serverless-lambda-pt2/" rel="noopener noreferrer"&gt;https://rachelisaweso.me/posts/serverless-lambda-pt2/&lt;/a&gt;&lt;/em&gt; and is by Rachel White &lt;a href="http://www.twitter.com/ohhoe" rel="noopener noreferrer"&gt;@ohhoe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Datadog makes setting up monitoring on your serverless function easy with our AWS Integration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fvghop0cgeagh7y2p19g5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fvghop0cgeagh7y2p19g5.png" alt="aws integration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first part is enabling the AWS integration. Head to &lt;a href="https://app.datadoghq.com/account/settings#integrations/amazon-web-services" rel="noopener noreferrer"&gt;the AWS integration tile&lt;/a&gt; and fill in your information.&lt;/p&gt;

&lt;p&gt;The AWS integration sets up some IAM roles and begins scraping your AWS account for information about what’s going on within your AWS infrastructure.&lt;/p&gt;

&lt;p&gt;Next we set up the Datadog Forwarder Lambda function, which is required for ingestion of AWS Lambda traces, enhanced metrics, custom metrics, and logs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.datadoghq.com/serverless/forwarder/" rel="noopener noreferrer"&gt;https://docs.datadoghq.com/serverless/forwarder/&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ftuqlw0ce3a1o6lkuplcx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ftuqlw0ce3a1o6lkuplcx.png" alt="datadog forwarder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can just launch right from our documentation. It’ll ask you for your Datadog API key, which you can find under Integrations &amp;gt; APIs on your Datadog Dashboard. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.datadoghq.com/account/settings#api" rel="noopener noreferrer"&gt;https://app.datadoghq.com/account/settings#api&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Now that we’ve added the integration and forwarder, we can begin to instrument our Lambda function. &lt;/p&gt;

&lt;p&gt;We’ll need to is add some more information to our &lt;code&gt;serverless.yml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;custom:
  datadog:
    flushMetricsToLogs: true
    apiKey: 
    addLayers: true
    logLevel: "info"
    enableXrayTracing: true
    enableDDTracing: true
    forwarder: 
    enableTags: true
    injectLogContext: true

plugins:
  - serverless-plugin-datadog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.datadoghq.com/serverless/serverless_integrations/plugin/" rel="noopener noreferrer"&gt;https://docs.datadoghq.com/serverless/serverless_integrations/plugin/&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Our serverless plugin has configuration options that you can use as needed for your specific use cases. You’ll need to add your Datadog API key here. &lt;/p&gt;

&lt;p&gt;In addition to the serverless plugin, we’re going to add the AWS X-Ray integration, which lets developers trace distributed applications built using AWS products. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.datadoghq.com/integrations/amazon_xray/?tab=nodejs" rel="noopener noreferrer"&gt;https://docs.datadoghq.com/integrations/amazon_xray/?tab=nodejs&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You need to make sure the following permissions are present in the policy document for your AWS/Datadog Role before adding to your code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use strict';
const AWSXRay = require('aws-xray-sdk');
const AWS = AWSXRay.captureAWS(require('aws-sdk'));

AWSXRay.captureHTTPsGlobal(require('http'));
AWSXRay.captureHTTPsGlobal(require('https'));

// captures axios chained promises. 
AWSXRay.capturePromise();

const AxiosWithXray = require('axios');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that we head back to our &lt;code&gt;handler.js&lt;/code&gt; file from Part 1. Run &lt;code&gt;npm install aws-xray-sdk&lt;/code&gt; and require it in your Lambda function &lt;em&gt;first&lt;/em&gt; because you want to catch everything that happens after it’s included. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fj9zjc69i721hka0ec7ub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fj9zjc69i721hka0ec7ub.png" alt="handler xray"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We add the code for capturing all HTTP and HTTPS traces, as well as capturing chained promises, which is super important since so much of Node.js is promise based. &lt;/p&gt;

&lt;p&gt;We’re also going to change the Axios global name to axioswithxray just so we remember we’re catching those responses as well. We’llchange the line in our code that was previously making the Axios call as well.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;sls deploy&lt;/code&gt; one last time so our instrumentation is fully reflected in our serverless function, and that’s all we have to do for our specific use case. &lt;/p&gt;

&lt;p&gt;You can see additional documentation for tracing SQL queries and other options on the X-Ray documentation: &lt;a href="https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-nodejs.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-nodejs.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have set up the AWS Integration and instrumented our serverless application, we can begin to have more insight into how our systems are working. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fs8r39msr5pmgqjqelrzp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fs8r39msr5pmgqjqelrzp.png" alt="serverless"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>monitoring</category>
      <category>serverless</category>
      <category>aws</category>
      <category>node</category>
    </item>
    <item>
      <title>Part 1: How to Build a Serverless Twitter Bot</title>
      <dc:creator>rachel</dc:creator>
      <pubDate>Tue, 20 Apr 2021 18:00:29 +0000</pubDate>
      <link>https://dev.to/ohhoe/part-1-how-to-build-a-serverless-twitter-bot-d10</link>
      <guid>https://dev.to/ohhoe/part-1-how-to-build-a-serverless-twitter-bot-d10</guid>
      <description>&lt;p&gt;&lt;em&gt;This post originates from &lt;a href="https://rachelisaweso.me/posts/serverless-lambda-pt1/" rel="noopener noreferrer"&gt;https://rachelisaweso.me/posts/serverless-lambda-pt1/&lt;/a&gt;&lt;/em&gt; and is by Rachel White &lt;a href="http://www.twitter.com/ohhoe" rel="noopener noreferrer"&gt;@ohhoe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So you want to build a Twitter bot? With serverless functions, it’s easier today than ever before—since you don’t need to worry about configuring daemons to constantly run your code or anything else server-side. Welcome to a two post series on building and monitoring a serverless application: in our case, a Twitter bot! In the first post we’ll be looking at AWS Lambda, S3 buckets, and CloudWatch to trigger our function to run. And in the second, we’ll cover setting up a AWS Integration with Datadog so that you can monitor your serverless function.&lt;/p&gt;

&lt;p&gt;First let's talk about a brief history. Twitter bots used to be very popular around 2015, before Twitter made it so that you had to apply for a developer account to have access to their API. There are lots of different kinds of bots: some are generative image bots, while others are text based, either tweeting random words mashed together, or Markov chaining data from various corpora. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fcfz1hwzfy7ayrszg3pbd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fcfz1hwzfy7ayrszg3pbd.png" alt="soft landscapes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One great example is &lt;a href="http://twitter.com/softlandscapes" rel="noopener noreferrer"&gt;@softlandscapes&lt;/a&gt;, made by &lt;a href="http://www.twitter.com/v21" rel="noopener noreferrer"&gt;@v21&lt;/a&gt;. It uses a tool called &lt;a href="http://www.tracery.io" rel="noopener noreferrer"&gt;Tracery&lt;/a&gt;, which generates language and text; bot developers realized they could use its structure to replace elements in SVG, which enables a lot of flexibility with creating generative images. You can see some other bots that are created with Tracery at &lt;a href="https://cheapbotsdonequick.com/" rel="noopener noreferrer"&gt;Cheap Bots Done Quick&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fmnjsya5v093kmhbyxvnk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fmnjsya5v093kmhbyxvnk.png" alt="Bracket Meme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another great example is &lt;a href="https://twitter.com/BracketMemeBot" rel="noopener noreferrer"&gt;@BracketMemeBot&lt;/a&gt;, made by &lt;a href="https://twitter.com/tinysubversions" rel="noopener noreferrer"&gt;Darius Kazemi&lt;/a&gt;, who thankfully documents a lot of what he makes. Bracket Meme Bot takes random categories of items from Wikipedia that meet a certain set of guidelines (must have a plural noun in the title, and must have at least sixteen pages)Once it finds some categories that meet the requirements, it picks 16 of them at random and draws them on the bracket. It’s extremely silly, and you end up with brackets for things like ‘SpongeBob SquarePants video games’ and ‘Underground Laboratories’. &lt;/p&gt;

&lt;p&gt;I picked one from Darius because he also keeps a GitHub repository of a lot of corpora that a ton of bot makers pull from. You can find at &lt;a href="https://github.com/dariusk/corpora" rel="noopener noreferrer"&gt;https://github.com/dariusk/corpora&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that you understand a bit about where we’re coming from, let’s get into the technical aspects.&lt;/p&gt;

&lt;p&gt;Some prerequisites: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node installed&lt;/li&gt;
&lt;li&gt;Serverless Framework CLI installed: &lt;a href="https://www.serverless.com/framework/docs/getting-started/" rel="noopener noreferrer"&gt;https://www.serverless.com/framework/docs/getting-started/&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;AWS Credentials set up with Serverless Framework for easier deployment (see quick setup): &lt;a href="https://www.serverless.com/framework/docs/providers/aws/guide/credentials/" rel="noopener noreferrer"&gt;https://www.serverless.com/framework/docs/providers/aws/guide/credentials/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;Twitter Developer Account&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first thing we’re going to do is navigate to the folder we want to use for our code and run &lt;code&gt;serverless create --template aws-nodejs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is going to have the serverless framework set up a node template that’s already compatible with what AWS is looking for. We’ve got two files that are important: the handler.js where we write our bot code, and the &lt;code&gt;serverless.yml&lt;/code&gt; file which is defining our provider, production environment, and other variables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fcd08mp603e9plpm8lgzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fcd08mp603e9plpm8lgzd.png" alt="Serverless.yml"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ve got to change the ‘service’ name in &lt;code&gt;serverless.yml&lt;/code&gt; to something that is relevant to our application name.We can also change the name of the function and handler if you’d like. &lt;/p&gt;

&lt;p&gt;Remember that if you change the function’s name in &lt;code&gt;serverless.yml&lt;/code&gt;, you will need to make sure that it reflects the name in module.exports as well.&lt;/p&gt;

&lt;p&gt;Now we can run &lt;code&gt;sls deploy&lt;/code&gt;, which is short for serverless deploy. This will take our files, zip them up, and deploy them to AWS Lambda. Log into your AWS console and navigate to the Lambda Dashboard. Click on the service that has the name you chose in the previous step, so we can make sure everything is connected correctly. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F4qwetk3w0az4vlbq5o7y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F4qwetk3w0az4vlbq5o7y.png" alt="aws dash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I can see my app showing up in the Lambda service dashboard once I hit sls deploy&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since everything is hooked up, now we can focus on coding our bot. For the sake of simplicity, I’m going to focus on just sending out a single tweet. We’re going to use a Twitter API client for Node.js called ‘Twit’. &lt;a href="https://github.com/ttezel/twit" rel="noopener noreferrer"&gt;https://github.com/ttezel/twit&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In the same directory you ran the serverless template command, type &lt;code&gt;npm init&lt;/code&gt; so we can create our package.json file. You don’t need to change any of the values here. Next, we’re going to run &lt;code&gt;npm install twit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we need to change code in our &lt;code&gt;handler.js&lt;/code&gt; file so that we are using the Twit library, and sending our messages out to Twitter.&lt;/p&gt;

&lt;p&gt;Starting on line 2 of &lt;code&gt;handler.js&lt;/code&gt;, we are going to add the following code, which accesses the Twit library and sets up our credentials. You can find the &lt;code&gt;consumer_key&lt;/code&gt;, &lt;code&gt;consumer_secret&lt;/code&gt;, &lt;code&gt;access_token&lt;/code&gt;, and &lt;code&gt;access_token_secret&lt;/code&gt; in the dashboard of your Twitter Developer account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Twit = require('twit')

const T = new Twit({
  consumer_key:         '...',
  consumer_secret:      '...',
  access_token:         '...',
  access_token_secret:  '...',
  timeout_ms:           60*1000,  // optional HTTP request timeout to apply to all requests.
  strictSSL:            true,     // optional - requires SSL certificates to be valid.
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to change the code inside of our module exports. With the base template that the serverless framework creates for us, we’re just returning a JSON object. We want to set up the code that handles the tweet we’re sending. (&lt;a href="https://javascript.info/async-await" rel="noopener noreferrer"&gt;https://javascript.info/async-await&lt;/a&gt; &amp;amp; &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html&lt;/a&gt;) For now, let’s just tweet ‘hello world’. Here is the code for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports.hello = async event =&amp;gt; {

  const tweetResponse = await new Promise((resolve, reject) =&amp;gt; {
    T.post('statuses/update', { status: 'hello world!' }, function(err, data, response) {
      console.log(data)
    })
  })

  return tweetResponse

};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last thing we need to set up for our Lambda function is a way to trigger it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Feddfvv2wu6ouok9hrhbr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Feddfvv2wu6ouok9hrhbr.png" alt="Lambda trigger"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on ‘Add trigger’ will take us to the trigger configuration page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fxc2omx4l9u5bmrz6uha2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fxc2omx4l9u5bmrz6uha2.png" alt="cloudwatch event"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can choose CloudWatch Events, and it will walk you through the process of setting up a rule. We created one called ‘tweeting’ which will run our function every 12 hours. You can set this up to run as frequently or infrequently as you want.&lt;/p&gt;

&lt;p&gt;And that’s it! Now we have a working Twitter bot. I wanted to keep the example simple so that you can take the bot anywhere you want: you can create images and use Twit’s media upload ability, or play around with NLP models for mashing up words. For more resources on botmaking, check out &lt;a href="https://botwiki.org/" rel="noopener noreferrer"&gt;https://botwiki.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/ohhoe/part-2-how-to-monitor-a-serverless-application-nak"&gt;Read Part 2: How to Monitor a Serverless Application&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>node</category>
      <category>javascript</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
