<?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: Typeform</title>
    <description>The latest articles on Forem by Typeform (@typeform).</description>
    <link>https://forem.com/typeform</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%2Forganization%2Fprofile_image%2F385%2F476e718c-4f4d-409e-a831-7bd8200f1018.png</url>
      <title>Forem: Typeform</title>
      <link>https://forem.com/typeform</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/typeform"/>
    <language>en</language>
    <item>
      <title>How I used Go to generate images for my dad’s meetups</title>
      <dc:creator>Alba Rincón</dc:creator>
      <pubDate>Wed, 15 Jul 2020 06:20:11 +0000</pubDate>
      <link>https://forem.com/typeform/image-generation-in-go-3bpi</link>
      <guid>https://forem.com/typeform/image-generation-in-go-3bpi</guid>
      <description>&lt;p&gt;I recently read a great article by Mat Ryer about &lt;a href="https://pace.dev/blog/2020/03/02/dynamically-generate-social-images-in-golang-by-mat-ryer.html"&gt;programmatically generating images in Go&lt;/a&gt; and got inspired by it to solve a repetitive task I usually do every month.&lt;/p&gt;

&lt;p&gt;My dad is the head of an organization called &lt;a href="http://projecte-loc.org/"&gt;Projecte LOC&lt;/a&gt; that promotes reading to kids and adults in Cornellà de Llobregat, Spain. Once a month they organize a meet-up: either a literary dinner with a book author to talk about a book or a storytelling session. He usually asks me to create an image to illustrate the event and sends the details via email to all the members of the organization. The illustration looks like this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--agxqWepu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xlhymqmox4cc3wn6besi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--agxqWepu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xlhymqmox4cc3wn6besi.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's quite annoying to do it every single month by hand, importing the image, aligning text, adjusting everything... I usually make mistakes copying the day, the time and the title from the email he sends to me. I end up re-doing it entirely after he finds typos/mistakes.&lt;/p&gt;

&lt;p&gt;So when I saw Mat's article I immediately thought that I could do something to improve this tedious process both for myself and my dad. Wouldn't it be great to have something where he would enter a few variable data about the meet-up (title, guest, image and date) and I would programmatically generate the whole image?&lt;/p&gt;

&lt;p&gt;I needed something really simple and user friendly for him to enter the info. That was an easy decision: Typeform. He's used to typeforms and I know the API really well, after all, I helped build it. Then, I would take advantage of Typeform webhooks to get the response details from the form submission, process the info about the meet-up, generate the corresponding image and provide a link for him to download it. 💪&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Creating the Typeform 🛠
&lt;/h2&gt;

&lt;p&gt;First, I created the typeform with all the fields that would change for each meet-up. Each field has a unique identifier called &lt;code&gt;reference&lt;/code&gt;, which is useful to identify the fields on the response payload that we'll receive on the webhook. By default, this &lt;code&gt;reference&lt;/code&gt; is a long alphanumeric string, but I modified it on the &lt;em&gt;Create Panel&lt;/em&gt; to look a bit more human-readable so I could identify each answer quickly in the code.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iElC6DQW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oioj0m9ky46i5bf6mimi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iElC6DQW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oioj0m9ky46i5bf6mimi.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Next, I created the webhook on the Connect Panel pointing it to an endpoint that will handle each typeform submission.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jxrhCyF1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wfu1to3xhagkn9d3y53c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jxrhCyF1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wfu1to3xhagkn9d3y53c.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Handling the webhook ⚓️
&lt;/h2&gt;
&lt;h3&gt;
  
  
  2.1. Signature verification ✍️
&lt;/h3&gt;

&lt;p&gt;When creating a webhook we are exposing the endpoint URL to the internet, which is not &lt;a href="https://developers.typeform.com/webhooks/secure-your-webhooks/"&gt;secure&lt;/a&gt;. Potentially anyone with bad intentions could request to it with any data. I wanted to be sure that I was only processing webhooks coming from Typeform, so I added a &lt;code&gt;secret&lt;/code&gt; on my webhook configuration. Then, Typeform would use it to sign the webhook payload and add it as a header on the request.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YnIgilZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c60i1x4rpjyqkenjov7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YnIgilZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c60i1x4rpjyqkenjov7m.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
To accept an incoming webhook request, the first thing the handler has to do is verify that Typeform sent it. &lt;/p&gt;

&lt;p&gt;This is done with the &lt;code&gt;verifySignature&lt;/code&gt; function that takes multiple parameters: the request body, the shared &lt;code&gt;secret&lt;/code&gt; with Typeform, and the value of the &lt;code&gt;Typeform-Signature&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;Then, it computes the signature for the received payload with the &lt;code&gt;secret&lt;/code&gt; and compares the result with the &lt;code&gt;receivedSignature&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;func&lt;/span&gt; &lt;span class="n"&gt;verifySignature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&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;secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receivedSignature&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&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;signature&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;computeSignature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secret&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="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;receivedSignature&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;computeSignature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&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;secret&lt;/span&gt; &lt;span class="kt"&gt;string&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;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;,&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;secret&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;_&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;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&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="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&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="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"sha256="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StdEncoding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EncodeToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sum&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="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the comparison succeeds we are sure the request is coming from Typeform so the execution can proceed, otherwise, the handler stops and returns an error.&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;generateHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&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;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// 1. Read the request body&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&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="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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&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;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&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;r&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;// 2. Verify the signature&lt;/span&gt;
    &lt;span class="n"&gt;ok&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;verifySignature&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;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="n"&gt;secretToken&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;r&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;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Typeform-Signature"&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="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&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;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// 3. The verification succeeded so we can process the webhook 🙌&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.2. Creating a Poster from the submission 🖼
&lt;/h3&gt;

&lt;p&gt;At this point, we are sure the request is perfectly safe. The next step is actually reading and parsing the JSON body of the request and storing it somewhere. To do that, we create a variable of &lt;a href="https://github.com/albarin/nit-del-llop/blob/master/pkg/poster/webhooks.go"&gt;type Webhook&lt;/a&gt; and unmarshal the request body into it.&lt;/p&gt;

&lt;p&gt;Next, we want to convert the Webhook into a &lt;a href="https://github.com/albarin/nit-del-llop/blob/master/pkg/poster/poster.go#L21"&gt;Poster&lt;/a&gt; variable holding only the answers to each of the typeform questions. This will simplify the rendering task, we won't have to work anymore with a complicated Webhook struct with full of non relevant data.&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;generateHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&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;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// 1. Read the request body&lt;/span&gt;
      &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="c"&gt;// 2. Verify the signature&lt;/span&gt;
      &lt;span class="o"&gt;...&lt;/span&gt;

        &lt;span class="c"&gt;// 3. Parse the webhook from the request body&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wh&lt;/span&gt; &lt;span class="n"&gt;poster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Webhook&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;Unmarshal&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wh&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;WithFields&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;Fields&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not unmarshal webhook"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&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;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// 4. Convert the webhook data to a Poster&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;wh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToPoster&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c"&gt;// 5. Generate the image&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ToPoster()&lt;/code&gt; function loops over the answers of the webhook using the &lt;code&gt;reference&lt;/code&gt; attribute (that we previously set when creating the form) to identify to which poster field it corresponds.&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;type&lt;/span&gt; &lt;span class="n"&gt;Poster&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;Title&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Guest&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Date&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;Time&lt;/span&gt;
    &lt;span class="n"&gt;Time&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;PicURL&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Type&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;Webhook&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ToPoster&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;Poster&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;poster&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Poster&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Answers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ref&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;poster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"guest"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;poster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Guest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"date"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&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;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;poster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"time"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;poster&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;answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;poster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Choice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Label&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"pic"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;poster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PicURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PicURL&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;poster&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Generating the image 👩‍🎨
&lt;/h2&gt;

&lt;p&gt;Finally we have our Poster ready to be rendered! 👏&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;generateHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&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;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// 1. Read the request body&lt;/span&gt;
      &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="c"&gt;// 2. Verify the signature&lt;/span&gt;
      &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="c"&gt;// 3. Parse the webhook from the request body&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="c"&gt;// 4. Convert the webhook data to a Poster&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;

        &lt;span class="c"&gt;// 5. Generate the image&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;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Render&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;WithFields&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;Fields&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not generate poster"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&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;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&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;Let's dive into the &lt;code&gt;Render&lt;/code&gt; method. We will use the &lt;a href="https://github.com/fogleman/gg"&gt;Go Graphics&lt;/a&gt; &lt;a href="https://github.com/fogleman/gg"&gt;https://github.com/fogleman/gg&lt;/a&gt; rendering library to generate the final image.&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;Poster&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Render&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="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&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;drawBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"assets/images/background.png"&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;drawBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"assets/images/logos.png"&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;drawPicture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;drawText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SavePNG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"poster.png"&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The poster always has a similar format with the same background and sponsors logos at the bottom, so that's the first part we will render with the &lt;code&gt;drawBackground&lt;/code&gt; and &lt;code&gt;drawLogos&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;Drawing the picture poster is a bit more interesting since it's uploaded through the typeform and we don't really know the size it will have. In the Poster variable, we have the url of the picture. First we will download it to a temporary file with the &lt;code&gt;[poster.Picture()](https://github.com/albarin/nit-del-llop/blob/master/pkg/poster/poster.go#L71)&lt;/code&gt; method, resize it to fit into the poster and position it in the right image coordinates.&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;drawPicture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gg&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="n"&gt;poster&lt;/span&gt; &lt;span class="n"&gt;Poster&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="c"&gt;// Download the picture to a local file&lt;/span&gt;
    &lt;span class="n"&gt;filepath&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;poster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Picture&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Load it&lt;/span&gt;
    &lt;span class="n"&gt;pic&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;gg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Resize it&lt;/span&gt;
    &lt;span class="n"&gt;resizedPic&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Thumbnail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bounds&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dx&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="m"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;pic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lanczos3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c"&gt;// Position and draw it&lt;/span&gt;
    &lt;span class="n"&gt;contentWidth&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;margin&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DrawImageAnchored&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resizedPic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;margin&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;contentWidth&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;185&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.5&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="c"&gt;// Delete the temporary file&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;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only part left now is drawing all the info about the meet-up (title, guest, image and date) with the &lt;code&gt;drawText&lt;/code&gt; method. The challenge here is making sure all the text lines fit in our image, since it comes from a user input we have no idea how long those lines could be. We need to change the font size depending on the length of the line.&lt;/p&gt;

&lt;p&gt;To simplify the task we create an array of &lt;code&gt;Line&lt;/code&gt; structs holding all the info of the poster. Each &lt;code&gt;Line&lt;/code&gt; has the text to render, the margin to position it, the font name, and the default font size. If the font size is too big causing the text to overflow the image, it will be decreased until it fits.&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;drawText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gg&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="n"&gt;poster&lt;/span&gt; &lt;span class="n"&gt;Poster&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="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;White&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c"&gt;// Lines with all the info to render&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Line&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;text&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;`"%s"`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;poster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;marginTop&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;290&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;fontSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;fontPath&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;RobotoBold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="s"&gt;"amb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;marginTop&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;fontSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;fontPath&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;RobotoLight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;text&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;"%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;poster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Guest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;marginTop&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;fontSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;fontPath&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;RobotoBold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;poster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;marginTop&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;fontSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;fontPath&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;RobotoLight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;poster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;marginTop&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;fontSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;fontPath&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;RobotoLight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;contentWidth&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;positionX&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;margin&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;contentWidth&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;positionY&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;margin&lt;/span&gt;

    &lt;span class="c"&gt;// Loop through each line adjusting the font and drawing it&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;lines&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;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadFontFace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fontPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fontSize&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adjustFontSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contentWidth&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;positionY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculatePositionY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;positionY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DrawStringAnchored&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&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="n"&gt;positionX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;positionY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.5&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="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we have our poster! We just need to save it as a PNG file.&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;Poster&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Render&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="c"&gt;// Draw everything&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="c"&gt;// Store the poster in a file&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;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SavePNG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"poster.png"&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Downloading the poster ⬇️
&lt;/h2&gt;

&lt;p&gt;Lastly, the most important part. You must be thinking how my dad is going to access this beautiful poster file and download it. 🤔Let me explain:&lt;/p&gt;

&lt;p&gt;As you saw in the last step, we always save the image with the same name, so we know for sure that after the typeform submission, we'll have the poster available in the same path. We'll take advantage of that fact and create another handler on the &lt;code&gt;/download&lt;/code&gt; endpoint that shows the poster on the browser.&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;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&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;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;image&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;"poster.png"&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;WithFields&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;Fields&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not open image"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&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;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&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;image&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&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;"image/png"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_&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;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&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;WithFields&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;Fields&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not write image"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&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;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we go back to our typeform &lt;em&gt;Create Panel&lt;/em&gt; and add that link into the Thank You Screen button. With this setup, after the form is submitted, the Thank You Screen will be shown and we'll be able to download the poster by clicking on the button.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g_umTvlE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/98okqafrhfs3y0ucxbmh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g_umTvlE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/98okqafrhfs3y0ucxbmh.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  5. Deploying it 🚀
&lt;/h2&gt;

&lt;p&gt;I wanted to practice my Docker skills a bit so I decided to use Docker and Heroku to deploy the application.&lt;/p&gt;
&lt;h3&gt;
  
  
  5.1. Dockerize it 📦
&lt;/h3&gt;

&lt;p&gt;The first thing to do was to &lt;em&gt;dockerize&lt;/em&gt; the app. I did it with a multi-stage build. In the first part, we are using &lt;code&gt;golang:1.14-alpine&lt;/code&gt; image to build the app into a binary called &lt;code&gt;poster&lt;/code&gt;. Then, in the second step we use the &lt;code&gt;alpine:latest&lt;/code&gt; image to copy the binary from the previous stage and run it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; golang:1.14-alpine AS builder&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; . /poster&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /poster&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;go mod download
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nv"&gt;CGO_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 go build &lt;span class="nt"&gt;-ldflags&lt;/span&gt; &lt;span class="s2"&gt;"-s -w"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; poster cmd/poster/&lt;span class="k"&gt;*&lt;/span&gt;.go

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:latest&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk &lt;span class="nt"&gt;--no-cache&lt;/span&gt; add ca-certificates
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /poster ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x poster
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ./poster&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.2. Deploy to Heroku
&lt;/h3&gt;

&lt;p&gt;I choose to go with &lt;a href="https://www.heroku.com/"&gt;Heroku&lt;/a&gt; for the deployment, because they support Docker image deploy with their CLI app.&lt;/p&gt;

&lt;p&gt;I created a free account and installed the &lt;a href="https://devcenter.heroku.com/articles/heroku-cli#download-and-install"&gt;CLI app&lt;/a&gt;. After that, creating the application was just logging in and running a simple command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;heroku create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a result of that command a new app is created in our account and it displays a generated URL to access it.&lt;/p&gt;

&lt;p&gt;Once your app is created, you need to tell Heroku which Docker file to use to run your app. We create a &lt;code&gt;heroku.yml&lt;/code&gt; at the root of our application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, our app is ready to be deployed using git:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;git push heroku master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the app has been deployed. We can access the handler at &lt;code&gt;https://{something}.herokuapp.com/download&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The last step is to update our webhook and Thank You screen buttons to point to the new URLs. Now it works! 💥&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5h4jfsVp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cparlg5r9f933mccnmp3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5h4jfsVp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cparlg5r9f933mccnmp3.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I took the opportunity to change the design a bit, this is what it looks like now! 😁&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sHJTy-ND--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nu48ruw2j63ctsrufv2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sHJTy-ND--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nu48ruw2j63ctsrufv2d.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can find the full code: &lt;a href="https://github.com/albarin/nit-del-llop"&gt;https://github.com/albarin/nit-del-llop&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading, any comments or questions are welcomed 😊&lt;/p&gt;

</description>
      <category>go</category>
      <category>typeform</category>
      <category>webhooks</category>
      <category>backend</category>
    </item>
    <item>
      <title>Collect Addresses on Typeform using Algolia Places</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Wed, 06 May 2020 20:16:41 +0000</pubDate>
      <link>https://forem.com/typeform/collect-addresses-on-typeform-using-algolia-places-1jog</link>
      <guid>https://forem.com/typeform/collect-addresses-on-typeform-using-algolia-places-1jog</guid>
      <description>&lt;p&gt;During the last weeks as the world was getting under lockdown, many small businesses had to close doors and put their activities on hold. This was actually a new beginning for many business owners, as they were looking for opportunities to continue running their shops while respecting government measures and social distances.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://typeform.com"&gt;Typeform&lt;/a&gt; we've seen many initiatives to help digitalize small businesses, by providing for example interfaces to take online orders or do deliveries. From farmers in the mountains of Chamonix to a bakery in Barcelona, all stores were facing similar issues and were looking for simple solutions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://typeform.com"&gt;Typeform&lt;/a&gt; lets you create easily a visual "menu" where customers can pick what they want to buy. Typeform then calculates the price automatically and displays a credit card payment field using &lt;a href="https://stripe.com"&gt;Stripe&lt;/a&gt;. Overall it's a very seamless process until you reach the part where you have to ask your customer for their address and where you should deliver the goods.&lt;/p&gt;

&lt;p&gt;In most cases, it's done by asking a group of questions. Usually, you ask first the street, then the postcode and finally the city. But when it comes to addresses it's hard to be consistent as there are so many ways to write it. Especially right now when this typeform is shared with people that are not tech-savvy. This means business owners have to spend countless hours going manually to every single order a check if the address was correctly filled.&lt;/p&gt;

&lt;p&gt;Unfortunately, we currently don't have native support in Typeform's product for an autocomplete address field. But as a Developer Advocate, I don't take no for an answer!&lt;/p&gt;

&lt;p&gt;There has to be a better way! And this is where hacker spirit kicks in!&lt;/p&gt;

&lt;p&gt;Algolia has been maintaining since 2016 a library called Places, doing exactly what we need. It's based on data from OpenStreetMap, and do autosuggestion as you type.&lt;/p&gt;

&lt;p&gt;In this article, I will show you how you can connect it to your Typeform and collect accurate addresses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it live 📺
&lt;/h2&gt;

&lt;p&gt;If you want to get a preview of what we are about to build, check it out &lt;a href="https://tf-algolia-places.glitch.me"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter the address of your choice, and you should be redirected to a typeform to order some good pizzas 🍕&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/XHvgQpf080vtTX2jf7/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/XHvgQpf080vtTX2jf7/giphy.gif" alt="demo typeform algolia"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-requisites 🛒
&lt;/h3&gt;

&lt;p&gt;A Typeform account, create one for free &lt;a href="https://www.typeform.com/?utm_source=dev.to&amp;amp;utm_campaign=devrel_projects&amp;amp;utm_medium=referral&amp;amp;utm_content=tf-algolia-places"&gt;here&lt;/a&gt;&lt;br&gt;
An Algolia Places account, get one for free &lt;a href="https://www.algolia.com/users/sign_up/places"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Add Algolia Places to your project 📍
&lt;/h2&gt;

&lt;p&gt;The good thing about this hack? We don't need any server-side code!&lt;br&gt;
Everything could happen in a plain HTML page with a bit of Javascript.&lt;/p&gt;

&lt;p&gt;Let's start by loading the library on our page.&lt;br&gt;
Adds this at the bottom of just before &lt;code&gt;&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/places.js@1.18.1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In our page, we then add an HTML element that will be the autocomplete field.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"address-input"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Where do you live?"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we have to initialize the library and connect it to this field.&lt;/p&gt;

&lt;p&gt;Add this snippet at the end of your page&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;placesAutocomplete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;places&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_APP_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#address-input&lt;/span&gt;&lt;span class="dl"&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;address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Replace &lt;code&gt;YOUR_APP_ID&lt;/code&gt; and &lt;code&gt;YOUR_API_KEY&lt;/code&gt; by the values given in Algolia dashboard.&lt;/p&gt;

&lt;p&gt;💥You should now have a functioning autocomplete field. Open your HTML page and try it out.&lt;/p&gt;
&lt;h3&gt;
  
  
  Customize the library 🖌️
&lt;/h3&gt;

&lt;p&gt;Right now, our example auto-suggests addresses all over the world, but the library is very flexible. If you add &lt;code&gt;countries: ['us']&lt;/code&gt; for example it will only show addresses in the US.&lt;/p&gt;

&lt;p&gt;I recommend you to check the &lt;a href="https://community.algolia.com/places/documentation.html"&gt;documentation&lt;/a&gt; to customize it the way you want 😉&lt;/p&gt;
&lt;h3&gt;
  
  
  Listen to changes 👂
&lt;/h3&gt;

&lt;p&gt;What is happening when the user has selected their address? At the moment nothing, because we haven't coded this part.&lt;/p&gt;

&lt;p&gt;To do that we add an event listener to the &lt;code&gt;placesAutocomplete&lt;/code&gt; object we created earlier. The Algolia Places library has many events available, but we are only interested by the &lt;code&gt;change&lt;/code&gt; event. This event will be triggered every time the address selected changes.&lt;/p&gt;

&lt;p&gt;In your code add the following lines:&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="nx"&gt;placesAutocomplete&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now you can restart your app, type an address, and select it. In your browser developer console, you now see the details of what's returned by the library.&lt;/p&gt;

&lt;p&gt;🤩 That's a lot of interesting data formatted exactly the way we need, but we may just need a subset of it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's prepare your typeform 👩‍🎨
&lt;/h2&gt;

&lt;p&gt;Now that you've seen the potential of this library, you may have a better understanding of which type of data you want to use in your typeform.&lt;/p&gt;

&lt;p&gt;For this example, we are going to pass &lt;code&gt;address&lt;/code&gt;, &lt;code&gt;city&lt;/code&gt;, &lt;code&gt;postcode&lt;/code&gt; and &lt;code&gt;country&lt;/code&gt; value only. To pass the data from our code to the typeform we are going to rely on &lt;a href="https://help.typeform.com/hc/en-us/articles/360029114712-How-to-use-Hidden-Fields"&gt;Hidden Fields&lt;/a&gt;. Hidden fields are a way to pass data to a typeform by adding query parameters to its URL.&lt;/p&gt;

&lt;p&gt;Your original typeform URL was:&lt;br&gt;
&lt;code&gt;https://picsoung.typeform.com/to/FWq00K&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It's now going to be &lt;code&gt;https://picsoung.typeform.com/to/FWq00K?address=xxxx&amp;amp;postcode=xxxx&amp;amp;country&amp;amp;city=xxxx&lt;/code&gt; where &lt;code&gt;xxxx&lt;/code&gt; is the value extracted thanks to Algolia Places.&lt;/p&gt;

&lt;p&gt;Let's now add hidden fields to your typeform. Click &lt;code&gt;+&lt;/code&gt; and select &lt;code&gt;hidden fields&lt;/code&gt;. Hidden fields are sitting at the top of your form and you can add as many as you want. Only the parameters declared as hidden fields will be passed to the results. You can also use hidden fields in the conditional logic, for example, to showcase that you don't do deliveries in certain postcodes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/kHxIgm99KvBOn6s90e/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/kHxIgm99KvBOn6s90e/giphy.gif" alt="Add hidden fields to a typeform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure it works by opening the URL of your typeform with hidden fields values put manually. Once you've submitted the typeform, in the &lt;code&gt;Results&lt;/code&gt; panel you should see that the values have been passed and recorded correctly.&lt;/p&gt;
&lt;h2&gt;
  
  
  Link our code to the typeform 🔗
&lt;/h2&gt;

&lt;p&gt;Now that we have the two pieces working independently, let's connect them together!&lt;/p&gt;
&lt;h3&gt;
  
  
  Construct the URL of the form 🏗️
&lt;/h3&gt;

&lt;p&gt;As we saw we need to append query parameters to our Typeform URL.&lt;br&gt;
In our code, add this snippet and replace &lt;code&gt;YOUR_TYPEFORM_URL&lt;/code&gt; with your own typeform URL.&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;typeformURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_TYPEFORM_URL&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;hidden_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;postcode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postcode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;hidden_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hidden_values&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hidden_values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp;&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;completeURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;typeformURL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hidden_query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We create a &lt;code&gt;hidden_values&lt;/code&gt; object with all the parameters we get from Algolia Places. &lt;br&gt;
We then turn this object into a string so it looks like &lt;code&gt;country=France&amp;amp;city=Paris...&lt;/code&gt; using a bit of ES6 magic to store it in &lt;code&gt;hidden_query&lt;/code&gt; variable.&lt;br&gt;
&lt;code&gt;completeURL&lt;/code&gt; is then the concatenation of our original URL and the hidden values.&lt;/p&gt;

&lt;p&gt;We now have two options, either we redirect the user to our typeform, or we embed it in our page.&lt;/p&gt;
&lt;h4&gt;
  
  
  Redirect ↪️
&lt;/h4&gt;

&lt;p&gt;Redirection is the easiest thing, just after the previous snippet add this line in your code:&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;completeURL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And that's it, you are now redirected to your form and location data are passed as hidden fields.&lt;/p&gt;
&lt;h4&gt;
  
  
  Embed 🖼️
&lt;/h4&gt;

&lt;p&gt;To embed your typeform in your page we will use our &lt;a href="https://github.com/typeform/embed"&gt;Embed SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, let's add the Embed SDK at the bottom of your page.&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://embed.typeform.com/embed.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; of your HTML page you need to add an HTML element where the form will be embedded.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"typeform_embed"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"height: 900px;width: 100%;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Give it the size you want by modifying the &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; properties.&lt;/p&gt;

&lt;p&gt;Now we need to embed the typeform when we receive the &lt;code&gt;change&lt;/code&gt; event from the Algolia library.&lt;/p&gt;

&lt;p&gt;Just after the line &lt;code&gt;let completeURL ...&lt;/code&gt; add the following:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;embedElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#typeform_embed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;typeformEmbed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;makeWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;embedElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;completeURL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;hideHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hideFooter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;buttonText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Take the survey!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Typeform successfully submitted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This piece of code loads the typeform with all the parameters and place it in the object with id &lt;code&gt;typeform_embed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.typeform.com/embed/"&gt;Typeform's Embed SDK&lt;/a&gt; has a lot of features and you can personalize many things on the look and feel of the embed, we just went for the easiest path.&lt;/p&gt;

&lt;p&gt;Note, the &lt;code&gt;onSubmit&lt;/code&gt; function, this will be triggered when the form is submitted. This could be useful to hide the form after being submitted, for example.&lt;/p&gt;

&lt;p&gt;You should now have a typeform appearing on your page after selecting an address in the field. And if you change the address it will update the typeform URL and embed it again.&lt;/p&gt;
&lt;h2&gt;
  
  
  Going further 🚀
&lt;/h2&gt;

&lt;p&gt;With this hack, you are now collecting sanitized addresses from your customers when they are filling up a typeform. 🎉&lt;/p&gt;

&lt;p&gt;You can personalize the settings of the Algolia Places library to restrict to certain countries or to a different type of address. The library even supports searching for airports!&lt;/p&gt;

&lt;p&gt;You can also pass other types of data as hidden fields to your form. Like the latitude or longitude.&lt;/p&gt;

&lt;p&gt;With a bit of CSS you can modify the look and feel of the search box and make it your own.&lt;/p&gt;

&lt;p&gt;On Typeform you can now add some logic jumps to react differently depending on the locations data collected in the hidden fields.&lt;/p&gt;

&lt;p&gt;I hope you liked this hack and found it useful.&lt;br&gt;
Feel free to suggest some other ideas ;)&lt;/p&gt;

&lt;p&gt;The complete source code is available on &lt;a href="https://glitch.com/~tf-algolia-places"&gt;Glitch&lt;/a&gt;&lt;/p&gt;


&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/tf-algolia-places?previewSize=0&amp;amp;path=index.html" alt="tf-algolia-places on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;



</description>
      <category>tutorial</category>
      <category>javascript</category>
      <category>typeform</category>
      <category>algolia</category>
    </item>
    <item>
      <title>Tutorial: Hacking a robot while respecting fundamental laws of robotics</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Mon, 19 Aug 2019 18:43:45 +0000</pubDate>
      <link>https://forem.com/typeform/tutorial-hacking-a-robot-and-respecting-fundamental-laws-of-robotics-54c4</link>
      <guid>https://forem.com/typeform/tutorial-hacking-a-robot-and-respecting-fundamental-laws-of-robotics-54c4</guid>
      <description>&lt;p&gt;This past week I got invited to attend &lt;a href="https://signal.twilio.com" rel="noopener noreferrer"&gt;Twilio Signal&lt;/a&gt; conference in San Francisco as part of their Champions program.&lt;/p&gt;

&lt;p&gt;I had the chance to meet other awesome Champions at our Summit. You should all follow them, they are all doing amazing things in their communities all around the world. Find more about the Twilio Champions program &lt;a href="https://www.twilio.com/champions" rel="noopener noreferrer"&gt;over here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The conference itself was full of great announcements around the Twilio eco-system. I am mostly excited by &lt;a href="https://www.twilio.com/conversations" rel="noopener noreferrer"&gt;Conversations&lt;/a&gt;, as a way to connect many people uing different systems (SMS, WhatsApp, chat...) into the same conversation. The new &lt;a href="https://github.com/twilio/twilio-cli" rel="noopener noreferrer"&gt;Twilio CLI&lt;/a&gt; to do everything around Twilio directly in the terminal looks pretty awesome too.&lt;/p&gt;

&lt;p&gt;Another big announcement at Signal was version 3 of &lt;a href="https://www.twilio.com/quest" rel="noopener noreferrer"&gt;TwilioQuest&lt;/a&gt; available on Desktop. If you are not familiar with TwilioQuest, imagine a video game where you gain XP points by solving coding challenges.&lt;br&gt;
It's a fun way to learn about the Twilio world and programming in general.&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%2Fwww.twilio.com%2Fquest%2Fnext%2Fimg%2Fscreenshots%2Fexplore.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%2Fwww.twilio.com%2Fquest%2Fnext%2Fimg%2Fscreenshots%2Fexplore.png" alt="screenshot of TwilioQuest"&gt;&lt;/a&gt;&lt;/p&gt;
Screenshot of TwilioQuest



&lt;p&gt;The main character you interact within TwilioQuest, is named &lt;em&gt;Cedric&lt;/em&gt; and is a friendly robot that is guiding you through your quest against the &lt;em&gt;Legacy Systems&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The thing I did not realize: Cedric is real! He and his friends attended Signal too. They were so many roaming the expo floor and booths.&lt;/p&gt;

&lt;p&gt;There even was a special Signal mission on TwilioQuest to earn XPs if you were spending some time with the team of &lt;a href="https://mistyrobotics.com" rel="noopener noreferrer"&gt;Misty Robotics&lt;/a&gt; (parent company of the Misty robot, Cedric's robot family).&lt;/p&gt;

&lt;p&gt;And this exactly what I did! I went over to meet the Misty Robotics team to learn more about those friendly robots🤖&lt;/p&gt;

&lt;p&gt;The team was organizing Developers testing sessions, and inviting people to try their &lt;em&gt;Hello World&lt;/em&gt; tutorial to "hack" the robot.&lt;/p&gt;

&lt;p&gt;Misty is an incredible robot, among many things she has multiple sensors to move around your house without bumping into anything, a speaker to express herself, a screen to show some emotions, and a camera with face recognition capability. And all that is hackable through an SDK! 🎉&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fpxgaixc6e8stohh53h3o.jpg" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fpxgaixc6e8stohh53h3o.jpg" alt="Misty robot look"&gt;&lt;/a&gt;&lt;/p&gt;
Isn't she lovely?



&lt;p&gt;I had a lot of fun following the tutorial. I made Misty move, make her blink her light and even taught her to recognize me. At the end of the session, the team was handing out surveys to collect feedback. And as you may have already guessed it was a Typeform! 🤩&lt;/p&gt;

&lt;p&gt;Then I had no option... I had to connect Misty to Typeform.&lt;/p&gt;

&lt;p&gt;I wanted to make Misty react every time someone was filling up the survey.&lt;/p&gt;

&lt;p&gt;Here is how I managed to connect the two.&lt;/p&gt;
&lt;h1&gt;
  
  
  Overall principle 📖
&lt;/h1&gt;

&lt;p&gt;We rely on Typeform webhooks functionality to react immediately after someone answered.&lt;/p&gt;

&lt;p&gt;The webhook is received by an app that can call the Misty API and make the robot react.&lt;/p&gt;

&lt;p&gt;But to be able to communicate with the Misty robot, your app needs to be on the same WIFI network, so it's most likely that you will run it locally on your laptop.&lt;/p&gt;

&lt;p&gt;We will use &lt;a href="http://ngrok.io" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt; to expose localhost to the world 🌍.&lt;/p&gt;
&lt;h1&gt;
  
  
  Make the Misty move her arm
&lt;/h1&gt;

&lt;p&gt;We create a small express app with only one endpoint in a file named &lt;code&gt;app.js&lt;/code&gt;. This endpoint will receive webhook notification and then call Misty API.&lt;/p&gt;

&lt;p&gt;This is how it looks:&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&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;bodyParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// parse application/x-www-form-urlencoded&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;

&lt;span class="c1"&gt;// parse application/json&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;ROBOT_IP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10.41.129.96&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;//change to your own&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ROBOT_IP&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/arms`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
        &lt;span class="na"&gt;Arm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Velocity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Units&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;degrees&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Example app listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can run the app by using the command &lt;code&gt;node app.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And to make her arm go up, run the following command &lt;code&gt;curl -X POST https://localhost:300&lt;/code&gt; in your terminal. &lt;/p&gt;

&lt;p&gt;And if everything works well you should see Misty's left arm going up 🎉&lt;/p&gt;
&lt;h1&gt;
  
  
  Connect it to Typeform 🔗
&lt;/h1&gt;

&lt;p&gt;All this is working well locally, but wouldn't it be cool to connect it to other services?&lt;/p&gt;

&lt;p&gt;To make it happen we need the help of an awesome tool called &lt;a href="https://ngrok.com/" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt;. ngrok will expose your localhost and make it available to rest of the internet by giving it a URL. This URL is unique to you and every time you launch ngrok. Make sure to read its &lt;a href="https://dashboard.ngrok.com/get-started" rel="noopener noreferrer"&gt;getting started guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have ngrok installed you can run the command &lt;code&gt;ngrok http 300&lt;/code&gt;.&lt;br&gt;
This should give you a URL back. We are going to use it to call our app from the outside.&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%2Fwww.evernote.com%2Fl%2FACUtnS6C0VFJKLTaOVZKDdJGkKcPch-HAy4B%2Fimage.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%2Fwww.evernote.com%2Fl%2FACUtnS6C0VFJKLTaOVZKDdJGkKcPch-HAy4B%2Fimage.png" alt="Screenshot of ngrok"&gt;&lt;/a&gt;&lt;/p&gt;
Screenshot of ngrok



&lt;p&gt;On your Typeform dashboard, we can now select the form we want to connect to Misty, and under &lt;em&gt;Connect &amp;gt; Webhooks&lt;/em&gt; add a new webhook with this URL.&lt;/p&gt;

&lt;p&gt;And voilà 🎉&lt;br&gt;
You now have a robot that raises her arm every time someone fills up your typeform.&lt;/p&gt;

&lt;p&gt;This will work until you kill ngrok or the node app. Ngrok will give you a new URL every time you launch it, so just keep it open while you are developing.&lt;/p&gt;
&lt;h1&gt;
  
  
  Go beyond 🚀
&lt;/h1&gt;

&lt;p&gt;After seeing Misty raising her arm the first time, I could not restrain myself, and I shouted a loud "Woo-hoo" on the conference floor 😊.&lt;/p&gt;

&lt;p&gt;But I could not stop jus now when I was so close to building something even cooler.&lt;/p&gt;

&lt;p&gt;My ultimate goal was to build an app that will make Misty speak and react to the things that were posted on the typeform.&lt;/p&gt;
&lt;h2&gt;
  
  
  Make her arm move dynamically 👋
&lt;/h2&gt;

&lt;p&gt;So I built a &lt;a href="https://picsoung.typeform.com/to/n6NnNI" rel="noopener noreferrer"&gt;simple typeform&lt;/a&gt;, where people could leave their name and decide which arm Misty should raise. &lt;/p&gt;

&lt;p&gt;To make it easier to extract data from typeform webhook payload, I had to update the &lt;code&gt;ref&lt;/code&gt; of my questions. On your typeform select the question and look at the bottom of the sidebar and click &lt;code&gt;Edit&lt;/code&gt;. There you can change it to whatever you please. I called mine &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;arm_choice&lt;/code&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%2Fd1nt04ao0vck22.cloudfront.net%2Fuploads%2F2015%2F07%2F09121737%2Fquestion-settings-2.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%2Fd1nt04ao0vck22.cloudfront.net%2Fuploads%2F2015%2F07%2F09121737%2Fquestion-settings-2.png" alt="screenshot typeform edit ref"&gt;&lt;/a&gt;&lt;/p&gt;
Edit Ref on typeform question



&lt;p&gt;Now let's see how to extract those values from the webhook payload 👇&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;form_response&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form_response&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;arm_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;arm_choice&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;selected_arm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arm_field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;username_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&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;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;username_field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then you can pass &lt;code&gt;select_arm&lt;/code&gt; value to Misty API, and raise the corresponding arm.&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="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ROBOT_IP&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/arms`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
        &lt;span class="na"&gt;Arm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;selected_arm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Velocity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Units&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;degrees&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;h2&gt;
  
  
  Maker her speak 🤖🗣️
&lt;/h2&gt;

&lt;p&gt;Misty REST API lets you send WAV audio files using the &lt;code&gt;SaveAudio&lt;/code&gt; endpoint (&lt;a href="https://docs.mistyrobotics.com/misty-ii/reference/rest/#saveaudio-data-string-" rel="noopener noreferrer"&gt;doc&lt;/a&gt;) but... they have to be encoded in base64 😤&lt;/p&gt;

&lt;p&gt;So I had to find a hack to generate a &lt;code&gt;.wav&lt;/code&gt; file and convert it to base64.&lt;/p&gt;

&lt;p&gt;It took me a couple of trials to find the perfect library to do it, but &lt;a href="https://github.com/Marak/say.js/" rel="noopener noreferrer"&gt;say.js&lt;/a&gt; saved my day!&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;say&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;say&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;say&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`hello_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.wav`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&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;return&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Using those few lines, it creates a &lt;code&gt;.wav&lt;/code&gt; file named &lt;code&gt;hello_${username}.wave&lt;/code&gt; with a voice that says &lt;code&gt;Hello nicolas&lt;/code&gt; for example.&lt;br&gt;
Unfortunately, I could not find the name for the female voices on my mac, so we are stuck with Alex for now 🤷‍♂️&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="nx"&gt;cont&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&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;wav&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WaveFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`hello_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.wav`&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;wav64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;wav&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBase64&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ROBOT_IP&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/audio`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
      &lt;span class="na"&gt;FileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`hello_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.wav`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;wav64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;ImmediatelyApply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//make Misty play it right away&lt;/span&gt;
      &lt;span class="na"&gt;OverwriteExisting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;And this 🔝 is how I read the file, convert it to base64 and call Misty API to make it play on the robot.&lt;/p&gt;

&lt;p&gt;And this how it finally looks 🤩&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1159195895646183424-934" src="https://platform.twitter.com/embed/Tweet.html?id=1159195895646183424"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1159195895646183424-934');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1159195895646183424&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;The code for the entire app is available here👇&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Hope that got you excited to hack things around and play with Misty 🤖.&lt;br&gt;
Their crowdfunding campaign is over, but you can already &lt;a href="https://shop.mistyrobotics.com/" rel="noopener noreferrer"&gt;pre-order&lt;/a&gt; it.&lt;/p&gt;

&lt;p&gt;🙏 Special thanks to Twilio Champions team for inviting me to be part of this great adventure 😃 &lt;/p&gt;

</description>
      <category>robots</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>The self-confidence toolbox for job interviews</title>
      <dc:creator>anabella</dc:creator>
      <pubDate>Tue, 02 Jul 2019 13:09:56 +0000</pubDate>
      <link>https://forem.com/typeform/the-self-confidence-toolbox-for-job-interviews-4k3j</link>
      <guid>https://forem.com/typeform/the-self-confidence-toolbox-for-job-interviews-4k3j</guid>
      <description>&lt;p&gt;One of the biggest challenges I faced when starting my career in software engineering was &lt;strong&gt;applying and interviewing for jobs&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;I went through &lt;em&gt;a ton&lt;/em&gt; of interviewing processes, and for most of them, I was unprepared and under-qualified. In spite of this, I realised that every not-so-good interview helped me improve my "technique" and become more confident.&lt;/p&gt;

&lt;p&gt;Then, about a year ago, I started participating in the other side of interviews, that much more comfortable side of the conversation: interviewing candidates instead of being a candidate myself. This change in perspective allowed me to observe interviewing in more detail (and with less stress) and reflect on all the things that I've learned about it.&lt;/p&gt;

&lt;p&gt;This post describes tactics that helped me reduce stress during those conversations, as well as some mental tools I used to frame the interviewing process and ultimately be more confident about my performance, whatever the outcome.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Getting an interview means you’re already 50% in&lt;/strong&gt; 🌓
&lt;/h4&gt;

&lt;p&gt;I know it doesn't feel like it, but it is often true. A friend of mine used to say this, and I didn't believe him. Years later, I realised that companies only spend time talking to candidates who they already suspect might be a good fit. If they asked you in for an interview, they want to learn more.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;You're also interviewing them&lt;/strong&gt; 👀
&lt;/h4&gt;

&lt;p&gt;Yes, you're being evaluated during an interview. But it’s a two-way street: the interview is also your chance to evaluate the company as a potential employer and learn whether the company and team are a good fit for you. It's important (and empowering) to keep this in mind during the interview–you’re also trying to find out if &lt;strong&gt;you&lt;/strong&gt; want to work there.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Tell your story&lt;/strong&gt; 📜
&lt;/h4&gt;

&lt;p&gt;This is an elevator pitch about yourself, and pitches need a good story. So, how can you describe your experience and objectives in a way that captivates others? Find that story you want to tell, and once you have it, keep working on that narrative to make it engaging. &lt;/p&gt;

&lt;p&gt;You don’t have to recite your resumé by heart. Instead, fill in the gaps between every milestone, from your own human perspective. Think about the most relevant point in time to start from, then pick and choose the events you tell so that they follow a logical, purposeful path. You're not trying to prove anything–instead, focus on making them remember you.&lt;/p&gt;

&lt;p&gt;In my case, my "story" changed every time I was looking for a new job: I would usually explain how each of my previous jobs contributed to my professional growth and what I was looking for next. I found that it would take me a couple of tries before I had my story clear enough in my mind to be able to transmit it to others.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Please don't lie!&lt;/strong&gt; 🤥
&lt;/h4&gt;

&lt;p&gt;Lying will just make you more nervous. I've done it, and it backfired. I still remember that interview as the worst in my life.&lt;/p&gt;

&lt;p&gt;You can, however, frame the truth without lying. For example, instead of saying, &lt;em&gt;"I don't know anything about React..."&lt;/em&gt; you could say, &lt;em&gt;"I've heard about React and its popularity…although I haven't used it yet, I'm curious and would like to give it a try."&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Ask questions&lt;/strong&gt; 🗣
&lt;/h4&gt;

&lt;p&gt;I used to get very nervous when interviewers asked me if I had any questions for them until I understood that I needed to think of some questions in advance and adapt those to the specific context of each conversation.&lt;/p&gt;

&lt;p&gt;So, prepare some questions beforehand. Do a little research about the company and think about what you're looking for in a new job and what you care about (remember, you're also interviewing &lt;em&gt;them&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Think about what you'd like to ask and what you want to communicate with your questions. The interviewer’s answers will give you a deeper understanding of the job and your questions will show them the things you care most about.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Trust them, they know&lt;/strong&gt; 👥
&lt;/h4&gt;

&lt;p&gt;This is one of my favourite tools in the self-confidence toolbox. There may be times when you feel you're not good enough for the job. &lt;em&gt;Ye olde imposter syndrome, right?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well my best tool against this is simply putting my trust in the people doing the interviews: telling myself, &lt;em&gt;"They know."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Why? Because they have a lot more context about the company, the team, and the position, and they're more likely to assess the situation correctly. So if I'm feeling like I might not be up to challenge, I just tell myself: &lt;em&gt;"You don't know that. They do."&lt;/em&gt; Remember my first point: companies spend time with candidates they already think might be a good fit.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;There's no such thing as being too interested&lt;/strong&gt; 🙇🏽‍♀️
&lt;/h4&gt;

&lt;p&gt;It's &lt;strong&gt;totally OK&lt;/strong&gt; to express your interest up front and ask for feedback or updates throughout the process. It's also a great strategy to go the extra mile to demonstrate it. If you really want to land a particular job, ask yourself, &lt;em&gt;"What can I do to stand out from every other candidate?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When I was interviewing for my current job, I decided I would go an extra 2 or 3 miles because I wanted the job &lt;em&gt;so badly.&lt;/em&gt; Before my coding interview I researched the company's APIs and created a suite of acceptance tests for them. I wrote an email to HR, asking if they would be interested in reviewing the project during the upcoming interview. Even if my small project wasn't anything special, they were impressed with my commitment, and I think that played a great part in the outcome.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;It's not you, it's them&lt;/strong&gt; 💔
&lt;/h4&gt;

&lt;p&gt;Rejection is gonna happen…and it's probably not about you. Many factors come into play during a hiring process, and the ones that are not related to you greatly outnumber the ones that are about you specifically. The best you can do is ask for feedback, reflect on what you've learned, and use it to feel more confident in your performance next time.&lt;/p&gt;




&lt;h3&gt;
  
  
  In the end, they want this as much as you do 👯‍♀️
&lt;/h3&gt;

&lt;p&gt;The people interviewing you are spending time getting to know you because they think you might be a great fit. They're not looking to rule you out, but quite the opposite: &lt;em&gt;they want you to succeed&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The hiring process can feel like a series of challenges to overcome to get a prize–challenges that the interviewers want most candidates to fail. This is not the case: they &lt;em&gt;should&lt;/em&gt; want you to succeed and they &lt;em&gt;should&lt;/em&gt; help you get there. But if it feels like the interviewers pressure you and want to see you at your limit, maybe it’s not the best place for you after all.&lt;/p&gt;

&lt;p&gt;Also, if you’re working with a recruiter, remember that it's their job to get a hire. Don't forget to use this to your advantage, let them help you: listen to what they say, as they have a lot of useful insights that can help you perform better.&lt;/p&gt;

&lt;p&gt;I once asked for 2 weeks of preparation for a coding interview, saying that I was a bit rusty with the subject we'd be covering in the test. Truth is I wasn't rusty, I had no experience with the subject at all. During the interview I asked to look at my own study files to recall something and it was &lt;em&gt;fine&lt;/em&gt;. In the end it all went well and I passed the interview.&lt;/p&gt;




&lt;h2&gt;
  
  
  A final note about coding interviews 🖥
&lt;/h2&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%2Fimages.unsplash.com%2Fphoto-1506452819137-0422416856b8%3Fixlib%3Drb-1.2.1%26ixid%3DeyJhcHBfaWQiOjEyMDd9%26auto%3Dformat%26fit%3Dcrop%26w%3D1266%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1506452819137-0422416856b8%3Fixlib%3Drb-1.2.1%26ixid%3DeyJhcHBfaWQiOjEyMDd9%26auto%3Dformat%26fit%3Dcrop%26w%3D1266%26q%3D80" alt="Photo by Kevin Ku on Unsplash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article focuses mostly on the "talking" part of interviews, but I feel there are a couple things left to be said about live coding interviews.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;It’s OK to say "I don't know"&lt;/strong&gt; 🤷‍♀️
&lt;/h4&gt;

&lt;p&gt;There's no shame in saying &lt;em&gt;"I don't know that."&lt;/em&gt; Take it as another opportunity to evaluate them as an employer. They should be able to explain a task or concept to you and give you the opportunity to show how easily you can pick up something new and apply it right away.&lt;/p&gt;

&lt;p&gt;This has happened to me twice, and it turned out to be a great learning experience. On one occasion, I got the chance to ask questions and demonstrate my learning process, and on the other I showed my Googling skills. In the end, I got both jobs!&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;It's not about the code&lt;/strong&gt; 💫
&lt;/h4&gt;

&lt;p&gt;While you're coding or white-boarding, think out loud as much as you can. Coding interviews aren't supposed to be about producing perfect code on the first try. They're about your thought process and your ability to think of solutions, debug problems, and communicate your ideas. Turn it into a conversation.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Easier said than done, right? I agree, but these strategies do make interviewing less stressful. They allow you to step back and approach interviewing not as a stress-filled contest to win a job but as a process that helps both sides evaluate whether the fit is right. Plus, the more you practice, the easier it gets.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have you used anything similar to these tools before? Do you have others? Drop them in the comments!&lt;/em&gt; 😉 &lt;em&gt;I'd love to read them!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>interview</category>
    </item>
    <item>
      <title>BarcelonaJS Meetup May</title>
      <dc:creator>Tiago Pombeiro</dc:creator>
      <pubDate>Wed, 29 May 2019 23:30:34 +0000</pubDate>
      <link>https://forem.com/typeform/barcelonajs-meetup-may-4f95</link>
      <guid>https://forem.com/typeform/barcelonajs-meetup-may-4f95</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xqFWnNMt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/fv811kulbbaap3yovanj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xqFWnNMt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/fv811kulbbaap3yovanj.png" alt="BarcelonaJS Logo" title="BarcelonaJS Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Javascripters from Barcelona and beyond got together once again in one more BarcelonaJs meetup. We had two great speakers:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Jepser Bernardino&lt;/em&gt; &lt;a href="https://twitter.com/jepser?lang=en"&gt;@jepser&lt;/a&gt;&lt;br&gt;
Slides at this &lt;a href="https://drive.google.com/open?id=1y7ZyFIWfjSqWJrsWTE19Vql08xX3L90t"&gt;link&lt;/a&gt;&lt;/p&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The dark side of React, Server Side Rendering

Server Side Rendering is a topic that pops up when taking about SEO or performance improvements for Single Page Applications.

In the React space, with a lot of tools around, which would be the way to go. Let's dive into the space beyond client side rendering, how routing works and data persistence is done with SSR.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;Oriol Torrillas&lt;/em&gt; - &lt;a href="https://twitter.com/otorrillas?lang=en"&gt;@otorrillas&lt;/a&gt;&lt;br&gt;
Slides at this &lt;a href="https://drive.google.com/file/d/11-oCj3MJ9Gr3OZglA-BbAuJ1CmxdUT2h/view?usp=sharing"&gt;link&lt;/a&gt;&lt;/p&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Demystifying design systems

Design systems are sometimes seen as myths. They can play a fundamental role in an organization, but yet we fail to implement them "properly".

In this talk, we will discuss about some patterns, common pitfalls and give practical examples that can help in turning a design system into a success story, for both designers and coders.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here is the link for the event - with more details about the talks:&lt;br&gt;
&lt;a href="https://www.meetup.com/BarcelonaJS/events/261419277/"&gt;https://www.meetup.com/BarcelonaJS/events/261419277/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the recording of the meetup here:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/6v_1kCuvQyA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Here is the direct link: &lt;a href="https://youtu.be/6v_1kCuvQyA"&gt;https://youtu.be/6v_1kCuvQyA&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kudos to both the speakers and &lt;a href="http://www.typeform.com"&gt;Typeform&lt;/a&gt; for hosting this event.&lt;/p&gt;

&lt;p&gt;Follow our next events here: &lt;a href="https://www.meetup.com/BarcelonaJS"&gt;https://www.meetup.com/BarcelonaJS&lt;/a&gt;&lt;/p&gt;

</description>
      <category>barcelonajs</category>
      <category>designsystems</category>
      <category>frontend</category>
      <category>serversiderendering</category>
    </item>
    <item>
      <title>Create a Salesforce lead from Typeform in less than half an hour</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Thu, 14 Mar 2019 19:56:42 +0000</pubDate>
      <link>https://forem.com/typeform/create-a-salesforce-a-lead-from-typeform-in-less-than-half-an-hour-lmg</link>
      <guid>https://forem.com/typeform/create-a-salesforce-a-lead-from-typeform-in-less-than-half-an-hour-lmg</guid>
      <description>&lt;p&gt;At Typeform, we love to use our product to run things. As you may have read in &lt;a href="https://www.typeform.com/blog/inside-story/21-ways-typeform-uses-typeforms/" rel="noopener noreferrer"&gt;a previous post&lt;/a&gt;, we use typeforms to rate our lunches every day, gather feedback about upcoming features, and even run our internal FIFA contest. There are so many ways to use Typeform :)&lt;/p&gt;

&lt;p&gt;We are also heavy Salesforce users: we use it to keep our partner program organized. Companies that are interested in integrating with Typeform contact us via this partner &lt;a href=""&gt;form&lt;/a&gt;, but then nothing happens. If we believe a lead could produce an interesting conversation, we have to create the lead &lt;em&gt;manually&lt;/em&gt; in Salesforce.&lt;/p&gt;

&lt;p&gt;I can hear developer folks out there saying, “There should be a better way!” 🤔&lt;/p&gt;

&lt;p&gt;You’re right! We should be able to enjoy both by using the engaging Typeform UI to collect data and the powerful Salesforce funnel to organize the data into leads.&lt;/p&gt;

&lt;p&gt;And this is what I’m going to explain here. I connected our typeform to our Salesforce organization and saved our team precious time.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites 🛒
&lt;/h1&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://www.salesforce.com/" rel="noopener noreferrer"&gt;Salesforce&lt;/a&gt; organization&lt;/li&gt;
&lt;li&gt;A Typeform account--&lt;a href="https://www.typeform.com/" rel="noopener noreferrer"&gt;create one for free&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A half hour of free time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Buckle up and let's get started! 🛫&lt;/p&gt;

&lt;h1&gt;
  
  
  Principles 📖
&lt;/h1&gt;

&lt;p&gt;This hack relies on Typeform webhooks. You can attach one or more webhooks to a Typeform so that when a new response is submitted, you are notified at the URL of your choice.&lt;/p&gt;

&lt;p&gt;Webhooks happen in real time, so they allow you to react quickly and keep everything in sync.&lt;/p&gt;

&lt;p&gt;On the Salesforce side, we will rely on their &lt;a href="https://www.salesforce.com/products/guide/lead-gen/web-to-lead/" rel="noopener noreferrer"&gt;Web-to-Lead&lt;/a&gt; solution. It's a quick way to generate leads from a web form.&lt;/p&gt;

&lt;p&gt;To receive webhook details from Typeform and send them to Salesforce, we use &lt;a href="http://glitch.com" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt;. &lt;a href="http://glitch.com" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt; is both an online IDE and a server. The app is deployed automatically, so there’s no need to worry about servers.&lt;/p&gt;

&lt;p&gt;You can also use other serverless solutions like &lt;a href="https://aws.amazon.com/lambda" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;, &lt;a href="https://cloud.google.com/functions/" rel="noopener noreferrer"&gt;Google Cloud functions&lt;/a&gt;, &lt;a href="https://azure.microsoft.com/en-us/services/functions" rel="noopener noreferrer"&gt;Azure&lt;/a&gt;, and &lt;a href="https://stdlib.com" rel="noopener noreferrer"&gt;Stdlib&lt;/a&gt;. Your choice! 😉&lt;/p&gt;

&lt;h1&gt;
  
  
  Implement the solution 👩‍💻
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Prepare the typeform
&lt;/h2&gt;

&lt;p&gt;Our typeform contains all of the questions we want to ask. Each question is identified by both an &lt;code&gt;id&lt;/code&gt; and a &lt;code&gt;ref&lt;/code&gt; property. Both are unique and automatically generated, but the &lt;code&gt;id&lt;/code&gt; value can't be changed. &lt;a href="https://gist.github.com/picsoung/1b2665b6083876c949bdf6fe09d1ed7d" rel="noopener noreferrer"&gt;Example of form definition&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%2Fwww.evernote.com%2Fl%2FACVug-zrn3ZNGJd2rtG7SxpwUtYs8_C-RXYB%2Fimage.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%2Fwww.evernote.com%2Fl%2FACVug-zrn3ZNGJd2rtG7SxpwUtYs8_C-RXYB%2Fimage.png" alt="details of field definition"&gt;&lt;/a&gt;&lt;/p&gt;
details of field definition



&lt;p&gt;We &lt;em&gt;can&lt;/em&gt; update the &lt;code&gt;ref&lt;/code&gt; values to make the code more readable. I’ll use the &lt;a href="https://tf-edit-ref.glitch.me" rel="noopener noreferrer"&gt;Typeform Edit Block Ref app&lt;/a&gt; to modify the &lt;code&gt;ref&lt;/code&gt; properties of fields in our typeform.&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%2Fwww.evernote.com%2Fl%2FACVnWFu2hplJMpEK3nRSwVGc0jPT0YDDZiIB%2Fimage.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%2Fwww.evernote.com%2Fl%2FACVnWFu2hplJMpEK3nRSwVGc0jPT0YDDZiIB%2Fimage.png" alt="screenshot of edit ref app"&gt;&lt;/a&gt;&lt;/p&gt;
screenshot of edit ref app



&lt;p&gt;Now the questions have &lt;code&gt;ref&lt;/code&gt; values like &lt;code&gt;first_name&lt;/code&gt;, &lt;code&gt;last_name&lt;/code&gt; instead of random characters. 👍&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%2Fwww.evernote.com%2Fl%2FACUecZQAfoNOQrgagEGrSU5epgSh9qRG4BYB%2Fimage.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%2Fwww.evernote.com%2Fl%2FACUecZQAfoNOQrgagEGrSU5epgSh9qRG4BYB%2Fimage.png" alt="After edit result"&gt;&lt;/a&gt;&lt;/p&gt;
Looks better, no? 😉



&lt;h2&gt;
  
  
  Get your Salesforce organization ID 🗄️
&lt;/h2&gt;

&lt;p&gt;To send leads to our Salesforce organization, I need to identify it by passing our &lt;code&gt;oid&lt;/code&gt; (organization ID) as a parameter. &lt;/p&gt;

&lt;p&gt;You can find the &lt;code&gt;OID&lt;/code&gt; in your Salesforce dashboard. Click on the ⚙️ icon, and you should find it under &lt;em&gt;Settings&lt;/em&gt; in the &lt;code&gt;Company Information&lt;/code&gt; section.&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%2Fwww.evernote.com%2Fl%2FACUtchZh8oZF7pDNQ3Oa3guTw9_HdNisZRYB%2Fimage.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%2Fwww.evernote.com%2Fl%2FACUtchZh8oZF7pDNQ3Oa3guTw9_HdNisZRYB%2Fimage.png" alt="sc"&gt;&lt;/a&gt;&lt;/p&gt;
Where to find your Salesforce OID



&lt;p&gt;Keep the &lt;code&gt;OID&lt;/code&gt; handy! You will need it later. 😉&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's code 🎉
&lt;/h3&gt;

&lt;p&gt;I knew you wanted to get to this part as soon as possible! So let's get our hands dirty. 😈&lt;/p&gt;

&lt;p&gt;As I said earlier, our function will extract details from the Typeform webhook payload and then call the Salesforce API to create a lead.&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/hook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// let's answer back quickly to typeform 👌&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;form_response&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form_response&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;received from Typeform webhook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;form_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// build the lead object&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lead_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;first_name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;last_name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;company&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;company&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;// salesforce debug mode&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;As you can see in this snippet, you’ll create a &lt;code&gt;/hook&lt;/code&gt; route, excepting a &lt;code&gt;POST&lt;/code&gt; request. Then, you’ll process the incoming request and extract the relevant data to build the &lt;code&gt;lead_data&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;For security reasons, don't store the &lt;code&gt;OID&lt;/code&gt; value directly in the code. Instead, store it as an environment variable.&lt;/p&gt;

&lt;p&gt;I also added a debug parameter so you can test it out without harming your real organization.&lt;/p&gt;

&lt;p&gt;The only thing left to do is to call the Salesforce Web-to-Lead API and create a lead.&lt;/p&gt;

&lt;p&gt;This is the missing piece to add:&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="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://webto.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;qs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lead_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/x-www-form-urlencoded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;res&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;err&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;err&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;That's all you need to connect things together. 🎊&lt;/p&gt;
&lt;h1&gt;
  
  
  Try it live
&lt;/h1&gt;

&lt;p&gt;To quickly try this integration, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://glitch.com/~tf-webtolead" rel="noopener noreferrer"&gt;Remix the project&lt;/a&gt; on Glitch&lt;/li&gt;
&lt;li&gt;Add your own &lt;code&gt;OID&lt;/code&gt; to the &lt;code&gt;.env&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Remove, add, or modify data extraction from the Typeform webhook payload in lines 21-28 in &lt;code&gt;server.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Show&lt;/code&gt; to see the URL of your project hosted on Glitch (and keep it for the next step)&lt;/li&gt;
&lt;li&gt;In Typeform, select your lead generation typeform and add your Glitch app URL under &lt;code&gt;Connect &amp;gt; Webhooks&lt;/code&gt; 
The URL format should be &lt;code&gt;https://{random_name}.glitch.me/hook&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Test by filling in and submitting your lead generation typeform--after you submit it, you should see a new lead in your Salesforce organization&lt;/li&gt;
&lt;li&gt;Celebrate! 🎉&lt;/li&gt;
&lt;/ol&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%2Fwww.evernote.com%2Fl%2FACXSHV_zi6VJp4bDmEO8MFpF6iSZjVyUTrQB%2Fimage.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%2Fwww.evernote.com%2Fl%2FACXSHV_zi6VJp4bDmEO8MFpF6iSZjVyUTrQB%2Fimage.png" alt="new lead in Salesforce"&gt;&lt;/a&gt;&lt;/p&gt;
Succesfully created a lead in Salesforce




&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/tf-webtolead?path=index.html" alt="tf-webtolead on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;



&lt;h1&gt;
  
  
  Go beyond 🗺️
&lt;/h1&gt;

&lt;p&gt;This is a simple hack to connect Typeform and Salesforce. To make it more complete, you can map more fields from your lead object to your typeform questions. It even works with custom Salesforce fields.&lt;/p&gt;

&lt;p&gt;If you are curious about connecting Typeform with other services, check out our &lt;a href="https://developer.typeform.com" rel="noopener noreferrer"&gt;developer documentation&lt;/a&gt; and build your own solution! 😉&lt;/p&gt;

&lt;p&gt;To stay updated about projects like this one, subscribe to our &lt;a href="https://developerplatform.typeform.com/to/DlIzNU" rel="noopener noreferrer"&gt;Developer Newsletter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>salesforce</category>
    </item>
    <item>
      <title>A whole new world to explore</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Thu, 07 Feb 2019 01:51:00 +0000</pubDate>
      <link>https://forem.com/typeform/a-whole-new-world-to-explore-590a</link>
      <guid>https://forem.com/typeform/a-whole-new-world-to-explore-590a</guid>
      <description>&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2Apr62nI63tWcvQNzo" 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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2Apr62nI63tWcvQNzo"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@serjosoza?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;sergio souza&lt;/a&gt; on &lt;a href="https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In 2018 the Typeform crew had the pleasure to meet some of you at conferences like Nordic APIs, or JS Heroes, or hackathons like HackUPC in Barcelona, or Hackference in Birmingham. It’s always great to meet users and partners at those events. You help us build the future of Typeform and its platform 🤩&lt;/p&gt;

&lt;p&gt;I can tell you that for 2019, from where we are we have a new fantastic point of view, the head full of ideas and no one to tell us no. A hundred thousand things to see and as many dazzling places we never knew we wanted to visit…&lt;/p&gt;

&lt;p&gt;The only thing that’s crystal clear is that now we are in a whole new world with you, our beloved Developer Community!&lt;/p&gt;

&lt;p&gt;So let’s get this year started, hop on this magic carpet ride together, and let’s check out our next destinations.&lt;/p&gt;

&lt;p&gt;We will begin our adventure by going to Boulder for a few events:&lt;/p&gt;

&lt;h4&gt;
  
  
  🇺🇸 BoulderJS meetup, Boulder
&lt;/h4&gt;

&lt;p&gt;20th February 2019&lt;/p&gt;

&lt;p&gt;For the first step of our Boulder trip, we will stop by BoulderJS meetup, meeting the local Javascript community.&lt;/p&gt;

&lt;p&gt;I will be sharing my experience building my first app using Vue.js, when I created &lt;a href="https://%F0%9F%8C%9A%F0%9F%8C%9E.ws" rel="noopener noreferrer"&gt;https://🌚🌞.ws&lt;/a&gt; to track events for the 2018 Solar Eclipse.&lt;/p&gt;

&lt;p&gt;🎟️ &lt;a href="https://www.meetup.com/Boulder-JS/events/xmkdvmyzdbbc/" rel="noopener noreferrer"&gt;Register&lt;/a&gt; (FREE)&lt;/p&gt;

&lt;h4&gt;
  
  
  🇺🇸WriteTheDocs Boulder
&lt;/h4&gt;

&lt;p&gt;21st February 2019&lt;/p&gt;

&lt;p&gt;WriteTheDoc is a global community of tech writers. Last year we participated in their sister events API the docs in Paris and London. It’s a great pleasure to be welcomed by the Boulder local group to exchange about documentation and Developer Experience best practices.&lt;/p&gt;

&lt;p&gt;I will be presenting about best practices on Developer Experience on Webhooks.&lt;/p&gt;

&lt;p&gt;🎟️ &lt;a href="https://www.meetup.com/Write-the-Docs-Boulder-Denver/" rel="noopener noreferrer"&gt;Register&lt;/a&gt; (FREE)&lt;/p&gt;

&lt;h4&gt;
  
  
  🇺🇸Typeform Office Hours
&lt;/h4&gt;

&lt;p&gt;While we will be in Boulder, we thought we wanted to meet our lovely users. That’s why we are organizing some Office Hours on Thursday 21st and Friday 22nd.&lt;br&gt;&lt;br&gt;
It’s your opportunity to come meet us and come with your questions about Typeform product.&lt;br&gt;&lt;br&gt;
We will be here to assist you, especially if you are interested to build things using our APIs.&lt;/p&gt;

&lt;p&gt;🎟 ️&lt;a href="https://developerplatform.typeform.com/to/azugOg" rel="noopener noreferrer"&gt;Signup here&lt;/a&gt; (FREE)&lt;/p&gt;

&lt;h4&gt;
  
  
  🇺🇸HackCU, Boulder
&lt;/h4&gt;

&lt;p&gt;23–24th February&lt;/p&gt;

&lt;p&gt;We don’t sponsor a lot of student hackathons but when we do, but do it’s because we have a special connection with their team. We are delighted to visit Gerard Sans founder of HackUPC and now a master student at CU-Boulder and Shubha Sharma, our summer intern in senior year in the same university. They are part of the outstanding team organizing HackCU.&lt;/p&gt;

&lt;p&gt;Can’t wait to see what hackers will build!&lt;/p&gt;

&lt;h4&gt;
  
  
  🇪🇸API Meetup BCN, Barcelona
&lt;/h4&gt;

&lt;p&gt;28th February&lt;/p&gt;

&lt;p&gt;It now has been more than 10 years that Barcelona has been selected to be the &lt;em&gt;Mobile Capital of the World&lt;/em&gt; for a week every year. During a week more than 100 thousand people will come from all over the world to discuss the newest trends in technology.&lt;/p&gt;

&lt;p&gt;Taking the opportunity of all those folks coming to Barcelona, the local API meetup is hosting their annual MWC meetup and we are excited to host it in our HQ! Join us for a night of API nerding! 🤓&lt;/p&gt;

&lt;p&gt;🎟️ &lt;a href="https://www.meetup.com/API-Meetup-Barcelona/events/258461375/" rel="noopener noreferrer"&gt;Register&lt;/a&gt; (FREE)&lt;/p&gt;

&lt;h4&gt;
  
  
  🇪🇸Women Techmakers, Barcelona
&lt;/h4&gt;

&lt;p&gt;6th April&lt;/p&gt;

&lt;p&gt;You still have a bit of time to get ready, but we are beyond excited to be part of the second edition of the Women Techmarkers conference in Barcelona.&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://womentechmakersbcn.github.io" rel="noopener noreferrer"&gt;Learn more&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I really hope you have a chance to catch us at one of those events! Remember, if you are organizing a meetup, a conference, a hackathon or an AI-powered ostrich race, and you want someone from Typeform to show up, let us know by filling the &lt;a href="https://picsoung.typeform.com/to/QXS2h1?source=dev_to_eventsq1" rel="noopener noreferrer"&gt;this typeform&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>hackathons</category>
      <category>conference</category>
      <category>developeradvocacy</category>
      <category>barcelona</category>
    </item>
  </channel>
</rss>
