<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vic</title>
    <description>The latest articles on DEV Community by Vic (@victorio).</description>
    <link>https://dev.to/victorio</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F788821%2Ff0d4463c-f102-4180-a515-38ba5c2c8f40.png</url>
      <title>DEV Community: Vic</title>
      <link>https://dev.to/victorio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/victorio"/>
    <language>en</language>
    <item>
      <title>Exploiting Slack’s video embeds to achieve e2ee communication</title>
      <dc:creator>Vic</dc:creator>
      <pubDate>Sun, 21 Jun 2026 04:56:06 +0000</pubDate>
      <link>https://dev.to/victorio/exploiting-slacks-video-embeds-to-achieve-e2ee-communication-52kb</link>
      <guid>https://dev.to/victorio/exploiting-slacks-video-embeds-to-achieve-e2ee-communication-52kb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Some time ago, while exploring Slack’s Block Kit reference, I noticed something peculiar: the &lt;a href="https://docs.slack.dev/reference/block-kit/blocks/video-block/" rel="noopener noreferrer"&gt;video block&lt;/a&gt;. When I saw that it accepted a &lt;code&gt;video_url&lt;/code&gt;, the first thing I thought was: how does it distinguish between any content and an actual video? Would there be any particular requirement or limitation in the embed? Foreign sources? &lt;/p&gt;

&lt;p&gt;Yeah, no. There is no runtime check, other than checking the provided video_url is accessible and responds with a 2xx or 3xx code. After those checks, it’s nothing more than a simple iframe.&lt;/p&gt;

&lt;p&gt;So, a few days ago I got an idea. What if there was an app that allowed you to encrypt messages with a key pair and send them through Slack?&lt;/p&gt;

&lt;p&gt;The idea is simple. Inside your client, using the browser crypto APIs, you create a key pair, encrypt the private key and send it to the server. Then, any time you want to do an operation (sign, encrypt, decrypt), the server will send you back your key and, inside a video block, you will decrypt your key and do the operation.&lt;/p&gt;

&lt;p&gt;This way, the server never gets the decrypted key but via the key-pairs, you can encrypt messages for anyone. &lt;/p&gt;

&lt;p&gt;This way, the server never gets the decrypted key but via the key-pairs, you can encrypt messages for anyone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fv1c.rocks%2Fassets%2Fe2ees-send.avif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fv1c.rocks%2Fassets%2Fe2ees-send.avif" alt="showcase of the registration process for e2ee Slack" width="800" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;For this app’s development I chose TypeScript. For no other reason than that I’m used to it and I’m able to iterate fast with it. &lt;/p&gt;

&lt;p&gt;During the implementation of the Slack app, I spent a decent amount of time until realizing that video blocks can not be included in ephemeral messages. This behavior is not documented anywhere.&lt;/p&gt;

&lt;p&gt;Regarding the encryption, first, I tried writing all the encryption logic myself. Using the subtle crypto API from the browser (which is fully available in the Slack video block).&lt;br&gt;
Shortly I noticed how difficult that was. How many techniques and cases I would need to be aware of. &lt;/p&gt;

&lt;p&gt;Fortunately, before suffering more, I found &lt;a href="https://openpgpjs.org/" rel="noopener noreferrer"&gt;openpgpjs&lt;/a&gt;. An amazing library maintained by Proton (yes, the email people) that does all the cryptography operations I need.&lt;/p&gt;

&lt;p&gt;I wanted the server to save as little data as possible by storing most of the data in slack metadata fields. I have already done this for other Slack bots.&lt;br&gt;
All the slack messages or views may store a metadata field which is never shown in the client. But, because of the length of encrypted messages, I wasn't able to use this feature.&lt;/p&gt;

&lt;p&gt;For serving the iframes, I ended up using a &lt;em&gt;slug&lt;/em&gt; system. On each call that needs client interaction, a unique slug which holds the necessary data for the action to be done is stored in a KV db.&lt;br&gt;
When the video embed is loaded, this information is embedded with the iframe client code so all cryptographic operations can be done locally.&lt;/p&gt;

&lt;p&gt;As an example, the flow for encrypting a message is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, the Slack command &lt;code&gt;/e2ee send&lt;/code&gt; is executed. A Slack modal opens, requesting the recipients of the message.&lt;/li&gt;
&lt;li&gt;After that modal is submitted, a &lt;em&gt;slug&lt;/em&gt; is generated, containing: the author private key &amp;amp; the recipients public key.&lt;/li&gt;
&lt;li&gt;When clicking on the video block inside Slack, the local-client is loaded with the above information.&lt;/li&gt;
&lt;li&gt;The author decrypts their private key via his passphrase (locally).&lt;/li&gt;
&lt;li&gt;The author writes the message, encrypts it for the recipients and signs it with his key (locally).&lt;/li&gt;
&lt;li&gt;The author sends &lt;em&gt;only&lt;/em&gt; the encrypted message.&lt;/li&gt;
&lt;li&gt;The server sends &lt;strong&gt;envelopes&lt;/strong&gt; to each one of the recipients of the message.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the way, while developing this project, I discovered some of the wonders modern nodejs has to offer. Did you know node natively &lt;a href="https://nodejs.org/api/environment_variables.html#dotenv" rel="noopener noreferrer"&gt;supports .env files&lt;/a&gt; now? I didn’t!&lt;/p&gt;

&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;You can check out the project right now, the source is at &lt;a href="https://github.com/v1ctorio/e2ee-slack" rel="noopener noreferrer"&gt;gh:v1ctorio/e2ee-slack&lt;/a&gt;, and self-host it for your Slack workspace&lt;br&gt;
in ~5 minutes.&lt;/p&gt;




&lt;p&gt;This project ends up being a hack since it doesn’t fully comply with Slack’s &lt;a href="https://docs.slack.dev/reference/block-kit/blocks/video-block/#constraints" rel="noopener noreferrer"&gt;design constraints&lt;/a&gt;. But it kept me wondering.&lt;br&gt;
With all the flexibility that web technologies give us, wouldn’t it be nice if major services supported fully-featured apps inside their client?&lt;/p&gt;

&lt;p&gt;I mean, Discord already does something similar with &lt;a href="https://docs.discord.com/developers/activities/overview" rel="noopener noreferrer"&gt;'Activities'&lt;/a&gt;&lt;br&gt;
 or Telegram with &lt;a href="https://core.telegram.org/bots/webapps" rel="noopener noreferrer"&gt;'Mini Apps'&lt;/a&gt;. Wouldn’t it be interesting to see more mainstream services adopt this approach?&lt;/p&gt;

</description>
      <category>programming</category>
      <category>automation</category>
      <category>discuss</category>
      <category>software</category>
    </item>
    <item>
      <title>In case you are not aware of the Anthropic situation</title>
      <dc:creator>Vic</dc:creator>
      <pubDate>Sat, 28 Feb 2026 00:26:01 +0000</pubDate>
      <link>https://dev.to/victorio/in-case-you-are-not-aware-of-the-anthropic-situation-40i1</link>
      <guid>https://dev.to/victorio/in-case-you-are-not-aware-of-the-anthropic-situation-40i1</guid>
      <description>&lt;h3&gt;
  
  
  The Anthropic statement
&lt;/h3&gt;

&lt;p&gt;At 2026-02-26 21:55 UTC, Anthropic releases a &lt;a href="https://www.anthropic.com/news/statement-department-of-war" rel="noopener noreferrer"&gt;public statement&lt;/a&gt; in which they speak out regarding the demands of the US Department Of War.&lt;/p&gt;

&lt;p&gt;In said statement, they explicitly address two concrete use cases in which they deny to provide their technology:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mass domestic surveillance&lt;/strong&gt;. They don't want their products being using to patrol USA citizens and acknowledge that their services could be used to easily arbitrarily profile any citizens data without the need of a warrant.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fully autonomous weapons&lt;/strong&gt;. Anthropic acknowledges the utility of partial &lt;em&gt;and&lt;/em&gt; fully autonomous weapons in the military, but they affirm that the guardrails present in their technology are not enough to assure the safety of american warfighters and civilians.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The open letter
&lt;/h3&gt;

&lt;p&gt;The same day, the &lt;a href="https://notdivided.org/" rel="noopener noreferrer"&gt;"We Will Not Be Divided"&lt;/a&gt; open letter is made public. In it, hundreds of Google and OpenAI employees declare their support to Anthropic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Response from the US
&lt;/h3&gt;

&lt;p&gt;On the next day, 27, the White House twitter account and Donald Trump (POTUS) make &lt;a href="https://xcancel.com/WhiteHouse/status/2027497719678255148" rel="noopener noreferrer"&gt;a post&lt;/a&gt; directing all USA federal agencies to stop using Anthropic's product in a six month period and threaten Anthropic with "major civil and criminal consequences" if they are not supportive during the transition period.&lt;/p&gt;

&lt;p&gt;The same day, at 22:14 UTC, Pete Hegseth (US Secretary of War) makes &lt;a href="https://xcancel.com/SecWar/status/2027507717469049070" rel="noopener noreferrer"&gt;a post&lt;/a&gt; calling out Anthropic for trying to "veto power over the operational decisions of the United States military" and designates Anthropic as a Supply-Chain Risk to National Security.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>news</category>
      <category>privacy</category>
    </item>
    <item>
      <title>Fumo dashboard</title>
      <dc:creator>Vic</dc:creator>
      <pubDate>Thu, 20 Jul 2023 15:27:33 +0000</pubDate>
      <link>https://dev.to/victorio/fumo-dashboard-c8a</link>
      <guid>https://dev.to/victorio/fumo-dashboard-c8a</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;A dashboard to manage the &lt;a href="https://github.com/nosesisaid/fumo-api"&gt;Fumo-API&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;p&gt;Most Visually Pleasing&lt;/p&gt;

&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://test-fumo-dashboard.nosesisaid.com"&gt;https://test-fumo-dashboard.nosesisaid.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://fumo-mock-api.vicotrio.repl.co"&gt;https://fumo-mock-api.vicotrio.repl.co&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KvfVKhW6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0pjotrocvb14kg2owzyk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KvfVKhW6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0pjotrocvb14kg2owzyk.png" alt="" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y4aRqNet--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wzokbe71mslrfydm1dz7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y4aRqNet--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wzokbe71mslrfydm1dz7.png" alt="" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4eZ9rm6I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwmiw3ylqxq1nqhqt3ux.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4eZ9rm6I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwmiw3ylqxq1nqhqt3ux.png" alt="" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4gx15Wgv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/345jen1no4n0pyefyfvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4gx15Wgv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/345jen1no4n0pyefyfvq.png" alt="" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/v1ctorio/fumos-mui-dashboard"&gt;https://github.com/v1ctorio/fumos-mui-dashboard&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;p&gt;MIT&lt;/p&gt;

&lt;h2&gt;
  
  
  Background (What made you decide to build this particular app? What inspired you?)
&lt;/h2&gt;

&lt;p&gt;I've had the Fumo-API for a long time and thought about making a dashboard so I can manage the fumos better, Refine helped me to make this process easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it (How did you utilize refine? Did you learn something new along the way? Pick up a new skill?)
&lt;/h3&gt;

&lt;p&gt;I used the create-refine-app CLI and the Inferencer feature, which I find very interesting and think I'll use in future projects&lt;/p&gt;

</description>
      <category>refinehackathon</category>
    </item>
    <item>
      <title>How to host RAW images for free</title>
      <dc:creator>Vic</dc:creator>
      <pubDate>Tue, 07 Jun 2022 17:39:56 +0000</pubDate>
      <link>https://dev.to/victorio/how-to-host-raw-images-for-free-1gea</link>
      <guid>https://dev.to/victorio/how-to-host-raw-images-for-free-1gea</guid>
      <description>&lt;p&gt;Hours ago I was searching for a way to host "raw" (with raw I mean an endpoint that returns an image) and most of them like azure blob storage are paid so I searched for free alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a new repo&lt;/li&gt;
&lt;li&gt;Upload files&lt;/li&gt;
&lt;li&gt;Drag your image&lt;/li&gt;
&lt;li&gt;On the image page, right-click it and click 'copy image link'
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LuaO41fS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eod9uoe14ck9pk2gx1ap.gif" alt="Example" width="800" height="374"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Telegra.ph
&lt;/h2&gt;

&lt;p&gt;To host the images in the telegram server&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to telegra.ph&lt;/li&gt;
&lt;li&gt;Click on the camera icon and choose your image &lt;/li&gt;
&lt;li&gt;Right-click the image and 'copy image link'
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EjZv-Zb3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rhc28a56g2gy0r6x6hiv.gif" alt="Example" width="800" height="374"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You also can use the API using for example &lt;a href="https://www.npmjs.com/package/telegraph-uploader"&gt;telegram-uploader&lt;/a&gt;.&lt;br&gt;
Here's a snippet of how to use it&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;uploadByBuffer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;telegraph-uploader&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;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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="nx"&gt;uploadByBuffer&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="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./image.png&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;image/png&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;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&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;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;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="cm"&gt;/* {
         link: 'https://telegra.ph/file/...',
         path: '/file/...',
       } */&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sirv.com
&lt;/h2&gt;

&lt;p&gt;It's a more advanced hosting, it provides benefits like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom domain&lt;/li&gt;
&lt;li&gt;Folders&lt;/li&gt;
&lt;li&gt;Custom name&lt;/li&gt;
&lt;li&gt;Custom endpoint
but also as it is a professional option it have limitations for the free plan, for example it only allow you to host 500mb for free and have a bandwidth of 2GB.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading :) &lt;/p&gt;

</description>
      <category>beginners</category>
    </item>
    <item>
      <title>The day snippet</title>
      <dc:creator>Vic</dc:creator>
      <pubDate>Mon, 06 Jun 2022 17:28:04 +0000</pubDate>
      <link>https://dev.to/victorio/the-day-snippet-2goc</link>
      <guid>https://dev.to/victorio/the-day-snippet-2goc</guid>
      <description>&lt;p&gt;Share here the code snippet to solve the weird error that you thought no one had had ever or the weird utility which you didn't even know that existed in that programming language or library.&lt;/p&gt;

&lt;p&gt;Mine is &lt;a href="https://split.js.org/"&gt;https://split.js.org/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Creating your own URL shortener</title>
      <dc:creator>Vic</dc:creator>
      <pubDate>Tue, 31 May 2022 16:30:02 +0000</pubDate>
      <link>https://dev.to/victorio/creating-your-own-url-shortener-4k2n</link>
      <guid>https://dev.to/victorio/creating-your-own-url-shortener-4k2n</guid>
      <description>&lt;p&gt;This is a kind of half-blog half-tutorial of how to create your URL shortener using Redis, go &amp;amp; GitHub copilot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I was searching for a URL shortener service for my domain, there are a lot like bit.ly, short.io, cutt.ly...  but most of them are paid or have a lot of limitations like the number of URLs. &lt;br&gt;
So I decided to create my own, to start the project I had to know &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Which language I'll use&lt;/li&gt;
&lt;li&gt;How do I'm going to store the data
For the first one, I decided to use Go. Why? Why not? It's a programming language so it works.
For the second one I decided to use MongoDB but this will change shortly.
Don't focus on that yet and start coding!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Setting up the workspace
&lt;/h2&gt;

&lt;p&gt;You can download the go cli &lt;a href="https://go.dev/dl/"&gt;here&lt;/a&gt; but I'm more based than you 😎 so GitHub gave me the Codespaces beta&lt;br&gt;
if you're based like me go to repo.new and create a new repo, make sure to check this box&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--64RbecPb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9xhsb2dxz2cw11cgnezz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--64RbecPb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9xhsb2dxz2cw11cgnezz.png" alt="Initialize this repository with Readme" width="533" height="99"&gt;&lt;/a&gt; if you want to use Codespaces, after creating the repo click here to create a Codespace &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZjpeU5nh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/azk8qemyofsaiclvix6k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZjpeU5nh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/azk8qemyofsaiclvix6k.png" alt="Create codespace on master" width="366" height="409"&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To init your project run the next command &lt;code&gt;go mod init shortener&lt;/code&gt;, this will create a &lt;code&gt;go.mod&lt;/code&gt;. Something like a &lt;code&gt;package.json&lt;/code&gt; in node or a &lt;code&gt;Gemfile&lt;/code&gt; in rust. &lt;/p&gt;
&lt;h2&gt;
  
  
  Start coding
&lt;/h2&gt;

&lt;p&gt;Now start coding!&lt;/p&gt;

&lt;p&gt;Paste the next code into the &lt;code&gt;main.go&lt;/code&gt; 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;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hello&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;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;hello&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;w&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="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a http server in the port &lt;code&gt;8080&lt;/code&gt; and reply to the endpoint &lt;code&gt;/hello&lt;/code&gt; with &lt;code&gt;Hello World!&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redirecting
&lt;/h3&gt;

&lt;p&gt;What a URL shortener does? redirecting the user to another URL.&lt;/p&gt;

&lt;p&gt;To do this we will use the next line of code&lt;br&gt;
&lt;code&gt;http.Redirect(w, r, URL, http.StatusFound)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Implementing this to our last code look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HandleReq&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;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;HandleReq&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Redirect&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;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://www.google.com"&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;StatusFound&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;h3&gt;
  
  
  Reding the url
&lt;/h3&gt;

&lt;p&gt;To read the url we will use the next line of code&lt;br&gt;
    &lt;code&gt;r.URL.Path[len("/"):]&lt;/code&gt;.&lt;br&gt;
Implementing this to our last code look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HandleReq&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;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;HandleReq&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;key&lt;/span&gt; &lt;span class="o"&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;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Redirect&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;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://www.google.com"&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;StatusFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&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;h3&gt;
  
  
  Implementing the database
&lt;/h3&gt;

&lt;p&gt;Now that we know how to read the url and redirecting we implement the database.&lt;/p&gt;

&lt;p&gt;To do this I thought that using MongoDb is a good idea. Let me save you that suffering, &lt;strong&gt;do not use mongo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For this, we will use Redis instead&lt;/p&gt;

&lt;h4&gt;
  
  
  Hosting the database
&lt;/h4&gt;

&lt;p&gt;Do you know how to host a redis database? I do not&lt;br&gt;
So for this, I'll use Railway, it lets you create a database in seconds, just go to &lt;a href="https://railway.app/new"&gt;https://railway.app/new&lt;/a&gt; &amp;amp; click &lt;code&gt;Provision redis&lt;/code&gt;, then click on &lt;code&gt;Redis&lt;/code&gt; -&amp;gt; &lt;code&gt;Connect&lt;/code&gt; &lt;br&gt;
There will be a URL like this &lt;code&gt;redis://default:password@host&lt;/code&gt;, store this data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;ℹ This tutorial doesn't cover how to create URLs programmatically **yet&lt;/em&gt;* so for creating URLs go to &lt;code&gt;data&lt;/code&gt; and create keys with the value of the URL where you want to redirect.*&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Connecting to the database
&lt;/h4&gt;

&lt;p&gt;For this we will use &lt;a href="//github.com/go-redis/redis/v8"&gt;&lt;code&gt;go-redis&lt;/code&gt;&lt;/a&gt;, to install it run &lt;code&gt;github.com/go-redis/redis/v8&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To create the client we will use the next code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&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;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="o"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For getting data from the database we will use the next code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;value&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;db&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="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Implementing this to our last code look like this:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/go-redis/redis"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;//This define db and context, why? In go if you want to make a global variable you need to define it outside the main function.&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;
&lt;span class="k"&gt;var&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;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;DataBase&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;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requestHandler&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;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;port&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Server started on port:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&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;DataBase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&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;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="o"&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Connected to Database"&lt;/span&gt;&lt;span class="p"&gt;)&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;requestHandler&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;//This get the key from the URL by wathing the url path and removing the `/`&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&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;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&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="c"&gt;//this checks if the key is empty, if it's, return 404&lt;/span&gt;
    &lt;span class="k"&gt;if&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;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"/"&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;Error&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="s"&gt;"Not Found"&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;StatusNotFound&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;//this gets the value from the database&lt;/span&gt;
    &lt;span class="n"&gt;value&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;db&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="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;//Go is kind of weir so if you want to know if there's a error you need to check if the value error value is not nil(null)&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="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;//check if there is no URl for the key, if it's true, return 404&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&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="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Not Found"&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;StatusNotFound&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="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Redirect&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;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&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;StatusFound&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 it!&lt;br&gt;
Now we have a completely functional URL shortener!&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post, if you have any questions or suggestions &lt;del&gt;feel free to&lt;/del&gt; PLEASE comment.&lt;/p&gt;

</description>
      <category>go</category>
      <category>showdev</category>
      <category>tutorial</category>
      <category>githubcopilot</category>
    </item>
  </channel>
</rss>
