<?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: Pol Milian</title>
    <description>The latest articles on Forem by Pol Milian (@elpol).</description>
    <link>https://forem.com/elpol</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%2F891853%2F6b88bffb-c761-4728-a68f-e50e603981b3.png</url>
      <title>Forem: Pol Milian</title>
      <link>https://forem.com/elpol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/elpol"/>
    <language>en</language>
    <item>
      <title>Building a Twitter bot with Go, GPT-3 and AWS</title>
      <dc:creator>Pol Milian</dc:creator>
      <pubDate>Tue, 27 Dec 2022 14:52:20 +0000</pubDate>
      <link>https://forem.com/elpol/building-a-twitter-bot-with-go-and-gpt-3-57m7</link>
      <guid>https://forem.com/elpol/building-a-twitter-bot-with-go-and-gpt-3-57m7</guid>
      <description>&lt;p&gt;I've recently been learning Go, as you can read &lt;a href="https://www.polmilian.dev/posts/first-impressions-of-go-as-a-javascript-developer" rel="noopener noreferrer"&gt;in my previous post&lt;/a&gt;. What better way to learn a programming language than with a real project?&lt;/p&gt;

&lt;p&gt;Everyone is talking about Twitter and its bots. I thought, how difficult would it be to do it? Is it even legal?&lt;/p&gt;

&lt;p&gt;The bot I made is like a "wise Indian guru" that tweets love advice every 2 hours. This advice is generated using the &lt;a href="https://beta.openai.com/docs/api-reference/introduction" rel="noopener noreferrer"&gt;GPT-3 API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;How did I do it?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We call the GPT-3 API and get the generated response body. From that, we parse it and trim it to remove blank spaces. This string is going to be the tweet for our bot&lt;/li&gt;
&lt;li&gt;If all this process is successful, we will then make a POST request to the &lt;a href="https://developer.twitter.com/en/docs/twitter-api" rel="noopener noreferrer"&gt;Twitter API&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How can we trigger this every 2h?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I decided to use an &lt;a href="https://docs.aws.amazon.com/lambda/index.html" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt; for this. Once the code is uploaded, it's very easy to trigger it every X amount of time using AWS EventBridge + a &lt;a href="https://crontab.guru/" rel="noopener noreferrer"&gt;cron or rate expression&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What do we need?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://www.extly.com/docs/perfect_publisher/user_guide/tutorials/how-to-auto-post-from-joomla-to-twitter/apply-for-a-twitter-developer-account/#apply-for-a-developer-account" rel="noopener noreferrer"&gt;Twitter Developer account with Elevated privileges&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A second Twitter account for our bot. A lot of guides don't tell you this (maybe it's too obvious?), but it should be step one in order to secure the handle you want.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the code for this project is open-source, and is available at: &lt;a href="https://github.com/el-pol/lovebot" rel="noopener noreferrer"&gt;https://github.com/el-pol/lovebot&lt;/a&gt;. Feel free to fork it &amp;amp; submit PRs 😇&lt;/p&gt;

&lt;h2&gt;
  
  
  Get the Twitter credentials to tweet from the bot
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;First of all, you need to apply for a Twitter developer account from your main account: &lt;a href="https://developer.twitter.com/en" rel="noopener noreferrer"&gt;https://developer.twitter.com/en&lt;/a&gt;. Then, apply for &lt;em&gt;Elevated Access&lt;/em&gt; so that your applications can read &amp;amp; write. Here is a good step-by-step: &lt;a href="https://www.extly.com/docs/perfect_publisher/user_guide/tutorials/how-to-auto-post-from-joomla-to-twitter/apply-for-a-twitter-developer-account/#apply-for-a-developer-account" rel="noopener noreferrer"&gt;https://www.extly.com/docs/perfect_publisher/user_guide/tutorials/how-to-auto-post-from-joomla-to-twitter/apply-for-a-twitter-developer-account/#apply-for-a-developer-account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Then, create a new regular Twitter account for the bot. I suggest to do this in another browser, so you don’t confuse your &lt;em&gt;Main Account&lt;/em&gt; with your &lt;em&gt;Bot Account&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;In the bot account settings, find the &lt;em&gt;Managed by&lt;/em&gt; section and refer it to your main account. This will add an &lt;strong&gt;Automated&lt;/strong&gt; badge to the bot account and &lt;strong&gt;Managed by @yourhandle&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Once you’ve done steps 1-2-3, follow this guide: &lt;a href="https://medium.com/geekculture/how-to-create-multiple-bots-with-a-single-twitter-developer-account-529eaba6a576" rel="noopener noreferrer"&gt;https://medium.com/geekculture/how-to-create-multiple-bots-with-a-single-twitter-developer-account-529eaba6a576&lt;/a&gt;

&lt;ol&gt;
&lt;li&gt;What we do here is authorize our main account to control our bot account. That’s why we need another authentication pin. This uses Oauth1a.&lt;/li&gt;
&lt;li&gt;The final step is different. As of today, you will need to do a POST request instead of visiting the URL: &lt;code&gt;curl --request POST --url '&amp;lt;https://twitter.com/oauth/access_token?oauth_token=&amp;gt;&amp;lt;TOKEN&amp;gt;&amp;amp;oauth_verifier=&amp;lt;PIN&amp;gt;'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;After this, you should get the response with the key &amp;amp; the token&lt;/li&gt;
&lt;li&gt;There is a better way to do this with Oauth2; it’s more secure but a bit more complicated since you will need to re-authenticate with this flow every time you make a new tweet. If you have the time and energy, I suggest you to do it this way. Here is a good example: &lt;a href="https://developer.twitter.com/en/docs/authentication/oauth-2-0/user-access-token" rel="noopener noreferrer"&gt;https://developer.twitter.com/en/docs/authentication/oauth-2-0/user-access-token&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;By the end, you should have 4 different secret keys:

&lt;ol&gt;
&lt;li&gt;Main account consumer key&lt;/li&gt;
&lt;li&gt;Main account access token secret&lt;/li&gt;
&lt;li&gt;Bot acess token (the one you just generated)&lt;/li&gt;
&lt;li&gt;Bot access token secret (the one you also just generated)&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;You will use all of those: the first two to tell Twitter you have a developer account authorized to read/write, and the last two to tell Twitter that you will be tweeting from your bot account. You are really authenticating in two different steps. If you would only want to tweet from your main account, you would only need your own consumer key &amp;amp; secret.&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  Get the OpenAI API credentials
&lt;/h2&gt;

&lt;p&gt;OpenAI is a paid API, so you will need to go to &lt;a href="https://beta.openai.com/overview" rel="noopener noreferrer"&gt;https://beta.openai.com/overview&lt;/a&gt; and add your billing details.&lt;/p&gt;

&lt;p&gt;Then, you will get an API key that you can authenticate with. You can see the documentation here: &lt;a href="https://beta.openai.com/docs/api-reference/making-requests" rel="noopener noreferrer"&gt;https://beta.openai.com/docs/api-reference/making-requests&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we need to pass our key to the Authorization Headers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;Believe it or not - the hardest part is over. If you have some experience in programming, what we are going to do next is two sequential POST requests: first to OpenAI to get the text, and next to Twitter to post it from our bot account.&lt;/p&gt;

&lt;p&gt;This is the file structure I used:&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%2Fhxhq0kg9tlvpfp9civj3.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%2Fhxhq0kg9tlvpfp9civj3.png" alt="File structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The fetch package contains our logic for the OpenAI request. We will then import that into &lt;code&gt;main.go&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;main.go&lt;/code&gt; we do the Twitter POST request. This could be refactored into another package for cleaner code.&lt;/li&gt;
&lt;li&gt;Your &lt;code&gt;.env&lt;/code&gt; file should look like this:&lt;/li&gt;
&lt;/ul&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%2Fl3jrfm8gg2tggep331od.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%2Fl3jrfm8gg2tggep331od.png" alt="Env vars"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Lambda-specific warning
&lt;/h3&gt;

&lt;p&gt;Usually, you would put all the code into &lt;code&gt;func main()&lt;/code&gt; and it would just work. But when we work with AWS Lambda, we need to add a small modification. We have to put our code in a handler and then put it in &lt;code&gt;func main()&lt;/code&gt;, as explained here: &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/golang-handler.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/lambda/latest/dg/golang-handler.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So for a Lambda, all the code you would normally put in &lt;code&gt;main&lt;/code&gt;, has to go into another function and then pass it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lambda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HandleRequest&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;Where &lt;code&gt;HandleRequest&lt;/code&gt; is the function where we will execute our main code.&lt;/p&gt;

&lt;p&gt;This is important because it tells the Lambda when to start. I did the mistake of not doing that. Then, the code is executed before the Lambda event starts, so it keeps erroring.&lt;/p&gt;

&lt;p&gt;With his Lambda handler, we can pass information to the context, so we can do fun things like passing arguments to our code from HTTP query params. For example: &lt;a href="https://aws.amazon.com/premiumsupport/knowledge-center/pass-api-gateway-rest-api-parameters/" rel="noopener noreferrer"&gt;https://aws.amazon.com/premiumsupport/knowledge-center/pass-api-gateway-rest-api-parameters/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Code review
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;main.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/aws/aws-lambda-go/lambda"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/dghubble/oauth1"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/el-pol/lovebot/fetch"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/joho/godotenv"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;HandleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;godotenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;consumerKey&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CONSUMER_KEY"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;consumerSecret&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CONSUMER_SECRET"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;accessToken&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ACCESS_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;accessSecret&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TOKEN_SECRET"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PROMPT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;consumerKey&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;consumerSecret&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;accessToken&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;accessSecret&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Missing required environment variable"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Will return a trimmed string&lt;/span&gt;
    &lt;span class="n"&gt;fetched&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetGenerated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// From here on, Twitter POST API&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oauth1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consumerKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;consumerSecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;oauth1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accessSecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;httpClient&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oauth1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NoContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Necessary - you don't want to be charged for long Lambdas timing out.&lt;/span&gt;
    &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;

    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"https://api.twitter.com/2/tweets"&lt;/span&gt;

    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{"text": "%s"}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetched&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;bodyReader&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bodyReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error when posting to twitter: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Response was OK: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"finished"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lambda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HandleRequest&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;The code is very basic - as this is just a fun project for me to learn Go. BTW, if you see any errors or improvements, please let me know.&lt;/p&gt;

&lt;p&gt;And then in &lt;code&gt;fetch.go&lt;/code&gt; we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"bytes"&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/joho/godotenv"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetGenerated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;godotenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OPENAI_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Missing required environment variable"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Create the request body&lt;/span&gt;
    &lt;span class="n"&gt;jsonBody&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{"prompt": "%s", "max_tokens": 256, "model": "text-davinci-003"}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Create the request&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://api.openai.com/v1/completions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBuffer&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonBody&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error when creating request: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Add the headers&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bearer %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error when sending request: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Check the response&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Response was not OK: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Parse the response&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;respBody&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Choices&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"text"`&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`json:"choices"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;respBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error when decoding response: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;trimmed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TrimSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;respBody&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;trimmed&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Result is empty"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trimmed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;280&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Result is too long"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;trimmed&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Packages used
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="//github.com/aws/aws-lambda-go/lambda"&gt;github.com/aws/aws-lambda-go/lambda&lt;/a&gt;: Necessary only if we are going to use AWS Lambda.&lt;/li&gt;
&lt;li&gt;
&lt;a href="//github.com/dghubble/oauth1"&gt;github.com/dghubble/oauth1&lt;/a&gt;: To authenticate to the Twitter Oauth1.a API.&lt;/li&gt;
&lt;li&gt;
&lt;a href="//github.com/el-pol/lovebot/fetch"&gt;github.com/el-pol/lovebot/fetch&lt;/a&gt;: I put all the OpenAI code in &lt;code&gt;fetch.go&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="//github.com/joho/godotenv"&gt;github.com/joho/godotenv&lt;/a&gt;: To load &lt;code&gt;.env&lt;/code&gt; variables&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Packaging the code &amp;amp; uploading it to AWS Lambda
&lt;/h2&gt;

&lt;p&gt;For this part, I followed this amazing guide written by Toul: &lt;a href="https://dev.to/toul_codes/infrahamburglar-a-cybersecurity-news-bot-built-with-aws-lambda-golang-and-twitter-api-v2-198e"&gt;https://dev.to/toul_codes/infrahamburglar-a-cybersecurity-news-bot-built-with-aws-lambda-golang-and-twitter-api-v2-198e&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we need to build our application &amp;amp; then zip it. This zipped file is what we will uploadto AWS Lambda.&lt;/p&gt;

&lt;p&gt;To build in Go, write in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linux  &lt;span class="nv"&gt;GOARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;amd64 go build &lt;span class="nt"&gt;-o&lt;/span&gt; your-twitter-bot main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this is done, do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zip your-twitter-bot.zip your-twitter-bot 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This zip file is what you will upload as the code for your Lambda. Every further modification that you do will force you to repeat this two steps &amp;amp; upload again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the trigger
&lt;/h3&gt;

&lt;p&gt;Every time this Lambda runs, you will post a new tweet. The way to schedule it is using a cron expression using AWS CloudWatch Events, or EventBridge. The reference for EventBridge is here: &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure to refer to the docs, AWS’ cron expressions are a bit different from the standard: &lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before adding the trigger, you should test that your Lambda works. If you go into the &lt;em&gt;Test&lt;/em&gt; section of your Lambda, you can trigger it. We don’t care about the content of the event - since our Lambda does not depend on any parameters or arguments. So we can trigger any event, and it should fire and work. &lt;/p&gt;

&lt;p&gt;If it worked, you should see a new tweet in your bot account.&lt;/p&gt;

&lt;p&gt;If everything is OK, you can add the trigger so that the bot tweets every X amount of time with a cron expression.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finished!
&lt;/h2&gt;

&lt;p&gt;If you’ve reached the end, you should have a working bot.&lt;/p&gt;

&lt;p&gt;This is the one I made, give him a follow: &lt;a href="https://twitter.com/LoveAdviceWiseG" rel="noopener noreferrer"&gt;https://twitter.com/LoveAdviceWiseG&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%2F2t5e9vgn8xffq72t85ma.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%2F2t5e9vgn8xffq72t85ma.png" alt="View of the bot timeline"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>twitter</category>
      <category>gpt3</category>
      <category>aws</category>
    </item>
    <item>
      <title>First impressions of Go as a JavaScript developer</title>
      <dc:creator>Pol Milian</dc:creator>
      <pubDate>Tue, 20 Dec 2022 12:16:59 +0000</pubDate>
      <link>https://forem.com/elpol/first-impressions-of-go-as-a-javascript-developer-ibk</link>
      <guid>https://forem.com/elpol/first-impressions-of-go-as-a-javascript-developer-ibk</guid>
      <description>&lt;p&gt;In my latest role, I had the chance to learn a bit of Go (or &lt;em&gt;Golang&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;My whole programming career I've been using JavaScript and TypeScript. I dabbled a bit with PHP. So let's just say that Go is officially the &lt;em&gt;second&lt;/em&gt; programming language I'm learning.&lt;/p&gt;

&lt;p&gt;So, here are my takeaways:&lt;/p&gt;

&lt;h2&gt;
  
  
  It's easier to pick up a second language
&lt;/h2&gt;

&lt;p&gt;When I started with JavaScript, it was daunting. I had no idea about programming. All these concepts of memory, loops, data types, algorithms... Everything was new. You start to connect the dots after a while, and once you get the logic right, it's easy to spend hours on &lt;a href="https://developer.mozilla.org/en-US/"&gt;MDN&lt;/a&gt; and deepen your knowledge.&lt;/p&gt;

&lt;p&gt;Now, with Go, the thought process is more like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"So this is how you do a for loop, it's different from JavaScript in this and that way"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have the basics of a programming language in my mind, so with Go, it's just figuring out how those basics work. It's a great exercise to constantly compare both.&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript is a mess
&lt;/h2&gt;

&lt;p&gt;Everything in Go is more organized. &lt;code&gt;go.mod&lt;/code&gt; and &lt;code&gt;go.sum&lt;/code&gt; are so much simpler and clean than &lt;code&gt;package.json&lt;/code&gt; and the dreaded &lt;code&gt;package-lock.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://pkg.go.dev/cmd/go"&gt;Go CLI&lt;/a&gt; is a joy to use. The thing is that everything is built into the language. When we use JavaScript, we have to use NodeJS to interact with the OS. And NodeJS is great, but it is a library/framework &lt;em&gt;hacked&lt;/em&gt; on top of JS. I'm sure tho that if we had to rebuild NodeJS today, it would be much better (hello &lt;a href="https://deno.land/"&gt;Deno&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The documentation in Go is excellent. Every package has its documentation page. For example, let's have a look at the &lt;a href="https://pkg.go.dev/net/http"&gt;HTTP package&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything is faster in Go
&lt;/h2&gt;

&lt;p&gt;Or at least it feels that way. I don't know enough about the innards of Go to tell you why it is faster. But literally every action I do feels a bit faster than in JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Go is making me a better programmer?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pointers
&lt;/h3&gt;

&lt;p&gt;There are some basic programming concepts that you never even touch in JavaScript. The biggest one I've had to spend some time with are &lt;a href="https://www.geeksforgeeks.org/pointers-in-golang/"&gt;pointers&lt;/a&gt;. I'm still wrapping my head around when to use &lt;code&gt;*&lt;/code&gt; and &lt;code&gt;&amp;amp;&lt;/code&gt;, but at least the concept of memory addresses is clear in my head.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error handling
&lt;/h3&gt;

&lt;p&gt;I like the style of &lt;em&gt;defensive&lt;/em&gt; programming that Go enforces. There's a pattern you see all the time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"filename.ext"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Do something if there's no error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So whenever we do anything, we first check if there's an error. If not, we proceed.&lt;/p&gt;

&lt;p&gt;This is great, because how many times you've had an unhandled error in JavaScript? In JS you always need to actively make sure that you catch an error, usually with a &lt;code&gt;try/catch&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;In Go, by putting the error first, we make sure we always handle it.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can easily compile
&lt;/h2&gt;

&lt;p&gt;Whatever code you write, you can &lt;a href="https://go.dev/doc/tutorial/compile-install"&gt;build it as an executable file for multiple systems&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I'm not sure if you can do this in NodeJS - but for sure it's not built in. To run NodeJS programs you usually need to have NodeJS installed, and then run &lt;code&gt;node your-program.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript is simple &amp;amp; it works
&lt;/h2&gt;

&lt;p&gt;In JS, it's pretty easy to write some messy code in a few minutes and see its effect. Hell, you can even right now open the dev tools in your browser, go to the console and just do &lt;code&gt;alert('hello')&lt;/code&gt; and it will work. JS is still the language of the web; so I don't think it's going anywhere. &lt;/p&gt;

&lt;p&gt;Around the web, there are thousands of libraries written in JS. There's more documentation, and more people using JavaScript than Go. I've already had quite a hard time finding some answers for Go questions - and I always find the answer for JS.&lt;/p&gt;

&lt;p&gt;I can see Go succeeding at replacing NodeJS, but for websites, JS and its frameworks will still prevail.&lt;/p&gt;

&lt;p&gt;That's why, if you are a Full-Stack developer, I recommend you to take a look at Go, mostly for the backend: &lt;a href="https://go.dev/tour/welcome/1"&gt;https://go.dev/tour/welcome/1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>go</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to improve your technical interview? Start livestreaming!</title>
      <dc:creator>Pol Milian</dc:creator>
      <pubDate>Wed, 10 Aug 2022 05:49:00 +0000</pubDate>
      <link>https://forem.com/elpol/how-to-improve-your-technical-interview-start-livestreaming-6ed</link>
      <guid>https://forem.com/elpol/how-to-improve-your-technical-interview-start-livestreaming-6ed</guid>
      <description>&lt;p&gt;Recently I saw a video where &lt;a href="https://midu.dev/"&gt;Midudev&lt;/a&gt;, one of my favorite devs, gets interviewed:&lt;/p&gt;

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

&lt;p&gt;It was a great learning experience for me. I've rarely seen other people interview, so it was very enlightening in a few areas.&lt;/p&gt;

&lt;p&gt;The interview Miguel does is to join &lt;a href="https://arc.dev/"&gt;arc.dev&lt;/a&gt;. This is a company that connects companies to developers, something like &lt;a href="https://gun.io/"&gt;gun.io&lt;/a&gt;, &lt;a href="https://www.g2i.co/"&gt;g2i&lt;/a&gt;, and many others.&lt;/p&gt;

&lt;p&gt;Justin is the interviewer. I couldn't find a lot of information regarding him, but at the end of the interview he gives out a few details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;He has more than 10 years of experience, mostly in backend development.&lt;/li&gt;
&lt;li&gt;His favorite languages are Python and Go.&lt;/li&gt;
&lt;li&gt;Mostly USA based.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Why livestreaming will improve your interviewing skills:
&lt;/h1&gt;

&lt;h2&gt;
  
  
  You get used to the pressure
&lt;/h2&gt;

&lt;p&gt;I always get very nervous at live coding, I really dislike it. It's not an uncommon feeling: there's someone observing you and scrutinizing your every move and thought. The pressure is there to not let the interviewer hanging and to "think fast".&lt;/p&gt;

&lt;p&gt;Miguel, on the other hand, is very good at it. This comes probably from streaming on Twitch. &lt;a href="https://www.twitch.tv/midudev"&gt;He is a successful streamer&lt;/a&gt;, usually having around 1000+ viewers per stream. By streaming so much he is used to people watching him code live. That's why I think thatin the coding part of the interview he does so well.&lt;/p&gt;

&lt;p&gt;He is still nervous, but the way he deals with the problem and explains all his actions is exactly what Justin (the interviewer) wants to see. To be fair, I believe the speed at which he solves the problem is because a very common interview problem: performing a two objects join with JS.&lt;/p&gt;

&lt;p&gt;Still, it would have been hard for a lot of people; especially doing it live. I like how he uses &lt;code&gt;node/assert&lt;/code&gt; as a very quick way to show he knows TDD and to prove his assumptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  You have to explain everything
&lt;/h2&gt;

&lt;p&gt;When you are streaming or being interviewed, there should not be "dead air". You have to talk, to explain everything you are doing. That's a skill that streaming will give you that's useful for live interviews.&lt;/p&gt;

&lt;p&gt;It's never good to have assumptions about what the other person knows. That's also a good thing Miguel does: explain absolutely everything he is thinking and doing. This way, Justin is not left there wondering and just staring. He gets a feel for how Miguel thinks, which ultimately is the number one skill in programming: problem solving - and all the thought process behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  You'll have a live directory of your skills
&lt;/h2&gt;

&lt;p&gt;If you have been streaming for a while, the VODs (stored files of past streams) will be available for everyone to see. Imagine a recruiter clicking on your name and being able to see hours and hours of you coding. There's no better social proof than that.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to start streaming?
&lt;/h1&gt;

&lt;p&gt;You just need a webcam and a &lt;a href="https://www.twitch.tv/"&gt;Twitch account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To record yourself, there's software like &lt;a href="https://obsproject.com/"&gt;OBS&lt;/a&gt; or &lt;a href="https://streamlabs.com/"&gt;Streamlabs&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>interview</category>
      <category>preparation</category>
      <category>beginners</category>
    </item>
    <item>
      <title>What I learned from Frontendmasters' Full Stack for Front-End Engineers Course</title>
      <dc:creator>Pol Milian</dc:creator>
      <pubDate>Sat, 16 Jul 2022 07:50:42 +0000</pubDate>
      <link>https://forem.com/elpol/what-i-learned-from-frontendmasters-full-stack-for-front-end-engineers-course-3gpk</link>
      <guid>https://forem.com/elpol/what-i-learned-from-frontendmasters-full-stack-for-front-end-engineers-course-3gpk</guid>
      <description>&lt;p&gt;In this post, I will reflect on what I learned from &lt;a href="https://twitter.com/JemYoung?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor"&gt;Jem Young's&lt;/a&gt; course &lt;a href="https://frontendmasters.com/courses/fullstack-v2"&gt;"Full Stack for Front-End Engineers" on FrontendMasters&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To be fair, I already knew most of what he taught; so the following notes are just little tidbits that I didn't use in the past or concepts that I want to go over again.&lt;/p&gt;

&lt;p&gt;I really recommend the course to everyone, even if you are just starting programming it will give you a good overview of how the Internet works and how servers work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The command line
&lt;/h2&gt;

&lt;p&gt;Why do people still use the command line, when so many things can be done with a GUI (Graphical User Interface)?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GUIs are opinionated.&lt;/strong&gt; Interfaces always have details that force you to do things a certain way; and sometimes you have to fight around them to do what you really want.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The command line is always faster.&lt;/strong&gt; If you know what you want to do, there is no faster way than the command line. You just type it and do it, without using your mouse. Kind of like using VIM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Useful commands
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;cat&lt;/strong&gt;: If we do &lt;code&gt;cat FILE&lt;/code&gt;, it will show us the file contents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;less&lt;/strong&gt;: It's like &lt;code&gt;cat&lt;/code&gt;, but will show us less contents, one page at a time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Shells
&lt;/h2&gt;

&lt;p&gt;A terminal runs a shell. The shell is what interacts with the system and interprets our commands.&lt;/p&gt;

&lt;p&gt;If we do &lt;code&gt;echo $0&lt;/code&gt;, we can know the shell we are using. Common ones are bash, fish, zsh...&lt;/p&gt;

&lt;h2&gt;
  
  
  IP addresses and protocols
&lt;/h2&gt;

&lt;p&gt;HTTP is based on TCP. UDP is faster, but TCP is lossless and that's why we use it.&lt;/p&gt;

&lt;p&gt;We can ping a site, to know if it is working. For example, &lt;code&gt;ping twitter.com&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a server
&lt;/h2&gt;

&lt;p&gt;We can use a cloud provider like DigitalOcean or AWS to set up a virtual server. There are some steps we always need to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update software&lt;/li&gt;
&lt;li&gt;Create a new user&lt;/li&gt;
&lt;li&gt;Make that user a super user&lt;/li&gt;
&lt;li&gt;Enable login for new user&lt;/li&gt;
&lt;li&gt;Disable root login&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sudo !!&lt;/code&gt; returns the last command as super user.&lt;/li&gt;
&lt;li&gt;If we check the &lt;code&gt;auth.log&lt;/code&gt; file, we can see everyone that is trying to log in.&lt;/li&gt;
&lt;li&gt;A common command to check a log is &lt;code&gt;tail -f FILE&lt;/code&gt;. It will give us the last lines, and follow it in real time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SSH keys
&lt;/h3&gt;

&lt;p&gt;SSH is comprised of two keys: public and private. We will create a public key and copy it into &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;, just so that we don't need to enter the key every time we try to log into the server.&lt;/p&gt;

&lt;p&gt;It's good practice to disable root login in our SSH config: &lt;code&gt;PermitRootLogin no&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;SSH runs in port 22, but some people change it for safety reasons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nginx
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.nginx.com/"&gt;Nginx&lt;/a&gt; helps us route our requests to wherever we want. It's used as a reverse proxy, web server and proxy server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nginx + Express
&lt;/h3&gt;

&lt;p&gt;We can set up an &lt;a href="https://expressjs.com/"&gt;Express&lt;/a&gt; server and with Nginx, route the request to Express. This is called &lt;strong&gt;proxy pass&lt;/strong&gt;. We edit the Nginx config and proxy pass to &lt;code&gt;localhost:3000&lt;/code&gt;, or whatever port our Express server uses. &lt;/p&gt;

&lt;p&gt;After any config change we make, we can run &lt;code&gt;nginx -t&lt;/code&gt; to validate the config.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nginx config
&lt;/h3&gt;

&lt;p&gt;We can write redirects in Nginx. 301 are temporary redirects, and 302 are permanent redirects. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;location /help {
    return 301 https://google.com
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also have a subdomain. We can have a lot of different servers and a lot of different subdomains in Nginx.&lt;/p&gt;

&lt;h2&gt;
  
  
  Process manager
&lt;/h2&gt;

&lt;p&gt;It's good practice to add a process manager to our server. This way we can manage restarts, and keep the server running. A common one is &lt;a href="https://www.npmjs.com/package/pm2"&gt;pm2&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bash basics
&lt;/h2&gt;

&lt;p&gt;Bash is a Unix shell and a command line language used everywhere. There are some common operators and tricks that we should know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;|&lt;/code&gt; and &lt;code&gt;&amp;gt;&lt;/code&gt;: the pipe operator (&lt;code&gt;|&lt;/code&gt;) gets the output and &lt;em&gt;pipes&lt;/em&gt; it into something else. For example &lt;code&gt;ps | grep bash&lt;/code&gt;. It's a redirection operator. &lt;code&gt;&amp;gt;&lt;/code&gt; will write to a file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;find&lt;/code&gt; and &lt;code&gt;grep&lt;/code&gt;: &lt;code&gt;find&lt;/code&gt; will search file names, and &lt;code&gt;grep&lt;/code&gt; will search file contents.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;If we do &lt;code&gt;sudo apt install unattended-upgrades&lt;/code&gt;, it will auto upgrade packages to prevent against known vulnerabilities.&lt;/p&gt;

&lt;p&gt;We should have a firewall. Keep all the ports closed unless needed. To check which ports are open, we can use &lt;a href="https://nmap.org/"&gt;nmap&lt;/a&gt;. If we do &lt;code&gt;nmap OUR_IP&lt;/code&gt;, we can see which ports are open and closed.&lt;/p&gt;

&lt;p&gt;There is a tool called &lt;a href="https://help.ubuntu.com/community/UFW"&gt;ufw&lt;/a&gt; (uncomplicated firewall), that will make closing and opening ports easy for us. For example, &lt;code&gt;ufw allow ssh&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP
&lt;/h2&gt;

&lt;p&gt;HTTP is HyperText Transfer Protocol, it is based on a request/response model. We send and receive packets, and each packet contains HTTP data. These packets have HTTP headers and the contents.&lt;/p&gt;

&lt;p&gt;The headers are like the envelope where we see information about the packet. Example of headers: &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;user-agent&lt;/code&gt;, &lt;code&gt;accept&lt;/code&gt;, &lt;code&gt;accept-encoding&lt;/code&gt;. Custom headers usually start with &lt;code&gt;X-&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Everything in HTTP is stateless, that's why we use cookies, which are a way to persist information over time.&lt;/p&gt;

&lt;p&gt;We can create custom headers and custom status codes.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTPS
&lt;/h2&gt;

&lt;p&gt;HTTPS is encrypted HTTP. It encrypts all data in-transit&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP2
&lt;/h2&gt;

&lt;p&gt;Requires SSL. It's faster because it can do multiplexing, we can do everything in one connection. For example: &lt;a href="https://http2.akamai.com/demo"&gt;https://http2.akamai.com/demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cookies cannot be compressed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load balancers
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;top&lt;/code&gt; and &lt;code&gt;htop&lt;/code&gt; tell us everything that goes on in the server. Kind of like Activity Monitor, for a server.&lt;/p&gt;

&lt;p&gt;Nginx can be used as a load balancer: &lt;a href="https://nginx.org/en/docs/http/load_balancing.html"&gt;https://nginx.org/en/docs/http/load_balancing.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  WebSockets
&lt;/h2&gt;

&lt;p&gt;Bidirectional connection between server and client. We keep the connection open. Usual example is for a chat app, or a chatbot.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>cli</category>
    </item>
    <item>
      <title>Primitive vs reference values in JavaScript</title>
      <dc:creator>Pol Milian</dc:creator>
      <pubDate>Sat, 16 Jul 2022 07:47:20 +0000</pubDate>
      <link>https://forem.com/elpol/primitive-vs-reference-values-in-javascript-1lki</link>
      <guid>https://forem.com/elpol/primitive-vs-reference-values-in-javascript-1lki</guid>
      <description>&lt;p&gt;In this post, we will take a look at a super common interview question: primitive vs reference values in JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a primitive value?
&lt;/h2&gt;

&lt;p&gt;In JS, there are 6 primitive values: number, string, boolean, undefined, null and symbol.&lt;/p&gt;

&lt;p&gt;You can think of them as the &lt;em&gt;base&lt;/em&gt;, hence the name &lt;em&gt;primitive&lt;/em&gt;. These values are not objects and they don't have methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a reference value?
&lt;/h2&gt;

&lt;p&gt;The short answer is: anything that is not a primitive value is a reference value. They are &lt;code&gt;typeof "object"&lt;/code&gt;. We are talking about objects, arrays, functions, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key differences
&lt;/h2&gt;

&lt;p&gt;The key difference is how these values behave under the hood. Specifically, &lt;strong&gt;how they store their values in memory.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The primitive values would have the value in memory, while the reference values would have a reference to that location in memory (the memory address), and not the value itself.&lt;/p&gt;

&lt;p&gt;For example:&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;let&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jesus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;nickName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;

&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Juan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;console&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;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 'Juan'&lt;/span&gt;
&lt;span class="nx"&gt;console&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;nickName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 'Jesus'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are only using primitive values here, so everything makes sense. Right?&lt;/p&gt;

&lt;p&gt;Now, let's take a look at a reference values example:&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;let&lt;/span&gt; &lt;span class="nx"&gt;jose&lt;/span&gt; &lt;span class="o"&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;Person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jose&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;juan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jose&lt;/span&gt;

&lt;span class="nx"&gt;juan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Juan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;console&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;jose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 'Juan'&lt;/span&gt;
&lt;span class="nx"&gt;console&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;juan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 'Juan'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See? In here, the &lt;code&gt;juan&lt;/code&gt; variable is referencing the same spot in memory as the &lt;code&gt;jose&lt;/code&gt; variable. That is why when we change the &lt;code&gt;name&lt;/code&gt; property in one of them, we will be changing it in both.&lt;/p&gt;

&lt;p&gt;This behavior also explains why if we compare two seemingly equal reference values, the result will be &lt;code&gt;false&lt;/code&gt;. For example:&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;const&lt;/span&gt; &lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Yellow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Banana&lt;/span&gt;&lt;span class="dl"&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;snack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Yellow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Banana&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;snack&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So primitive types are compared by their value, while reference types are compared by their reference. &lt;/p&gt;

&lt;p&gt;Lastly, remember that &lt;strong&gt;primitive values are immutable.&lt;/strong&gt; So when you change a primitive value, what you are doing is replacing the in-memory value. You are not modifying it like you can do with reference values.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
