<?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: Jordan Tingling</title>
    <description>The latest articles on DEV Community by Jordan Tingling (@jordan_t).</description>
    <link>https://dev.to/jordan_t</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F823718%2F6100df55-6694-4fc5-8094-e6265052cb69.jpg</url>
      <title>DEV Community: Jordan Tingling</title>
      <link>https://dev.to/jordan_t</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jordan_t"/>
    <language>en</language>
    <item>
      <title>The First AI-Powered URL Shortener - Shrinkify</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Sun, 26 Oct 2025 22:11:15 +0000</pubDate>
      <link>https://dev.to/jordan_t/the-first-ai-powered-url-shortener-shrinkify-mah</link>
      <guid>https://dev.to/jordan_t/the-first-ai-powered-url-shortener-shrinkify-mah</guid>
      <description>&lt;p&gt;&lt;strong&gt;What does he mean by AI-powered URL Shortener?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hey Guys, I'm Launching &lt;a href="https://shrinkify.co" rel="noopener noreferrer"&gt;Shrinkify&lt;/a&gt; today and figured this community i've been apart of for a longtime would appreciate the honest behind-the-scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  I had an issue with how things were
&lt;/h2&gt;

&lt;p&gt;I was paying $29/mo to Bitly. For what? A database entry and a 301 redirect. Maybe some basic charts if I was lucky.&lt;/p&gt;

&lt;p&gt;The idea wondered in my head for a while, that shortening urls don't need to be that expensive and most of the current solutions only shorten links, people still left with many questions unanswered. I wanted something that could fill in the blanks to the questions I had and many others do about how their links are actually performing? what they could be doing differently? and I wanted an solution that was more generous but I couldn't find one so... I built my own.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes it different (the technical bits)
&lt;/h2&gt;

&lt;p&gt;Instead of just another CRUD app with redirects, I added AI that's actually useful:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conversational analytics&lt;/strong&gt; – Ask questions in plain English:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Which link got the most clicks this week?"
"Is my landing page still up?"
"When's the best time to post my next link?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzew4nohs9t8ndxgu6og3.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzew4nohs9t8ndxgu6og3.png" alt="shrinkify-ai" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No GraphQL queries. No SQL. Just ask and get answers with real data. Your data! your links/urls! your campaigns/products/videos! all these data sources will feed metrics into Shrinkify where users can derive actionable insights from to actually make decisive decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Under the hood:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React 18 + TypeScript + Vite&lt;/li&gt;
&lt;li&gt;Supabase for backend (Postgres + real-time subscriptions)&lt;/li&gt;
&lt;li&gt;OpenAI API for conversational interface along with all the fancy models (ChatGPT, Claude, Gemini, and more)&lt;/li&gt;
&lt;li&gt;ML models for predictive analytics&lt;/li&gt;
&lt;li&gt;Edge functions for AI health monitoring&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2d5ezijk6tl6e1zleiam.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2d5ezijk6tl6e1zleiam.png" alt="shrinkify-ai" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other features devs will appreciate:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔮 Predictive analytics (7/30/90-day forecasts)&lt;/li&gt;
&lt;li&gt;🏥 Automated health monitoring with alerts&lt;/li&gt;
&lt;li&gt;⚡️ AI slug generator (because naming is the hardest problem)&lt;/li&gt;
&lt;li&gt;🔌 High-speed API access on premium is coming soon also&lt;/li&gt;
&lt;li&gt;📊 CSV exports for your own analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pricing (actually fair)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free:&lt;/strong&gt; 25 links, 10K clicks, basic AI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro:&lt;/strong&gt; $9/mo (1k links, 100K clicks)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Premium:&lt;/strong&gt; $99/mo (unlimited links, 1M clicks/mo, and all AI features)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compare that to Bitly's $29/mo for basic features.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tech stack
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend: React 18, TypeScript, Tailwind CSS, shadcn/ui, kibo UI
Backend: Supabase (Postgres + Edge Functions)
AI: OpenAI GPT-4 API, Gemini, Claude
Analytics: Custom ML models
Deployment: Vercel
Payments: Stripe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open to questions about any of the architecture decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm posting here
&lt;/h2&gt;

&lt;p&gt;I'm indie building this. No VC money. No team. Just me and i'm having fun.&lt;/p&gt;

&lt;p&gt;The code isn't perfect. There are probably bugs. But it's honest work and it actually solves a problem I had.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Would love feedback from this community:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the AI useful or gimmicky?&lt;/li&gt;
&lt;li&gt;What features would you actually use?&lt;/li&gt;
&lt;li&gt;What would make you switch from your current solution?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try it out, break it, tell me what sucks: &lt;a href="https://shrinkify.co" rel="noopener noreferrer"&gt;shrinkify.co&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'll be around to answer questions 🙏&lt;/p&gt;

&lt;p&gt;⭐️ Shrinkify's Product Hunt Link: &lt;a href="https://www.producthunt.com/products/shrinkify?comment=4965815" rel="noopener noreferrer"&gt;AI URL shortener that doesn't feel like a scam&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffx7yjwji4p939l6vgxiy.png" alt="shrinkify-ai" width="800" height="735"&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;P.S. - If you're curious about how I implemented the conversational AI or the predictive models, happy to write a deep-dive post.&lt;/em&gt;&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%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExazBxeDQ1NG1uOXR0eGNtYTh6d2Jubnh0bW9sYzN0NXd4Y29odDY5NCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FsMYk8hbUO6D2TYdE9R%2Fgiphy.gif" 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%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExazBxeDQ1NG1uOXR0eGNtYTh6d2Jubnh0bW9sYzN0NXd4Y29odDY5NCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FsMYk8hbUO6D2TYdE9R%2Fgiphy.gif" width="480" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>startup</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Calculator Backend-API In Go</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Mon, 02 Dec 2024 00:18:00 +0000</pubDate>
      <link>https://dev.to/jordan_t/calculator-backend-api-in-go-2173</link>
      <guid>https://dev.to/jordan_t/calculator-backend-api-in-go-2173</guid>
      <description>&lt;p&gt;Back again with another mini-project, this time with a calculator backend API tool written in Go!&lt;/p&gt;

&lt;p&gt;I recently wrapped up a project to build an HTTP+JSON API for a stateless calculator, and let me tell you—it was a lot more fun (and a little more challenging) than I expected. On the surface, it might sound simple: “Hey, it’s just a calculator, right?” But once you dive in, you start uncovering all the nitty-gritty details that make an API truly production-ready.&lt;/p&gt;

&lt;p&gt;So, let me share the process, the lessons learned, and what I’d tweak if I had to do it again.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;~ Souce code: Found &lt;a href="https://github.com/SirTingling/cloudprojects/tree/main/calculator-backend-api" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  A Stateless Calculator API
&lt;/h1&gt;

&lt;p&gt;The mission was straightforward: build an API for a calculator that doesn’t store any data—no databases, no in-memory caching. Every calculation happens in isolation. Stateless. Clean. Simple. The API follows an OpenAPI specification, which lays out all the endpoints and expected behaviors.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's next?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Input Validation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the first lessons I learned was the importance of input validation. You can’t trust users, even with something as basic as math. For example:&lt;/p&gt;

&lt;p&gt;What happens if someone sends in a non-number? Boom.&lt;br&gt;
How about division by zero? Double boom.&lt;/p&gt;

&lt;p&gt;To handle this, I made sure every input was sanitized and validated before the API even thought about processing it. If something was off, the user got a helpful, friendly error message like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Division by zero is not allowed. Please provide a valid denominator."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nobody likes cryptic “500 Server Error” messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Logging for Debugging&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You know that saying, “Logs are your best friend”? It’s true. I implemented structured logging using a Go &lt;code&gt;golang.org/x/exp/slog&lt;/code&gt; package, and it saved me so much time. Every request was logged with details like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The request path&lt;/li&gt;
&lt;li&gt;The user’s IP address&lt;/li&gt;
&lt;li&gt;The status code&lt;/li&gt;
&lt;li&gt;Any errors that popped up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a snippet of how I set it up for &lt;strong&gt;text logs&lt;/strong&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="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;slog&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;slog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTextHandler&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;Stdout&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;Or for JSON logs (which are great for integrating with monitoring tools):&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;logger&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;slog&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;slog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewJSONHandler&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;Stdout&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;Having those logs handy made debugging a breeze when something didn’t work as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  CORS: An Unexpected Hero
&lt;/h3&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipxvs1lbo1dssmgqq40o.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipxvs1lbo1dssmgqq40o.png" alt=" " width="100" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hadn’t initially planned for this API to be used in a browser-based app, but as the project evolved, it became clear that CORS (Cross-Origin Resource Sharing) was necessary. &lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;github.com/rs/cors&lt;/code&gt; package, I quickly added the required headers to allow browser-based clients to interact with the API.&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;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cors&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;cors&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;AllowedOrigins&lt;/span&gt;&lt;span class="o"&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="s"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;AllowedMethods&lt;/span&gt;&lt;span class="o"&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="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"OPTIONS"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;AllowedHeaders&lt;/span&gt;&lt;span class="o"&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="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;AllowCredentials&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&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;
  
  
  My main packages
&lt;/h3&gt;

&lt;p&gt;1) &lt;code&gt;net/http&lt;/code&gt;: Go’s standard library for setting up the HTTP server and routing requests.&lt;br&gt;
2) &lt;code&gt;encoding/json&lt;/code&gt;: To handle JSON encoding/decoding for requests and responses.&lt;br&gt;
3) &lt;code&gt;golang.org/x/exp/slog&lt;/code&gt;: For logging every request in either text or JSON format.&lt;br&gt;
4) &lt;code&gt;github.com/rs/cors&lt;/code&gt;: To handle cross-origin requests for web integrations.&lt;/p&gt;
&lt;h3&gt;
  
  
  What about the calculation logic?
&lt;/h3&gt;

&lt;p&gt;Well I made some handlers for these calculations, they are pretty basic in nature and primarily focus on the core functionality of calculations (Addition, Subtraction, Division &amp;amp; Multiplication).&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="c"&gt;//handlers.go&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;AddHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;slog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&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;HandlerFunc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&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;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;handleOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&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="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;float64&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;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&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;func&lt;/span&gt; &lt;span class="n"&gt;SubtractHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;slog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&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;HandlerFunc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&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;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;handleOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&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="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;float64&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;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&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;func&lt;/span&gt; &lt;span class="n"&gt;MultiplyHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;slog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&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;HandlerFunc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&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;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;handleOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&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="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;float64&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;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&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;func&lt;/span&gt; &lt;span class="n"&gt;DivideHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;slog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&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;HandlerFunc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&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;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;handleOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&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="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;float64&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;b&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="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"division by zero"&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;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&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;Aside from this, handling my HTTP requests with the famous &lt;code&gt;net/http&lt;/code&gt; package was straightforward and there are many examples out there of doing this in different ways. My case was very simple and I just needed to serve up some HTTP, handling the response writer and the request.&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;LoggingMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next&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;Handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;slog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&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;Handler&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&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;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;start&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;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;lrw&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;loggingResponseWriter&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="o"&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;statusCode&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;StatusOK&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lrw&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;duration&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;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"path"&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;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="s"&gt;"method"&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;Method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lrw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration&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;type&lt;/span&gt; &lt;span class="n"&gt;loggingResponseWriter&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;
    &lt;span class="n"&gt;statusCode&lt;/span&gt; &lt;span class="kt"&gt;int&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;lrw&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;loggingResponseWriter&lt;/span&gt;&lt;span class="p"&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;code&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lrw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;
    &lt;span class="n"&gt;lrw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&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;code&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;&lt;strong&gt;Here are some use-case examples:&lt;/strong&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="c"&gt;// Start up server&lt;/span&gt;
&lt;span class="c"&gt;// go run main.go&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2024&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;&lt;span class="n"&gt;T19&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;47.777&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;05&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Starting server on :3000"&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2024&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;&lt;span class="n"&gt;T19&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;55.440&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;05&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Request completed"&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=/&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;164.584&lt;/span&gt;&lt;span class="n"&gt;µs&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2024&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;&lt;span class="n"&gt;T19&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;51.520&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;05&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Request completed"&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=/&lt;/span&gt;&lt;span class="n"&gt;subtract&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;124.875&lt;/span&gt;&lt;span class="n"&gt;µs&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2024&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;&lt;span class="n"&gt;T19&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;56.727&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;05&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Request completed"&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=/&lt;/span&gt;&lt;span class="n"&gt;divide&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;40.875&lt;/span&gt;&lt;span class="n"&gt;µs&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2024&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;&lt;span class="n"&gt;T19&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;04.128&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;05&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Request completed"&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=/&lt;/span&gt;&lt;span class="n"&gt;multiply&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;46.458&lt;/span&gt;&lt;span class="n"&gt;µs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Requests:&lt;/strong&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="c"&gt;// Addition&lt;/span&gt;
&lt;span class="n"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c"&gt;//localhost:3000/add&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"result"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Subtraction&lt;/span&gt;
&lt;span class="n"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c"&gt;//localhost:3000/subtract&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"result"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Division&lt;/span&gt;
&lt;span class="n"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c"&gt;//localhost:3000/divide  &lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"result"&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="c"&gt;// Multiplication&lt;/span&gt;
&lt;span class="n"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c"&gt;//localhost:3000/multiply&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"result"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Yep! That's pretty much it! It was a quick and fun mini-project that I enjoyed! Feel free to give it a try and improve &amp;amp; enhance whichever way you'd like to.&lt;/p&gt;

&lt;p&gt;Until next time, cheers! 🍻 🥂 &lt;/p&gt;

</description>
      <category>challenge</category>
      <category>go</category>
      <category>devops</category>
      <category>api</category>
    </item>
    <item>
      <title>Currency Converter In Go</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Sun, 01 Dec 2024 21:51:54 +0000</pubDate>
      <link>https://dev.to/jordan_t/currency-converter-in-go-jdo</link>
      <guid>https://dev.to/jordan_t/currency-converter-in-go-jdo</guid>
      <description>&lt;p&gt;Hey Guys!&lt;/p&gt;

&lt;p&gt;Yet another small mini-project for making a currency converter in Go! &lt;/p&gt;

&lt;p&gt;It's a simple but fun project that should take someone about an hour or 2 depending on their experience. It takes a currency type from one end, the currency which we intend to convert to and the amount to be converted.&lt;/p&gt;

&lt;p&gt;I'm making use of a third-party service (&lt;code&gt;https://openexchangerates.org&lt;/code&gt;) to retrieve the latest currency data.&lt;/p&gt;

&lt;p&gt;My Main base currencies are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1) USD
2) EUR
3) GBP
4) JPY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and I also have support for "other" currencies through input in the TUI. Both for base currencies and currencies to be converted to.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;~ Source Code: Found &lt;a href="https://github.com/SirTingling/cloudprojects/tree/main/current-converter" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Let's Begin
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;What&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;

                              &lt;span class="n"&gt;List&lt;/span&gt;             

&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;USD&lt;/span&gt;               
&lt;span class="n"&gt;United&lt;/span&gt; &lt;span class="n"&gt;States&lt;/span&gt; &lt;span class="n"&gt;Dollar&lt;/span&gt;

&lt;span class="err"&gt;£&lt;/span&gt; &lt;span class="n"&gt;GBP&lt;/span&gt;               
&lt;span class="n"&gt;British&lt;/span&gt; &lt;span class="n"&gt;Pound&lt;/span&gt;

&lt;span class="err"&gt;€&lt;/span&gt; &lt;span class="n"&gt;EUR&lt;/span&gt;       
&lt;span class="n"&gt;Euro&lt;/span&gt;        

&lt;span class="err"&gt;¥&lt;/span&gt; &lt;span class="n"&gt;JPY&lt;/span&gt;       
&lt;span class="n"&gt;Japanese&lt;/span&gt; &lt;span class="n"&gt;Yen&lt;/span&gt;       


  &lt;span class="err"&gt;•••&lt;/span&gt;          
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The main functionalities of the application are:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get Conversion details entered by the user&lt;/li&gt;
&lt;li&gt;Use those details and send an API request to Openxchangerates (Third-Party service with the latest currency conversion rates)&lt;/li&gt;
&lt;li&gt;Convert currencies &amp;amp; amount&lt;/li&gt;
&lt;li&gt;Output currencies &amp;amp; amount data to the user&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The packages used:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;net/http&lt;/code&gt; - for http requests to the currency exchange api&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;github.com/charmbracelet/huh&lt;/code&gt; - for the TUI interface form&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;github.com/charmbracelet/bubbles/list&lt;/code&gt; - feature-rich for browsing a general-purpose list of items&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;encoding/json&lt;/code&gt; - in order to marshal the data for the API&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;github.com/charmbracelet/lipgloss&lt;/code&gt; - Style definitions for terminal layouts&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;So let's discuss the first bit of functionality, which is getting conversion details from the user.&lt;/p&gt;

&lt;p&gt;A view method for getting this user-provided data had to be made and it asks the user questions on what currency to convert, which currency to be converted to, and more.&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;m&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;View&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&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;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;"Error: %v&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;Press any key to continue.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&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="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Return an empty string when finished to avoid redundant output.&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="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isCustomInput&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;questionStyle&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="s"&gt;"Enter your custom base currency code (e.g., USD):&lt;/span&gt;&lt;span class="se"&gt;\n\n&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="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;View&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;questionStyle&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="s"&gt;"What is your base currency?&lt;/span&gt;&lt;span class="se"&gt;\n\n&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="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isCustomInput&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;questionStyle&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="s"&gt;"Enter your custom target currency code (e.g., EUR):&lt;/span&gt;&lt;span class="se"&gt;\n\n&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="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;View&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;questionStyle&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="s"&gt;"What do you want to convert to?&lt;/span&gt;&lt;span class="se"&gt;\n\n&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="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;questionStyle&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="s"&gt;"How much to convert?&lt;/span&gt;&lt;span class="se"&gt;\n\n&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="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;What&lt;/span&gt; &lt;span class="n"&gt;do&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;want&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;convert&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;

                                  &lt;span class="n"&gt;List&lt;/span&gt;             

&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;USD&lt;/span&gt;               
&lt;span class="n"&gt;United&lt;/span&gt; &lt;span class="n"&gt;States&lt;/span&gt; &lt;span class="n"&gt;Dollar&lt;/span&gt;

&lt;span class="err"&gt;£&lt;/span&gt; &lt;span class="n"&gt;GBP&lt;/span&gt;               
&lt;span class="n"&gt;British&lt;/span&gt; &lt;span class="n"&gt;Pound&lt;/span&gt;       


  &lt;span class="err"&gt;•••&lt;/span&gt;        
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;How&lt;/span&gt; &lt;span class="n"&gt;much&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;convert&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;

                    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Now let's discuss the second point, using the currency conversion details and sending an API request to Openxchangerates.&lt;/p&gt;

&lt;p&gt;Here I'm getting/fetching for the latest currency rates from Openxchangerates.org via an API key provided by the third-party currency exchange platform. In my case, I made use of &lt;code&gt;.env's&lt;/code&gt; for secret management but there are a multitude of other ways to better handle this, especially if it were a production app. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;~ Openxchangerates.org docs used for this: located &lt;a href="https://docs.openexchangerates.org/reference/latest-json" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&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="c"&gt;//api.go&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;api&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;"encoding/json"&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;type&lt;/span&gt; &lt;span class="n"&gt;CurrencyData&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;Base&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;             &lt;span class="s"&gt;`json:"base"`&lt;/span&gt;
    &lt;span class="n"&gt;Rates&lt;/span&gt; &lt;span class="k"&gt;map&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;float64&lt;/span&gt; &lt;span class="s"&gt;`json:"rates"`&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;FetchRates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiKey&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="n"&gt;CurrencyData&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;url&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;"https://openexchangerates.org/api/latest.json?app_id=%s&amp;amp;prettyprint=false"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&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;url&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;CurrencyData&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;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CurrencyData&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;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"API request failed with status: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;CurrencyData&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;data&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;CurrencyData&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;data&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;Then we'll proceed with converting the currencies and amounts:&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="c"&gt;//conversion.go&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;conversion&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&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;rateFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rateTo&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;float64&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;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rateTo&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;rateFrom&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;which is simply taking in a base amount (amount), a rate from the base currency and the rate to be converted to and returns a final converted amount.&lt;/p&gt;




&lt;p&gt;Lastly, providing the converted currencies and amount-related data back to the user.&lt;/p&gt;

&lt;p&gt;Controlling the logic behind these selections is an update function that serves as the main state transition handler for the application's model.&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;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cmd&lt;/span&gt;

    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyMsg&lt;/span&gt;&lt;span class="o"&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;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&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;key&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;"enter"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isCustomInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c"&gt;// Handle custom currency input&lt;/span&gt;
                &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToUpper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TrimSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isAlphabetic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid currency code: must be 3 letters"&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;m&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;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&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="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currencyFrom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isCustomInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResetSelected&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;m&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;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currencyTo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isCustomInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Placeholder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Enter amount (e.g., 100)"&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Focus&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;m&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;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&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="c"&gt;// Handle amount input&lt;/span&gt;
                &lt;span class="n"&gt;amountStr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TrimSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&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;amount&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;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amountStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;64&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;m&lt;/span&gt;&lt;span class="o"&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid amount: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&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;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
                &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quit&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c"&gt;// Handle list selection&lt;/span&gt;
                &lt;span class="n"&gt;selectedItem&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SelectedItem&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;Item&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;selectedItem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"OTHER"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isCustomInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Placeholder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Enter currency code (e.g., USD)"&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Focus&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;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;textinput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Blink&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;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&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="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currencyFrom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selectedItem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResetSelected&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;m&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;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currencyTo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selectedItem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Placeholder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Enter amount (e.g., 100)"&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Focus&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;m&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;case&lt;/span&gt; &lt;span class="s"&gt;"ctrl+c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"esc"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quit&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Handle text input for custom currency or amount input&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isCustomInput&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&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="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textInput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&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;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Handle list updates for currency selection&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&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;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&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;m&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// go run main.go&lt;/span&gt;
&lt;span class="m"&gt;200.00&lt;/span&gt; &lt;span class="n"&gt;EUR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;166.03&lt;/span&gt; &lt;span class="n"&gt;GBP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;That pretty much wraps up this relatively quick currency converter. I hope you've enjoyed the quick read and feel free to give a shot also, it's not that bad! 😁.&lt;/p&gt;

&lt;p&gt;Feel free to also experiment with other third-party currency exchange providers out there, there are many. Hopefully, they got a decent API too!&lt;/p&gt;

&lt;p&gt;See you guys on the next one! 👋🏼&lt;/p&gt;

</description>
      <category>currency</category>
      <category>go</category>
      <category>devops</category>
      <category>api</category>
    </item>
    <item>
      <title>URL Shortener in Go</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Thu, 28 Nov 2024 04:11:54 +0000</pubDate>
      <link>https://dev.to/jordan_t/url-shortener-in-go-3d8l</link>
      <guid>https://dev.to/jordan_t/url-shortener-in-go-3d8l</guid>
      <description>&lt;h1&gt;
  
  
  Building URL Shorteners in Go: A Tale of Two Frameworks
&lt;/h1&gt;

&lt;p&gt;URL shorteners are a classic example of how simple tools can make a big impact. Whether you’re sharing links on social media or sending them in a text, shorter URLs are easier to manage and look clean. &lt;/p&gt;

&lt;p&gt;In this blog post, I’ll walk you through these two URL shortener projects that are lightweight and very quick to create, they are both built-in Go: one using the &lt;strong&gt;Gin framework&lt;/strong&gt; and the other using &lt;strong&gt;Gorilla Mux&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Each brings a unique approach to the table, and I’ll highlight their features and differences.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;~ Source Code: Found &lt;a href="https://github.com/SirTingling/cloudprojects.git" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  URL Shortener with GUI: Feature-Rich and Intuitive
&lt;/h2&gt;

&lt;p&gt;Let’s start with the first project—a URL shortener that goes beyond a simple API. It includes both a &lt;strong&gt;REST API backend&lt;/strong&gt; and a &lt;strong&gt;desktop GUI application&lt;/strong&gt;, making it accessible for developers and non-technical users alike. This project uses the &lt;strong&gt;Gin framework&lt;/strong&gt; for its backend and &lt;strong&gt;Fyne&lt;/strong&gt; for the GUI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;REST API Backend&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The Gin framework powers a fast and reliable API for shortening and redirecting URLs. It’s lightweight yet robust, perfect for this use case.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Desktop GUI&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Built with the Fyne framework, the GUI is clean, minimalistic, and easy to use. It enables users to shorten URLs without needing to touch a terminal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Secure and Random Keys&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The short URLs are generated using secure random values, ensuring uniqueness and reducing the chances of collisions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dual Access&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Whether you’re comfortable with REST APIs or prefer a GUI, this project has you covered.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;To get started, clone the repository and install the necessary external Go packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/SirTingling/cloudprojects.git
&lt;span class="nb"&gt;cd &lt;/span&gt;url-shortener
go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/gin-gonic/gin
go get &lt;span class="nt"&gt;-u&lt;/span&gt; fyne.io/fyne/v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the App
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backend Server&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run the backend server with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run server.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server will start at &lt;code&gt;http://localhost:8080&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Desktop GUI&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Launch the GUI application with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run gui.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This opens a simple window where you can input long URLs and get shortened links in return.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does it work?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;API Endpoints:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;POST /shorten:&lt;/code&gt; Accepts a long URL and returns a short URL.&lt;br&gt;
&lt;code&gt;GET /:short:&lt;/code&gt; Redirects the short URL to the original URL.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GUI Workflow:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Enter the long URL.&lt;/li&gt;
&lt;li&gt;Click "Shorten URL".&lt;/li&gt;
&lt;li&gt;Copy the shortened link and share it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The inclusion of a GUI makes it more versatile than a typical backend-only application.&lt;/p&gt;




&lt;h2&gt;
  
  
  URL Shortener V2: Lightweight and Straightforward
&lt;/h2&gt;

&lt;p&gt;The second project is all about simplicity. Built with &lt;strong&gt;Gorilla Mux&lt;/strong&gt;, it focuses on providing a basic yet functional URL shortener. If you’re looking for a lightweight solution that gets the job done, this is the one, my friends.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Gorilla Mux for Routing&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Gorilla Mux is a powerful router for Go, and it’s used here to handle all the HTTP endpoints.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;MD5-Based Key Generation&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Shortened URLs are created using an MD5 hash of the original URL. Yes, I do agree, that it’s not as secure as random generation, nevertheless, it’s efficient and ensures deterministic results.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;In-Memory Storage&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The shortener uses a simple in-memory map to store URLs. This makes it fast, though it’s not ideal for production-scale applications.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Minimal Dependencies&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With only Gorilla Mux as an external dependency, this project is easy to set up and deploy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's Go!
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &amp;lt;repository-url&amp;gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;url-shortener
go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/gorilla/mux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the App
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Start the server with:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server will run at &lt;code&gt;http://localhost:8080&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create Short URL:&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Send a POST request to /create with the url parameter:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"url=https://example.com"&lt;/span&gt; http://localhost:8080/create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Response:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;http://localhost:8080/abcde
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Redirect:
Access the shortened URL
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/abcde
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This redirects to the original URL.&lt;/p&gt;

&lt;p&gt;Honestly, it’s quick to implement and works well as a learning project or for small-scale use cases. I liked it as a quick mini-project.&lt;/p&gt;




&lt;h3&gt;
  
  
  Comparing the Two Approaches
&lt;/h3&gt;

&lt;p&gt;Here’s a quick breakdown of the differences:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;URL Shortener with GUI (Gin)&lt;/th&gt;
&lt;th&gt;URL Shortener V2 (Mux)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Framework&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gin&lt;/td&gt;
&lt;td&gt;Gorilla Mux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Frontend&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Desktop GUI (Fyne)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;URL Key Generation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Secure Random Values&lt;/td&gt;
&lt;td&gt;MD5 Hash&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not Specified&lt;/td&gt;
&lt;td&gt;In-Memory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Complexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Simple&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Working with both approaches was straightforward in my personal opinion and I hope you guys will give them both a try as they can both be used in many different scenarios outside of URL shortening.&lt;/p&gt;

&lt;p&gt;The Gin-based solution is ideal for those who want an all-in-one tool with a user interface, while the Mux-based version is perfect for lightweight, API-only use cases.&lt;/p&gt;




&lt;p&gt;Thanks for tuning in again to my mini-project adventure with Go (and many more languages &amp;amp; tools). I'll catch you guys in the next one! Cheers!! 🥂 &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxjvv3qumvqdm4gphsxo.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpxjvv3qumvqdm4gphsxo.gif" alt=" " width="200" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>cloud</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Simple Go CLI-Todo App</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Wed, 27 Nov 2024 23:44:56 +0000</pubDate>
      <link>https://dev.to/jordan_t/simple-go-cli-todo-app-19j6</link>
      <guid>https://dev.to/jordan_t/simple-go-cli-todo-app-19j6</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hey Guys!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I haven't blogged on Dev in over 2 years! It's been a while so please excuse me if my typing skills have degraded over time.&lt;/p&gt;

&lt;p&gt;I'm currently learning Go and received a list of projects to complete and share, one of these happens to be a simple Golang cli-todo app that allows someone to add todos to a list of tasks and achieve a set of basic functionality on these tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;These include:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1) Listing Tasks&lt;br&gt;
2) Adding More Tasks&lt;br&gt;
3) Modifying These Tasks&lt;br&gt;
4) Making Tasks Completed&lt;/p&gt;

&lt;p&gt;Unfortunately, I don't have a fancy name for it 😅 as it's designed to be a lightweight, easy-to-use app that someone can complete in a day. Even if you're a beginner.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7yvkak1xfuzpqjw3cow.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7yvkak1xfuzpqjw3cow.png" alt=" " width="800" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;~ &lt;em&gt;Project Source code: &lt;a href="https://github.com/SirTingling/cloudprojects/tree/main/go-cli-todo-app" rel="noopener noreferrer"&gt;https://github.com/SirTingling/cloudprojects/tree/main/go-cli-todo-app&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's Begin
&lt;/h2&gt;

&lt;p&gt;Well as usual, the creation of our &lt;code&gt;main.go&lt;/code&gt;. Once this is setup, we will need to define the structure and functionality of our todos. I did so in a separate &lt;code&gt;todo.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Todo&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;Completed&lt;/span&gt;   &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;CreatedAt&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;CompletedAt&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;Time&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with a slice to hold our todos&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;Todos&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Todo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we'll need the implementation of the main methods of functionality, which include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add
&lt;/li&gt;
&lt;/ul&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;todos&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;add&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="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Todo&lt;/span&gt;&lt;span class="p"&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;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Completed&lt;/span&gt;&lt;span class="o"&gt;:&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;CompletedAt&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;CreatedAt&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;Now&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="n"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todo&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;Creates a Todo object with a title, sets its Completed status to false, and appends it to the Todos slice.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;delete
&lt;/li&gt;
&lt;/ul&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;todos&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="kt"&gt;int&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;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;todos&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="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validateIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&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="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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&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="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;Validates the index, then uses slicing to remove the item from the Todos list.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;toggle
&lt;/li&gt;
&lt;/ul&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;todos&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="kt"&gt;int&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="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="n"&gt;todos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validateIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&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="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;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;todos&lt;/span&gt;
    &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Completed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;completedTime&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;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;completedTime&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedAt&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;todo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Completed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Completed&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;Validates the index, flips the Completed boolean, and updates the CompletedAt timestamp accordingly.&lt;/p&gt;

&lt;p&gt;The rest of the methods follow a very similar functionality, if any issues, feel free to check out the &lt;a href="https://github.com/SirTingling/cloudprojects/tree/main/go-cli-todo-app" rel="noopener noreferrer"&gt;source code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running The App
&lt;/h2&gt;

&lt;p&gt;A common issue with many to-do apps that are cli-based is that they aren't as charming. With the help of a third-party package called &lt;code&gt;aquasecurity/table&lt;/code&gt; the to-do list will be displayed neatly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aquasecurity/table" rel="noopener noreferrer"&gt;aquasecurity/table&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It can be installed with:&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;go&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;aquasecurity&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I made a method to display the todos using methods from external the package. Particularly &lt;code&gt;SetRowLines&lt;/code&gt;, &lt;code&gt;SetHeaders&lt;/code&gt;, &lt;code&gt;New&lt;/code&gt;, &lt;code&gt;AddRow&lt;/code&gt; &amp;amp; &lt;code&gt;Render&lt;/code&gt; were the primarily used ones in my case.&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;todos&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;table&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;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetRowLines&lt;/span&gt;&lt;span class="p"&gt;(&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;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetHeaders&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="s"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Created At"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Completed At"&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;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;todos&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"❌"&lt;/span&gt;
        &lt;span class="n"&gt;completedAt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Completed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"✅"&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedAt&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;completedAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedAt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&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;RFC1123&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;//time standard&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Itoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;t&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;completed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreatedAt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&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;RFC1123&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;completedAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;table&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;print&lt;/code&gt; method is a neat way to show the list of todos in the terminal. It creates a table with columns for things like the task number, title, whether it's completed, when it was created, and when it was completed. &lt;/p&gt;

&lt;p&gt;It goes through each todo item, checks if it's done or not, and adds a ✅ if it's completed or a ❌ if it isn't. If the task is finished, it even shows the exact date and time it was completed. &lt;/p&gt;

&lt;p&gt;Once all the rows are ready, it prints the table out in a clean, readable format. Super handy for quickly seeing the status of all a user's tasks at a glance!&lt;/p&gt;

&lt;h3&gt;
  
  
  How about saving these todos?
&lt;/h3&gt;

&lt;p&gt;So I thought that the functionality of saving the todos locally to let's say a file, in this case, &lt;code&gt;todos.json&lt;/code&gt;, and then reading from there would be a good idea. Essentially having some level of persistence of our data regarding each and all todos.&lt;/p&gt;

&lt;p&gt;We could add this functionality to an existing file, but I think it's a good idea to separate concerns. &lt;/p&gt;

&lt;p&gt;I added a &lt;code&gt;storage.go&lt;/code&gt;, it could be called whatever you'd like &lt;code&gt;store.go&lt;/code&gt;, &lt;code&gt;persist.go&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;I chose JSON but the same principles usually apply to any data format you'd like to save the data too.&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;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Filename&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="n"&gt;NewStorage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]{&lt;/span&gt;&lt;span class="n"&gt;Filename&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;filename&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;T&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;fileData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarshalIndent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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="s"&gt;"    "&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="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fileData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// file mode&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;s&lt;/span&gt; &lt;span class="n"&gt;Storage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;T&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;fileData&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;ReadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filename&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="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;fileData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// convert and populate data&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There's a &lt;strong&gt;Storage&lt;/strong&gt; struct that keeps track of the file being worked with.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;NewStorage&lt;/strong&gt; function helps set things up by just giving it the file name.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;Save&lt;/strong&gt; method takes the data, turns it into pretty JSON, and writes it to the file (todos.json). If something goes wrong, it tells us with an error.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;Load&lt;/strong&gt; method does the opposite—reads the file, unpacks the JSON, and fills the fileData with the data.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s an easy, reusable way to handle saving and loading any kind of data without needing a database or anything fancy.&lt;/p&gt;

&lt;p&gt;From here I make use of the NewStorage in the main.go to add some todos to my list and save them which can now be viewed in my todos.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Todos&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="c"&gt;// Load data (todos) from storage:&lt;/span&gt;
    &lt;span class="n"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewStorage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Todos&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="s"&gt;"todos.json"&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;storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;todos&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;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;"Warning: Could not load todos from storage. Starting fresh todos."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// Parse &amp;amp; Execute&lt;/span&gt;
    &lt;span class="n"&gt;cmdFlags&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewCmdFlags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;cmdFlags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&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;todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// Save to storage&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;storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todos&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error saving todos in storage: %v&lt;/span&gt;&lt;span class="se"&gt;\n&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;








&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Go for a drive"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Completed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CreatedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-11-26T15:26:06.691069-05:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CompletedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Eat dinner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Completed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CreatedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-11-26T15:26:37.361324-05:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CompletedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-11-26T15:33:03.088908-05:00"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Walk my dog"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Completed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CreatedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-11-27T17:44:04.963474-05:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CompletedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Go hiking later with ashley"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Completed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CreatedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-11-27T17:51:01.667686-05:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CompletedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the commands, I didn't make anything fancy. I defined the flags I'll use as a struct&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;CmdFlags&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;Add&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Del&lt;/span&gt;    &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;Edit&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Toggle&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;List&lt;/span&gt;   &lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then a simple function using the flag package the list these flags, give them more details &amp;amp; descriptions, and customize them. I've also heard good things about the &lt;a href="https://github.com/spf13/cobra" rel="noopener noreferrer"&gt;Cobra package&lt;/a&gt; which could be very easy to use here, next time I'll try it out.&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;NewCmdFlags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;CmdFlags&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;CmdFlags&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="c"&gt;// Flag list and usage of cli todo app&lt;/span&gt;
    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringVar&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;cf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"add"&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="s"&gt;"Add a new todo specifying title"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringVar&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;cf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Edit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"edit"&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="s"&gt;"Edit a todo by index &amp;amp; specify a new title. id:new_title"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntVar&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;cf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Del&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"del"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Specify a todo by index to delete effectively"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntVar&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;cf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Toggle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"toggle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Specify a todo by index to toggle"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BoolVar&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;cf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"List all todos"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;//&lt;/span&gt;
    &lt;span class="n"&gt;flag&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cf&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there, you can get creative on how you'd like to execute these flags, in my case I made simple case statements.&lt;/p&gt;

&lt;h3&gt;
  
  
  That's It?
&lt;/h3&gt;

&lt;p&gt;Yep! That completed this simple Go cli to-do app that can be done in a relatively short period of time, major shout out to &lt;strong&gt;&lt;em&gt;Coding with Patrik&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;The Builder&lt;/em&gt;&lt;/strong&gt; both of which have amazing content out there for helping with projects like these and making it fun!&lt;/p&gt;

&lt;p&gt;Thanks for reading and I hope that these mini-projects inspire others to either get started with Go or simply keep practicing with it. I have a few more to do and share, see you guys next time!&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fko9yvrthf1zzowdkxfyc.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fko9yvrthf1zzowdkxfyc.gif" alt=" " width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>cli</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>Git CheatSheet</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Sun, 02 Oct 2022 02:02:16 +0000</pubDate>
      <link>https://dev.to/jordan_t/git-cheatsheet-4j76</link>
      <guid>https://dev.to/jordan_t/git-cheatsheet-4j76</guid>
      <description>&lt;h1&gt;
  
  
  Git (Version Control)
&lt;/h1&gt;

&lt;p&gt;Git is an essential collaborative part of any programmer/developer/DevOps engineer's daily routine. Git is widely used in the industry with version control platforms such as Github, Bitbucket, etc.&lt;/p&gt;

&lt;p&gt;There is a multitude of commands to use for Git; mastering them takes time and effort. In this post, my aim is to share with you some of the more frequently used commands in Git that every developer should know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Clone
&lt;/h2&gt;

&lt;p&gt;Git clone is a command that is used for downloading existing source code from a remote repository (Github, Bitbucket). Basically, git clone makes an identical copy of the latest version of a project in a repository and saves it within your local filesystem on your local machine.&lt;/p&gt;

&lt;p&gt;Generally, I &lt;strong&gt;clone with https&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git clone &amp;lt;https://name-of-the-repository-link&amp;gt;&lt;/code&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8m74u96mdxuajtyy9ty.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8m74u96mdxuajtyy9ty.png" alt=" " width="380" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will make a copy of the repository to your local machine so you can start working with it, make changes, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git branch
&lt;/h2&gt;

&lt;p&gt;By making use of branches in Git, several developers are able to work in parallel on the same project simultaneously. We can use the git branch command for creating, listing, and deleting branches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a new branch:
&lt;/h3&gt;

&lt;p&gt;This command will create a branch locally. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;git branch &amp;lt;branch-name&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To push the new branch into the remote repository, here is the command to use:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git push -u &amp;lt;remote&amp;gt; &amp;lt;branch-name&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Viewing branches:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git branch or git branch --list&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Delete a branch:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git branch -d &amp;lt;branch-name&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Git checkout
&lt;/h2&gt;

&lt;p&gt;This is also one of the most used Git commands. In order to work in a branch, we first need to switch to that branch. We use &lt;strong&gt;git checkout&lt;/strong&gt; mainly for switching from one branch to another. It can also be used for checking out files and commits.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git checkout &amp;lt;name-of-your-branch&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The changes in your current branch must be committed or stashed before you switch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The branch you want to checkout should already exist in your local directory.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a shortcut command that will allow you to create and switch to a branch at the same time:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git checkout -b &amp;lt;name-of-your-branch&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command creates a new branch in your local (-b means for branch) and checks the branch out to new right after it has been created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git status
&lt;/h2&gt;

&lt;p&gt;The Git status command gives all the necessary information about the current branch.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git status&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This information is very important, it provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Info on whether the current branch is up to date&lt;/li&gt;
&lt;li&gt;Info on anything to commit, push or pull&lt;/li&gt;
&lt;li&gt;Info on files stages, unstaged or untracked.&lt;/li&gt;
&lt;li&gt;Info on files created, modified, or deleted.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Git add
&lt;/h2&gt;

&lt;p&gt;Whenever we create, modify, or delete a file, these changes will happen in our local and will not be included in the enxt commit.&lt;/p&gt;

&lt;p&gt;we need to use the git add command to include the changes of a file(s) into our next commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add a single file:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git add &amp;lt;file&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Add everything at once:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git add -A&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;git add&lt;/strong&gt; command doesn't change the repository and the changes are not saved until we make use of &lt;strong&gt;git commit&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Git commit
&lt;/h2&gt;

&lt;p&gt;The famous &lt;strong&gt;Git commit&lt;/strong&gt; command is probably the most used command of Git. To save our changes we make use of git commit.&lt;/p&gt;

&lt;p&gt;Git commit is like setting a checkpoint in the development process which you can go back to later if needed.&lt;/p&gt;

&lt;p&gt;We are able to write a short message explaining what you have developed or changes in the source code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git commit -m "commit message&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS: Git commit saves your changes only locally&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Git push
&lt;/h2&gt;

&lt;p&gt;Making use of &lt;strong&gt;Git push&lt;/strong&gt; is for sending your changes to the remote server (remote repository) after committing your changes. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;git push &amp;lt;remote&amp;gt; &amp;lt;branch-name&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If your branch is newly created, please upload the branch with the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git push --set-upstream &amp;lt;remote&amp;gt; &amp;lt;name-of-your-branch&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;or&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git push -u origin &amp;gt;branch-name&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS: Git push only uploads changes that have been committed&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Git pull
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;git pull&lt;/strong&gt; command is used to get updates from the remote repository. This command is basically a combination of &lt;strong&gt;git fetch&lt;/strong&gt; and &lt;strong&gt;git merge&lt;/strong&gt; which means that, when we use git pull, it gets the updates from the remote repository (git fetch) and immediately applies the latest changes in your local (git merge).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git pull &amp;lt;remote&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Git revert
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;git revert&lt;/strong&gt; command is used to undo the changes that we've made. &lt;/p&gt;

&lt;p&gt;To see your commit history, make use of this command: &lt;strong&gt;git log --oneline&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Specify the hash code next to your commit that you would like to undo:&lt;/p&gt;

&lt;p&gt;Example: 4442389&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git revert 4442389&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The Git revert command will undo the given commit, but will create a new commit without deleting the older one.&lt;/p&gt;

&lt;p&gt;The advantage of using &lt;strong&gt;git revert&lt;/strong&gt; is that it doesn't do anything to the commit history. Also, everything happens in our local system unless we push it to the remote repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git merge
&lt;/h2&gt;

&lt;p&gt;Once you have completed development in your branch and everything works as intended, the final step is to merge the local branch with the parent branch (remote branch). This can be accomplished with the &lt;strong&gt;git merge&lt;/strong&gt; command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before merging, you should update your local development branch:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git fetch&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Then, we can merge your feature branch into the remote branch:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git merge &amp;lt;branch-name&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS: Please ensure your local development branch has the latest version before you merge your branches, otherwise, you may face conflicts or other unwanted issues with versioning and state control&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I hope these frequently used Git commands will help all developers in their daily tasks. There are many more things to learn about Git and complex ways of versioning, therefore, I encourage you to continue learning Git and take things future.&lt;/p&gt;

&lt;p&gt;Thank you @CemEygi &lt;/p&gt;

</description>
      <category>github</category>
      <category>git</category>
      <category>linux</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Pass The AWS Certified Solution Architect - Associate (SAA-CO3)</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Sun, 28 Aug 2022 02:27:00 +0000</pubDate>
      <link>https://dev.to/jordan_t/pass-the-aws-certified-solution-architect-associate-saa-co3-523p</link>
      <guid>https://dev.to/jordan_t/pass-the-aws-certified-solution-architect-associate-saa-co3-523p</guid>
      <description>&lt;p&gt;I passed the &lt;strong&gt;AWS Certified Solutions Architect — Associate exam (SAA-C02)&lt;/strong&gt; on Nov 12, 2021. &lt;a href="https://www.credly.com/badges/dc1b4f82-d1f0-4149-a601-b27ae39d6cd2/public_url" rel="noopener noreferrer"&gt;SA-associate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;~ &lt;em&gt;Please right-click and "open link in new tab" for all links&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By Aug 30, 2022, the &lt;em&gt;(SAA-C02)&lt;/em&gt; version of the exam will be retired and the &lt;em&gt;(SAA-CO3)&lt;/em&gt; will be the new version of the exam, however, all information and resource that I will be providing will prepare you for the new version of the exam &lt;em&gt;(SAA-CO3)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This post was written to help my dad (you got this pops!) pass the certification, however, it's not exclusive to my dad and can be taken advantage of by anyone interested in the &lt;strong&gt;AWS Certified Solutions Architect — Associate exam (SAA-C03)&lt;/strong&gt; including his co-workers that are also interested in passing this cert. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9gi1wtzw8nbyc1wavmz.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9gi1wtzw8nbyc1wavmz.png" alt=" " width="300" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  First Steps
&lt;/h3&gt;

&lt;p&gt;Well, the &lt;strong&gt;starting point&lt;/strong&gt; for me was the &lt;a href="https://d1.awsstatic.com/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Exam-Guide.pdf" rel="noopener noreferrer"&gt;exam guide&lt;/a&gt; which is located on the &lt;a href="https://aws.amazon.com/certification/certified-solutions-architect-associate/" rel="noopener noreferrer"&gt;main page&lt;/a&gt; of the exam where you could also download the sample questions that AWS provides.&lt;/p&gt;

&lt;p&gt;The next thing I did was begin collecting relevant resources I plan to use for studying. Try to have all the necessary resources stored in one place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Establish Your Learning Path/Resources
&lt;/h3&gt;

&lt;p&gt;From all the resources you collected, try to establish your learning path, based on your experience and the time you plan to invest. There are plenty of courses on learning platforms such as &lt;strong&gt;Udemy&lt;/strong&gt;, &lt;strong&gt;Cloud Academy&lt;/strong&gt;, &lt;strong&gt;A Cloud Guru&lt;/strong&gt;, etc. Try to pick one of the courses. After I tried several ones, I made the decision of taking A Cloud Guru's &lt;a href="https://learn.acloud.guru/course/certified-solutions-architect-associate/overview" rel="noopener noreferrer"&gt;AWS Certified Solutions Architect - Associate (SAA-C02)&lt;/a&gt; course, and don't worry, they have updated the course to match the new version of the exam &lt;em&gt;(SAA-C03)&lt;/em&gt;. It's a great choice for someone that doesn't have the most time and needs an interactive way of learning by doing hands-on labs, quizzes, etc. &lt;strong&gt;A Cloud Guru&lt;/strong&gt; is a paid subscription company that offers multiple plans, I recommend the personal Plan-Basic. For this certification that is more than enough, however, if you need more then they have it for you!&lt;/p&gt;

&lt;p&gt;For the persons that have more time on their hands &amp;gt;45.9 hours of content and desire a deeper understanding of the technologies and services within the certification to not only the certification but truly understand them on a deeper level then I definitely recommend &lt;strong&gt;Adrian Cantrill's&lt;/strong&gt; course &lt;a href="https://learn.cantrill.io/p/aws-certified-solutions-architect-associate-saa-c03" rel="noopener noreferrer"&gt;AWS Certified Solutions Architect - Associate (SAA-C03&lt;/a&gt;. Adrain's course is a one-time fee of $40, however, his learning material is impeccable, I recommend his course material to anyone at any stage of their journey to cloud &amp;amp; AWS!&lt;/p&gt;

&lt;p&gt;What I find also useful is the &lt;a href="https://tutorialsdojo.com/aws-certified-solutions-architect-associate-saa-c03/" rel="noopener noreferrer"&gt;Tutorials Dojo SAA-C03&lt;/a&gt; study path, with the list of all the useful resources. On that page. Also, try to read the &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/framework/wellarchitected-framework.pdf#welcome" rel="noopener noreferrer"&gt;AWS Well architectures framework&lt;/a&gt; and other major whitepapers related to the &lt;em&gt;SAA-C03&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You can also take the official AWS training for this exam if possible, but it is a matter of preference. Someone is more comfortable with official training and dedicated time, and someone is more comfortable going with an online course, at your own pace.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let The Learning Begin
&lt;/h3&gt;

&lt;p&gt;Whatever you picked, dedicate some time to go through all the topics, even if it's 2-3 hours a day, by the end of the week that's 14-21 hours dedicated to studying for the most popular IT certification in 2022. It is not required, however, I do recommend writing specific notes from the lectures, because it is a lot of stuff. You will come back later to the notes, trust me. Try not just to go through materials, but also try to get your hands dirty with AWS stuff, and gather some &lt;strong&gt;hands-on experience&lt;/strong&gt;. There are plenty of possibilities in the &lt;a href="https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&amp;amp;all-free-tier.sort-order=asc" rel="noopener noreferrer"&gt;AWS Free Tier&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheduling The Exam
&lt;/h3&gt;

&lt;p&gt;I personally didn't schedule my exam until I had completed all my learning, hands-on, practice exams, etc. However, everyone is different, therefore you could schedule your exam after a few days (7–14) when you see how are you progressing, this is not required, only an option for those that want to hold themselves accountable. Doing so can help determine a learning pace for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vouchers and Providers
&lt;/h3&gt;

&lt;p&gt;You have basically 2 providers for scheduling the exam:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pearson VUE&lt;/li&gt;
&lt;li&gt;PSI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I immediately recommend Pearson VUE, trust me. Pearson VUE provides taking the exam online and I wanted to take it from home. I have tried PSI in the past and even to this date, they are a headache for me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Time - Extra 30 Mins
&lt;/h3&gt;

&lt;p&gt;If you are not a native English speaker, you can get yourself an extra 30 minutes for taking an exam. I found this really useful, however, I do speak English as my native language and didn't feel I needed the extra time. You can request this via &lt;strong&gt;Exam accommodations&lt;/strong&gt;, and pick &lt;strong&gt;ESL + 30 MINUTES&lt;/strong&gt; one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Push Through
&lt;/h3&gt;

&lt;p&gt;When going through the resources, be sure you understand all the topics. If you don’t, check it again or try to search for an answer. Try to keep notes of all relevant pieces of information. The &lt;em&gt;SAA-C03&lt;/em&gt; covers a vast area of topics. Be sure that you master these topics to the best of your ability, Here is a short list of major topics in the &lt;em&gt;SAA-C03&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;EC2&lt;/strong&gt; – As the most fundamental compute service offered by AWS, you should know about EC2 inside out.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lambda&lt;/strong&gt; – Lambda is the common service used for serverless applications. Study how it is integrated with other AWS services to build a full-stack serverless app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Elastic Load Balancer&lt;/strong&gt; – Load balancing is very important for a highly available system. Study the different types of ELBs, and the features each of them supports.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Auto Scaling&lt;/strong&gt; – Study what services in AWS can be auto-scaled, what triggers scaling, and how auto-scaling increases/decreases the number of instances.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Elastic Block Store&lt;/strong&gt; – As the primary storage solution of EC2, study the types of EBS volumes available. Also study how to secure, backup, and restore EBS volumes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;S3 / Glacier&lt;/strong&gt; – AWS offers many types of S3 storage depending on your needs. Study what these types are and what differs between them. Also review the capabilities of S3 such as hosting a static website, securing access to objects using policies, lifecycle policies, etc. Learn as much about S3 as you can.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Storage Gateway&lt;/strong&gt; – There are occasional questions about Storage Gateway in the exam. You should understand when and which type of Storage Gateway should be used compared to using services like S3 or EBS. You should also know the use cases and differences between DataSync and Storage Gateway.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;EFS&lt;/strong&gt; – EFS is a service highly associated with EC2, much like EBS. Understand when to use EFS, compared to using S3, EBS, or instance store. Exam questions involving EFS usually ask about the trade-off between cost and efficiency of the service compared to other storage services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RDS / Aurora&lt;/strong&gt; – Know how each RDS database differs from one another, and how they are different from Aurora. Determine what makes Aurora unique, and when it should be preferred over other databases (in terms of function, speed, cost, etc). Learn about parameter groups, option groups, and subnet groups.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DynamoDB&lt;/strong&gt; – The exam includes lots of DynamoDB questions, so read as much about this service as you can. Consider how DynamoDB compares to RDS, Elasticache and Redshift. This service is also commonly used for serverless applications along with Lambda.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Elasticache&lt;/strong&gt; – Familiarize yourself with Elasticache Redis and its functions. Determine the areas/services where you can place a caching mechanism to improve data throughput, such as managing the session state of an ELB, optimizing RDS instances, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;VPC/NACL/Security Groups&lt;/strong&gt; – Study every service that is used to create a VPC (subnets, route tables, internet gateways, nat gateways, VPN gateways, etc). Also, review the differences between network access control lists and security groups, and during which situations they are applied.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Route 53&lt;/strong&gt; – Study the different types of records in Route 53. Study also the different routing policies. Know what hosted zones and domains are.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IAM&lt;/strong&gt; – Services such as IAM Users, Groups, Policies, and Roles are the most important to learn. Study how IAM integrates with other services and how it secures your application through different policies. Also, read on the best practices when using IAM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CloudWatch&lt;/strong&gt; – Study how monitoring is done in AWS and what types of metrics are sent to CloudWatch. Also read up on Cloudwatch Logs, CloudWatch Alarms, and the custom metrics made available with CloudWatch Agent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CloudTrail&lt;/strong&gt; – Familiarize yourself with how CloudTrail works, and what kinds of logs it stores as compared to CloudWatch Logs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kinesis&lt;/strong&gt; – Read about Kinesis sharding and Kinesis Data Streams. Have a high-level understanding of how each type of Kinesis Stream works.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CloudFront&lt;/strong&gt; – Study how CloudFront helps speed up websites. Know what content sources CloudFront can serve from. Also, check the kinds of certificates CloudFront accepts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SQS&lt;/strong&gt; – Gather info on why SQS is helpful in decoupling systems. Study how messages in the queues are being managed (standard queues, FIFO queues, dead letter queues). Know the differences between SQS, SNS, SES, and Amazon MQ.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SNS&lt;/strong&gt; – Study the function of SNS and what services can be integrated with it. Also, be familiar with the supported recipients of SNS notifications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SWF&lt;/strong&gt; / CloudFormation / OpsWorks – Study how these services function. Differentiate the capabilities and use cases of each of them. Have a high-level understanding of the kinds of scenarios they are usually used in.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Practice Exams
&lt;/h3&gt;

&lt;p&gt;No matter how many times you listen for the video course, it is really hard to pass the exam without trying to solve practice exams. Do the &lt;strong&gt;practice exams&lt;/strong&gt;! If you chose to complete A Cloud Guru's &lt;a href="https://learn.acloud.guru/course/certified-solutions-architect-associate/overview" rel="noopener noreferrer"&gt;AWS Certified Solutions Architect - Associate (SAA-C02)&lt;/a&gt; course, they provide &lt;strong&gt;1&lt;/strong&gt; practice exam. However, the best practice exams for the SAA-C03 are provided by John Bonso's Tutorial Dojo &lt;a href="https://portal.tutorialsdojo.com/courses/aws-certified-solutions-architect-associate-practice-exams/" rel="noopener noreferrer"&gt;AWS Certified Solutions Architect Associate Practice Exams SAA-C02/SAA-C03 2022&lt;/a&gt;. They provide &lt;strong&gt;6&lt;/strong&gt; practice exams that are made to be more difficult than the actual AWS SAA-C03 exam and in my opinion, they definitely are. I have used Tutorial Dojo's practice exam to prepare for all my certifications so far, they are highly recommended by me!&lt;/p&gt;

&lt;p&gt;For all the certificates I passed so far, I had worse results on the practice exams than on the real exam. That was also the case with this one.&lt;/p&gt;

&lt;p&gt;Once you are done with a practice exam, try to &lt;strong&gt;revisit all the questions&lt;/strong&gt; and &lt;strong&gt;explanations&lt;/strong&gt;. When I say all, I mean the ones with &lt;strong&gt;correct&lt;/strong&gt; and &lt;strong&gt;incorrect&lt;/strong&gt; answers. Try to memorize some important facts you notice from the explanations. That will probably be useful for the exam. &lt;strong&gt;Do all of the practice exams&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be aware of the words &lt;strong&gt;cost-efficient&lt;/strong&gt;, &lt;strong&gt;cost-optimized&lt;/strong&gt;, &lt;strong&gt;high availability&lt;/strong&gt;, &lt;strong&gt;fault tolerance&lt;/strong&gt;! Your answers are depending on these words.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Leading Up To The Exam
&lt;/h3&gt;

&lt;p&gt;When going to the exam, try to &lt;strong&gt;follow all the instructions&lt;/strong&gt; you received in the confirmation mail. When you start, try to &lt;strong&gt;organize your time&lt;/strong&gt; when going through the exam.&lt;/p&gt;

&lt;p&gt;The Pass/Fail status you should get immediately, and score report in a day.&lt;/p&gt;

&lt;p&gt;Special Note: &lt;em&gt;You got this dad, you already know the concepts, just learn the AWS way of doing things and pay special attention to certain keywords, phrases and use cases of services.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading and I hope this has helped whomever reading to achieve their &lt;strong&gt;AWS Certified Solutions Architect — Associate exam (SAA-C03)&lt;/strong&gt; certification.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>linux</category>
      <category>git</category>
    </item>
    <item>
      <title>Do we really need AWS?</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Tue, 24 May 2022 04:59:02 +0000</pubDate>
      <link>https://dev.to/jordan_t/do-we-really-need-aws-3hao</link>
      <guid>https://dev.to/jordan_t/do-we-really-need-aws-3hao</guid>
      <description>&lt;h2&gt;
  
  
  Honestly, do we really need AWS?
&lt;/h2&gt;

&lt;p&gt;Short answer, simply YES!! we do. The ease of mind and cost that AWS and other cloud providers offer is simply nothing short of spectacular. We also have layers and layers of security to protect even government official data, bank data and personally identifiable data (PID). &lt;strong&gt;ALL&lt;/strong&gt; of that for a simple monthly / semi-annual / annual fee that is not stagnant. You pay-as-you-go, which simply means, the more you use or require to use, then the more you pay. The best and also possibly the worst part of this model is the cost, if you know what you are doing or have a team of professionals managing your infrastructure then you can greatly minimize your cost compared to that of creating, setting &amp;amp; configuring your own IT department / IT infrastructure and employing personnel, purchasing hardware, etc. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;However, if you have no clue what you are doing, you can put yourself or business into a financial deficit. Automatic Auto Scaling can be disabled to give the users more control etc but the point is, know what you are doing when you enter the field of cloud computing (AWS / Azure / GCP) or get in contact with people who do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is AWS?
&lt;/h2&gt;

&lt;p&gt;AWS is made up of many different cloud computing products and services. The highly profitable division of Amazon provides servers, storage, networking, remote computing, email, mobile development, and security. AWS can be broken into three main products: EC2, Amazon’s virtual machine service, Glacier, a low-cost cloud storage service, and S3, Amazon’s storage system.&lt;/p&gt;

&lt;p&gt;AWS is so large and present in the computing world that it's far outpaced its competitors. As of the first quarter of 2021, one independent analyst reports AWS has over a third of the market at 32.4%, with Azure following behind at 20%, and Google Cloud at 9%.&lt;/p&gt;

&lt;p&gt;AWS has 81 availability zones in which its servers are located. These serviced regions are divided in order to allow users to set geographical limits on their services (if they so choose), but also to provide security by diversifying the physical locations in which data is held. Overall, AWS spans 245 countries and territories.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PS: These percentages are probably a bit out of date but you get the big picture, AWS is still the king.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Cost Savings with AWS
&lt;/h2&gt;

&lt;p&gt;Amazon took a refreshing approach to pricing its hosting when launching AWS. Every service is "a la carte", meaning you pay for what you use. This makes a lot of sense for server infrastructure, as traffic tends to be very bursty, especially the larger the site is.&lt;/p&gt;

&lt;p&gt;Traditional hardware, for the most part, goes unutilized for 90% of its lifecycle. AWS helps deal with this problem by keeping it cheap during the slow times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling with AWS
&lt;/h2&gt;

&lt;p&gt;As I said earlier, scaling can be wonderful but educate yourself on how to properly scale efficiently based on your requirements or get someone who can perform these tasks for you.&lt;/p&gt;

&lt;p&gt;Since AWS’s cost is modified based on the customers’ usage, start-ups and small businesses can see the obvious benefits of using Amazon for their computing needs. In fact, AWS is great for building a business from the bottom as it provides all the tools necessary for companies to start up with the cloud. For existing companies, Amazon provides low-cost migration services so that your existing infrastructure can be seamlessly moved over to AWS.&lt;/p&gt;

&lt;p&gt;As a company grows, AWS provides resources to aid in expansion. As the business model allows for flexible usage, customers will never need to spend time thinking about whether or not they need to reexamine their computing usage. In fact, aside from budgetary reasons, companies could realistically “set and forget” all their computing needs. &lt;/p&gt;

&lt;h2&gt;
  
  
  Can we trust AWS with our data?
&lt;/h2&gt;

&lt;p&gt;Arguably, Amazon Web Services (AWS) is much more secure than a company hosting its own website or storage. AWS currently has dozens of data centers across the globe that are continuously monitored and strictly maintained. The diversification of the data centers ensures that a disaster striking one region doesn’t cause permanent data loss worldwide. Imagine if Netflix were to have all of its personnel files, content, and backed-up data centralized on-site on the eve of a hurricane. Chaos would ensue.&lt;/p&gt;

&lt;p&gt;In fact, localizing data in an easily identifiable location and where hundreds of people can realistically obtain access is unwise. AWS has tried to keep its data centers as hidden as possible, locating them in out-of-the-way locations and allowing access only on an essential basis.&lt;/p&gt;

&lt;p&gt;The data centers and all the data contained therein are safe from intrusions, and, with Amazon’s experience in cloud services, outages and potential attacks can be quickly identified and easily remedied, 24 hours a day. The same can’t be said for a small company whose computing is handled by a single IT specialist working out of a large office. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The most important feature in AWS is its flexibility. All the services work and communicate together with your application to automatically judge demand and handle it accordingly.&lt;/p&gt;

&lt;p&gt;Combined with the fantastic API and the Amazon Machine Images you create, you can have a completely customized solution that provisions a server instance in under 10 minutes, and is ready to to accept connections once it comes online. Then you can quickly shut down instances when they are no longer needed, making server management a thing of the past.&lt;/p&gt;

&lt;p&gt;AWS is my cloud provider of choice, however, Azure &amp;amp; GCP are both incredible cloud providers, each with their own advantages and disadvantages compared to AWS. My advice is to find one and stick with it and then understand another if you so choose too. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are so many resources out nowadays to help people get started in AWS or resources for experienced cloud individuals as well.&lt;/p&gt;

&lt;p&gt;Beginners - intermediate:&lt;br&gt;
&lt;a href="https://acloudguru.com" rel="noopener noreferrer"&gt;A Cloud Guru&lt;/a&gt; This is where I began my journey by completing my Certified Cloud Practitioner Certification. I recommend them highly for newbies but for people with more experience, I still do recommend them but I have a certain person by the name of Adrian Cantrill that is better at getting more detailed with AWS services.&lt;/p&gt;

&lt;p&gt;Intermediate - Advanced:&lt;br&gt;
&lt;a href="https://learn.cantrill.io/" rel="noopener noreferrer"&gt;Adrian Cantrill&lt;/a&gt; Without this guy, I definitely couldn't have passed any associate level certification. For those just starting out in AWS, I do recommend him, however, take note that his courses are very detailed, not cheap and 100% worth it.&lt;/p&gt;

&lt;p&gt;For those who want a crash course and do not want to spend money just yet or at all, I have a few options that are 100% &lt;strong&gt;FREE&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://explore.skillbuilder.aws/learn" rel="noopener noreferrer"&gt;AWS Skill Builder&lt;/a&gt; These are free lessons offered by AWS themselves.&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=SOTamWNgDKc" rel="noopener noreferrer"&gt;AWS Certified Cloud Practitioner Certification Course (CLF-C01) - Pass the Exam!&lt;/a&gt; offered by FreeCodeCamp.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks for tuning in, see you again next time!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>What does it mean to truly be Server-Less (Serverless)</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Fri, 20 May 2022 02:56:39 +0000</pubDate>
      <link>https://dev.to/jordan_t/what-does-it-mean-to-truly-be-server-less-serverless-dld</link>
      <guid>https://dev.to/jordan_t/what-does-it-mean-to-truly-be-server-less-serverless-dld</guid>
      <description>&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cu4bn9xgvmfrbc6ncgf.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cu4bn9xgvmfrbc6ncgf.gif" alt=" " width="760" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Serverless? What's this all about?
&lt;/h2&gt;

&lt;p&gt;Serverless computing, or more simply Serverless, is a hot topic in the software architecture world. The “Big Three” cloud vendors—Amazon, Google, and Microsoft—are heavily invested in Serverless, and we’ve seen plenty of books, open-source projects, conferences, and software vendors dedicated to the subject. But what is Serverless, and why is (or isn’t) it worth considering?&lt;/p&gt;

&lt;p&gt;OOHH! It most definitely is worth considering, in-fact allow me to explain to you why.&lt;/p&gt;

&lt;p&gt;Serverless was first used to describe applications that significantly or fully incorporate third-party, cloud-hosted applications and services, to manage server-side logic and state. Serverless can also mean applications where server-side logic is still written by the application developer, but, unlike traditional architectures, it’s run in stateless compute containers that are event-triggered, ephemeral (may only last for one invocation), and fully managed by a third party.&lt;/p&gt;

&lt;h2&gt;
  
  
  Okay I get it but can this Serverless thing actually save me money?
&lt;/h2&gt;

&lt;p&gt;Serverless can be more cost-effective than renting or purchasing a fixed quantity of servers, which generally involves significant periods of underutilization or idle time. It can even be more cost-efficient than provisioning an autoscaling group, due to more efficient bin-packing of the underlying machine resources.&lt;/p&gt;

&lt;p&gt;This can be described as pay-as-you-go computing or bare-code as you are charged based solely upon the time and memory allocated to run your code; without associated fees for idle time.&lt;/p&gt;

&lt;p&gt;Immediate cost benefits are related to the lack of operating costs, including: licenses, installation, dependencies, and personnel cost for maintenance, support, or patching. The lack of personnel cost is an &lt;strong&gt;advantage&lt;/strong&gt; that applies broadly too cloud computing.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ij41myjjq1w64ts3q8y.jpeg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ij41myjjq1w64ts3q8y.jpeg" alt=" " width="450" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Elasticity VS Scalability
&lt;/h2&gt;

&lt;p&gt;In addition, a Serverless architecture means that developers and operators do not need to spend time setting up and tuning autoscaling policies or systems; the cloud provider is responsible for scaling the capacity to the demand. As Google puts it: "from prototype to production to planet-scale."&lt;/p&gt;

&lt;p&gt;As cloud native systems inherently scale down as well as up, these systems are known as elastic rather than scalable.&lt;/p&gt;

&lt;p&gt;Small teams of developers are able to run code themselves without the dependence upon teams of infrastructure and support engineers; more developers are becoming DevOps skilled and distinctions between being a software developer or hardware engineer are blurring.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's truly going on behind the scenes?
&lt;/h2&gt;

&lt;p&gt;Now, it's a bit complicated but yet simple, bare with me!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's (FaaS) Function as a Service, Serverless vendors offer compute runtimes, also known as Function as a Service (FaaS) platforms, which execute application logic but do not store data. Common languages supported by serverless runtimes are Java, Python and PHP. Generally, the functions run under isolation boundaries, such as, Linux containers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Serverless Function code should have entirely stateless logic, so redundant instances will not cause inconsistencies for customers. Cloud hosting providers usually have many points-of-presence around the globe. This means that the servers in which an application runs are nearest to all possible end users. The cloud hosting provider will redundantly deploy a Serverless Function to data centers around the world, at the same time. This is good for a developer's customers because their client-side requests will be responded to with as little latency as possible. All of the networking logic is implemented by the cloud provider. Cloud hosting providers that offer Serverless Functions use industry standard best practices for automated code deployment. This means that there is no chance of human error breaking a service during deployment. It allows for fast shipment of new code, with little to no downtime for a web product.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are these FaaS providers I speak of?
&lt;/h2&gt;

&lt;p&gt;Well, truth is, there are many FaaS providers for many different use cases that each have their own individual quirks and personalities associated with them but here are a few:&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Lambda
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt; is a Serverless, event-driven compute service that lets you run code for virtually any type of application or backend service without provisioning or managing servers. You can trigger Lambda from over 200 AWS services and software as a service (SaaS) applications, and only pay for what you use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using Lambda functions is ideal in scenarios where on-demand compute is required e.g. provide compute for operations like file processing like file conversion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Azure Functions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-overview" rel="noopener noreferrer"&gt;Azure Functions&lt;/a&gt; built by Microsoft Azure is a Serverless solution that allows you to write less code, maintain less infrastructure, and save on costs. Instead of worrying about deploying and maintaining servers, the cloud infrastructure provides all the up-to-date resources needed to keep your applications running.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cloud Functions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cloud.google.com/functions/" rel="noopener noreferrer"&gt;Cloud Functions&lt;/a&gt; developed by Google Cloud Platform (GCP), Cloud Functions has a simple and intuitive developer experience. Just write your code and let Google Cloud handle the operational infrastructure. Develop faster by writing and running small code snippets that respond to events. Streamline challenging orchestration problems by connecting Google Cloud products to one another or third party services using events.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Identify what you are trying to accomplish and what is the given criteria that needs to be met. Answering these questions is the simplest way to distinguish between the different Function as a Service (FaaS) vendors to ultimately find the proper solution for your specific use case.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;My beginners recommendation to learning Serverless computing is this crash course by FreeCodeCamp: &lt;a href="https://www.youtube.com/watch?v=DiwS9VTMFv0" rel="noopener noreferrer"&gt;Serverless Functions Course - Create a Serverless API&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My Intermediate - Advanced recommendation would be this 7-hour course by &lt;strong&gt;A Cloud Guru&lt;/strong&gt; called &lt;a href="https://learn.acloud.guru/course/871c7714-6ba7-46f9-9458-b60c779e5a18/overview" rel="noopener noreferrer"&gt;Building a Full-Stack Serverless Application on AWS&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lastly, Serverless is best learnt through doing, so pick a FaaS and work with one, for beginners I recommend AWS Lambda, you can write code using Java, Go, PowerShell, Node.js, C#, Python, and Ruby. It takes time to learn it especially if you are new to cloud and AWS but with a bit of practice, you'll be riding the Serverless bicycle easily.&lt;/p&gt;

&lt;p&gt;Thanks for tuning in and have a great day!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>devops</category>
      <category>aws</category>
      <category>programming</category>
    </item>
    <item>
      <title>Get up and running with Terraform (IaC) Tool</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Wed, 18 May 2022 20:08:37 +0000</pubDate>
      <link>https://dev.to/jordan_t/get-up-and-running-with-terraform-iac-tool-1ofb</link>
      <guid>https://dev.to/jordan_t/get-up-and-running-with-terraform-iac-tool-1ofb</guid>
      <description>&lt;h3&gt;
  
  
  What exactly is this amazing tool?
&lt;/h3&gt;

&lt;p&gt;Infrastructure as code (IaC) tools allow you to manage infrastructure with configuration files rather than through a graphical user interface. IaC allows you to build, change, and manage your infrastructure in a safe, consistent, and repeatable way by defining resource configurations that you can version, reuse, and share.&lt;/p&gt;

&lt;p&gt;Terraform is &lt;strong&gt;HashiCorp&lt;/strong&gt;'s infrastructure as code tool. It lets you define resources and infrastructure in human-readable, declarative configuration files, and manages your infrastructure's lifecycle. Using Terraform has several advantages over manually managing your infrastructure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Terraform can manage infrastructure on multiple cloud platforms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The human-readable configuration language helps you write infrastructure code quickly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Terraform's state allows you to track resource changes throughout your deployments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can commit your configuration to version control to safely collaborate on infrastructure.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How exactly do I manage my Infrastructure?
&lt;/h3&gt;

&lt;p&gt;Terraform plugins called providers let Terraform interact with cloud platforms and other services via their application programming interfaces (APIs). &lt;strong&gt;HashiCorp&lt;/strong&gt; and the Terraform community have written over 1,000 providers to manage resources on Amazon Web Services (AWS), Azure, Google Cloud Platform (GCP), Kubernetes, Helm, GitHub, Splunk, and DataDog, just to name a few.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I deploy my Infrastructure?
&lt;/h3&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F520kavi7aeb2vkz2nm1i.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F520kavi7aeb2vkz2nm1i.png" alt=" " width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Terraform's configuration language is declarative, meaning that it describes the desired end-state for your infrastructure, in contrast to procedural programming languages that require step-by-step instructions to perform tasks. Terraform providers automatically calculate dependencies between resources to create or destroy them in the correct order.&lt;/p&gt;

&lt;p&gt;In order to deploy infrastructure with Terraform, you need to understand a few basic concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Scope - Identify the infrastructure for your project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Author - Write the configuration for your infrastructure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Initialize - Install the plugins Terraform needs to manage the infrastructure. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plan - Preview the changes Terraform needs to manage the infrastructure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apply - Make the planned changes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvaftxvzq5krqajwlsvjr.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvaftxvzq5krqajwlsvjr.png" alt=" " width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Terraform also keeps track of your real infrastructure in a state file, which acts as a source of truth for your environment. Terraform uses the state file to determine the changes to make to your infrastructure so that it will match your configuration.&lt;/p&gt;

&lt;p&gt;Terraform even has it's own cloud!&lt;/p&gt;

&lt;p&gt;Terraform allows you to collaborate on your infrastructure with its remote state backends. When you use Terraform Cloud (free for up to five users), you can securely share your state with your teammates, provide a stable environment for Terraform to run in, and prevent race conditions when multiple people make configuration changes at once.&lt;/p&gt;

&lt;p&gt;Keep learning Terraform and other Infrastructure as Code (IaC) tools! &lt;/p&gt;

&lt;p&gt;To learn more about Infrastructure as Code, check out this blog post: &lt;a href="https://jordantingling.hashnode.dev/what-is-infrastructure-as-code-iac-and-why-do-we-need-it-in-our-lives" rel="noopener noreferrer"&gt;What is Infrastructure as Code?&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Information:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hashicorp&lt;/strong&gt; &lt;strong&gt;Learn&lt;/strong&gt; is a great place to learn Terraform for beginners - intermediate level. They also teach how to use Terraform with cloud providers (AWS / Azure / GCP) &amp;amp; tools like kubernetes, Docker, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://learn.hashicorp.com/" rel="noopener noreferrer"&gt;Hashicorp Learn&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;FreeCodeCamp also have a quick crash course on Terraform but more specifically, "Automate your AWS cloud infrastructure" using Terraform.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=SLB_c_ayRMo&amp;amp;t=5547s" rel="noopener noreferrer"&gt;FreeCodeCamp - Terraform Course - Automate your AWS cloud infrastructure&lt;/a&gt;&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>devops</category>
      <category>aws</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Deepgram x DEV Hackathon Submission - VocalBridge - An AudioBook &amp; Podcast Speech-to-Text application!</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Sat, 02 Apr 2022 22:51:44 +0000</pubDate>
      <link>https://dev.to/jordan_t/deepgram-x-dev-hackathon-submission-vocalbridge-an-audiobook-podcast-speech-to-text-application-50fe</link>
      <guid>https://dev.to/jordan_t/deepgram-x-dev-hackathon-submission-vocalbridge-an-audiobook-podcast-speech-to-text-application-50fe</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywkqawcq7tjwxf19he7n.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywkqawcq7tjwxf19he7n.gif" alt=" " width="200" height="130"&gt;&lt;/a&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6c9yhhx6s4uznr3qew19.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6c9yhhx6s4uznr3qew19.jpg" alt=" " width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm a Cloud enthusiast (&lt;strong&gt;AWS&lt;/strong&gt; primarily) and student at the University of London (&lt;em&gt;BSc Computer Science&lt;/em&gt;). I'm new to Deepgram and their Speech-to-Text API based on deep learning and AI, however, I'm not new to app and website development. I have knowledge and experience designing and building web &amp;amp; mobile applications and integrating native &amp;amp; non-native API's into them. From concept/sketches/wireframes to UI/UX design and further into production or development.&lt;/p&gt;

&lt;p&gt;I decided to participate in the "Innovative Ideas" category of the Deepgram Hackathon on DEV simply out of curiosity and innovation. I wanted to create an application that would solve a problem that I have, in a very simple manner. The problem is, there are times I want to listen to an AudioBook or Podcasts or even both but I don't have 2-3 or even 4+ hours to be listening and even if I did have that amount of time, my brain would be fried by the end of it and I probably wouldn't have retained much. I wanted to create a solution for this, what if I could use "keywords or/and phrases" as an input into an application? That is able to give me the most essential information relating to my given "keywords or/and phrases" in a small concise manner, maybe 2 or 3 paragraphs if I'm in a hurry or possibly a page or 2 if I have time. That was the simple thought process I had when creating "&lt;strong&gt;VocalBridge&lt;/strong&gt;". I'm not sure of the small details of the "how" I could make this happen with Deepgram, that is why, this application is in the "Innovative Ideas" category of the Deepgram + Dev.to Hackathon.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4r4gyzkxjwvzehvbhhsu.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4r4gyzkxjwvzehvbhhsu.jpg" alt=" " width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  My Deepgram Use-Case
&lt;/h3&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8oo3f2v0jeyxztd9v9r.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8oo3f2v0jeyxztd9v9r.jpg" alt=" " width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/j4CoaYva1aNCAxsATU/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/j4CoaYva1aNCAxsATU/giphy.gif" width="480" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;—&lt;/p&gt;

&lt;p&gt;This project was created as an application that would integrate with Deepgram. &lt;strong&gt;VocalBridge&lt;/strong&gt; offers a huge range of &lt;em&gt;&lt;strong&gt;AudioBooks &amp;amp; Podcasts&lt;/strong&gt;&lt;/em&gt; to offer children and parents. I was inspired by the idea of reading &lt;em&gt;bite-sized&lt;/em&gt; chunks of information on-the-go in a matter of a minute or two from an AudioBook and/or Podcast that is usually 1 or 2+ hours of audio content. There are solutions out there that can fulfil this task in a similar manner, however, &lt;strong&gt;VocalBridge&lt;/strong&gt; is able to search and transcribe &lt;em&gt;intelligently&lt;/em&gt; the most "important" phrases or lines of these audio sources and transcribe them in an &lt;em&gt;orderly&lt;/em&gt; way that is not only pleasing to the eyes of the user but also sensible and intuitive just as if it was written that way in that specific order even though it was not. That is the "secret sauce" of the application that is &lt;strong&gt;VocalBridge&lt;/strong&gt;, even though this is only a concept, I am sure that this application would be a life saver for persons that are on-the-go and simply want a brief synopsis of the actual content within the AudioBook and/or Podcast, not only the descriptive summary provided by the author or distributor/provider of the AudioBook and/or Podcast.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1eolyrycamwibl5h8s8o.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1eolyrycamwibl5h8s8o.jpg" alt=" " width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Dive into Details
&lt;/h3&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxm4igtgwyz3sdva0xqvj.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxm4igtgwyz3sdva0xqvj.jpg" alt=" " width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;—&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VocalBridge&lt;/strong&gt; is pretty much a simple idea that was created to solve a simple problem for so many individuals that are on-the-go and need that &lt;em&gt;bite-sized&lt;/em&gt; chunk of information and don't have hours on end to listen to a full blown AudioBook and/or Podcast. This project is suitable for people of all races, ages and religions. It would be beneficial for persons 16-28 years old, that are usually going to school with assignments, an AudioBook or Podcast may contain crucial information for them which they can make good use of and individuals that are 20-45 years old that are usually working, have children or other responsibilities and would like to gain the information within an AudioBook or Podcast but don't have the hours required to listen to these audio sources.&lt;/p&gt;

&lt;p&gt;Children would also benefit greatly from the services of &lt;strong&gt;VocalBridge&lt;/strong&gt;. By reading kids AudioBooks and/or Podcasts, kids could gradually begin or continue learning and understanding words and phrases of songs or poems within these AudioBooks and/or Podcasts. &lt;strong&gt;VocalBridge's&lt;/strong&gt; idea with the help of Deepgram, is made to be the transcription bridge from these various audio sources to text and provide an everyday solution for the issue of having to listen an entire AudioBook or Podcast to learn the true meaning within it. VocalBridge aims to reduce the time needed to accomplish this task into a matter of minutes for millions of persons regardless of their age, religion, and race.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbey8q1fvyn5qix8yrqxx.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbey8q1fvyn5qix8yrqxx.jpg" alt=" " width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;—&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50oifgeuypyitpvd6n6c.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50oifgeuypyitpvd6n6c.jpg" alt=" " width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, &lt;strong&gt;VocalBridge&lt;/strong&gt; was an extremely fun "Innovative Ideas" challenge mobile application project. I'm an &lt;strong&gt;AWS&lt;/strong&gt; guy so if I was to actually build this mobile application, There definitely would be some type of incorporation with &lt;strong&gt;AWS&lt;/strong&gt; within this mobile application. There would also be a web application built for users that prefer a laptop/desktop experience rather than a mobile experience. Lastly, &lt;strong&gt;VocalBridge&lt;/strong&gt; was a treat to create, this application is indeed a prototype, but it was interesting to create a simple problem solver. Thank you Deepgram + Dev.to for the Hackathon!&lt;/p&gt;

&lt;p&gt;Here is a link to the prototype of VocalBridge, please keep in mind that this is a "prototype", not a real working application. Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cloud.protopie.io/p/73a7b2d6bb" rel="noopener noreferrer"&gt;https://cloud.protopie.io/p/73a7b2d6bb&lt;/a&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fju3957pf1tfaperey6bt.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fju3957pf1tfaperey6bt.jpg" alt=" " width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hackwithdg</category>
      <category>uiux</category>
      <category>app</category>
      <category>uidesign</category>
    </item>
    <item>
      <title>Cloud Resume Challenge - My Journey</title>
      <dc:creator>Jordan Tingling</dc:creator>
      <pubDate>Thu, 03 Mar 2022 17:53:00 +0000</pubDate>
      <link>https://dev.to/jordan_t/cloud-resume-challenge-my-journey-241e</link>
      <guid>https://dev.to/jordan_t/cloud-resume-challenge-my-journey-241e</guid>
      <description>&lt;h2&gt;
  
  
  Who Am I?
&lt;/h2&gt;

&lt;p&gt;I'm a Cloud enthusiast (AWS primarily) and student at the &lt;a href="https://london.ac.uk/" rel="noopener noreferrer"&gt;University of London &lt;/a&gt; &lt;em&gt;(BSc Computer Science)&lt;/em&gt;. I do have experience in front-end and back-end engineering, however, this was a step in a new direction that allowed me to get my hands really &lt;strong&gt;&lt;em&gt;cloudy&lt;/em&gt;&lt;/strong&gt; with AWS.&lt;/p&gt;

&lt;p&gt;My journey through learning AWS was surely an impulsive one, It began with ACG &lt;a href="https://acloudguru.com/" rel="noopener noreferrer"&gt;A Cloud Guru&lt;/a&gt; which I pay massive respect to for starting my journey into the cloud. I stumbled upon the &lt;strong&gt;Cloud Resume Challenge&lt;/strong&gt; through (Youtube/Linkedin/Reddit) by &lt;strong&gt;Forest Brazeal&lt;/strong&gt; (Cloud Architect, AWS Serverless Hero). Here is some information about the challenge &lt;a href="https://cloudresumechallenge.dev/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am definitely late to the party, (the last date set by Forrest Brazeal on this challenge was 31-July-2020) due to my preparation for AWS certifications, however, I still wanted to give it a try. I would also like to thank Alex  Eversmeyer, as I referred his &lt;a href="https://alexeversmeyer.com/post/11" rel="noopener noreferrer"&gt;blog&lt;/a&gt; and Github repos, whenever I needed assistance.&lt;/p&gt;

&lt;h1&gt;
  
  
  Let's Get To It!
&lt;/h1&gt;

&lt;h3&gt;
  
  
  AWS Certification
&lt;/h3&gt;

&lt;p&gt;Being new to the world of AWS and cloud computing, I achieved the AWS Certified Practioner Certification in Sept 2021. I then went on to achieve the AWS Certified Solutions Architect Associate (Nov 2021), and AWS Certified Developer Associate (Dec 2021), currently, I am preparing for the AWS Certified Solution Architect Professional. Massive shoutout to &lt;strong&gt;Adrian Cantrill&lt;/strong&gt; for his in-depth and hands-on &lt;a href="https://learn.cantrill.io/" rel="noopener noreferrer"&gt;courses&lt;/a&gt; and labs. &lt;strong&gt;ACG&lt;/strong&gt; gave me the introduction to the cloud, however, &lt;strong&gt;Adrian&lt;/strong&gt; pushed me even further into understanding AWS technologies at a deeper level. &lt;/p&gt;

&lt;h3&gt;
  
  
  Front-End (HTML/CSS/JS)
&lt;/h3&gt;

&lt;p&gt;I tried to keep it as minimalistic as possible. I have front-end experience, however, I wanted to focus more on the technologies which make up the bulk of this challenge and not &lt;em&gt;tinkering&lt;/em&gt; with CSS all day long. The HTML page would also be linked to a JS file that contains the JavaScript snippet which will update and fetch the visitor count from the "back end" (DynamoDB, Lambda, API Gateway).&lt;/p&gt;

&lt;h3&gt;
  
  
  Static S3 Website
&lt;/h3&gt;

&lt;p&gt;Based on the knowledge I acquired during the preparation of AWS certifications, hosting a static website on S3 and using CloudFront for content distribution was easy (CloudFront even provides you with an automatic "CloudFront SSL Certification". I purchased a domain name using AWS Route 53 and set up my hosted zone and configured it to use the CloudFront distribution. Also, I made use of AWS Certification Manager(ACM) to procure my personal SSL certificate for the site.&lt;/p&gt;

&lt;p&gt;Here is a brief overview of the architecture, Thanks &lt;a href="https://dev.to/luisyonaldo"&gt;Luis Nuñez&lt;/a&gt; for the diagram.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5z9dx8g75b4j95ab4ni.jpeg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5z9dx8g75b4j95ab4ni.jpeg" alt=" " width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Back-End
&lt;/h3&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hzyug6541eqwhkw8389.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hzyug6541eqwhkw8389.gif" alt=" " width="220" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The backend infrastructure and logic were needed to update and retrieve the "visitor count" from a database table (DynamoDB table) that is needed for the front-end to display this count on the website. The backend involved the use of AWS resources like API Gateway, Lambda, and DynamoDB.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;DynamoDB: DynamoDB is AWS's fast and flexible NoSQL Database service offering for any scale. I created a simple DynamoDB table with one item to store and update the visitor count. A snipped of Python code comes in handy here. The numeric value increments each time you call the DynamoDB table. This operation is implemented in the Lambda function (more details below).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lambda: AWS Lambda is a compute service that lets you run code without provisioning or managing servers. I created a python based Lambda function, which queries the DynamoDB table and updates the visitor count item. I utilized an API call which is made to an API gateway to increment the numeric value (add a visitor counter).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;API Gateway: Amazon API Gateway provides the option to create and manage APIs to back-end systems running on Amazon EC2, AWS Lambda, or any publicly addressable web service. In my case, the API Gateway exposes a REST API Endpoint, which will be called by a Javascript snippet embedded in the front-end HTML page, on every page visit/refresh - to update and fetch the visitor count from the DynamoDB table, through the Lambda function. Enabling CORS (Cross-Origin Resource Sharing) on the API Gateway resource is mandatory to fetch the response back when it is called.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;The concept is quite simple: Each time the website is requested, an API call is made to an API gateway, which in turn maps to a lambda function. This lambda function does nothing else than increment a field in a DynamoDB table. The new counter is returned and displayed on the web page.&lt;/p&gt;

&lt;h1&gt;
  
  
  Back-End (Infrastructure as Code)
&lt;/h1&gt;

&lt;p&gt;Even though the backend is relatively simple and can be assembled in a few minutes in the AWS Console, it's still not the most convenient way, especially if you need to update or delete something. Fortunately, AWS has our back and offers the ability to provision our cloud infrastructure in a number of ways. In this case, we use AWS Serverless Application Model (SAM), an Infrastructure as Code (IaC) solution that allows us to define and build our Serverless application using a single YAML template. Among other things, this allows us to keep and update our infrastructure together with our codebase and, most importantly, to create an application infrastructure that can be reproduced over and over again.&lt;/p&gt;

&lt;p&gt;Here is a brief overview of the architecture, Thanks &lt;a href="https://dev.to/aws-builders"&gt;AWS Community Builders&lt;/a&gt; for the diagram.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;My architecture is slightly different in this case, however, this is a general overlook of similar architecture.&lt;/em&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi6qimdwfk4fcg0kgpvza.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi6qimdwfk4fcg0kgpvza.png" alt=" " width="779" height="637"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Front-End - CI/CD
&lt;/h3&gt;

&lt;p&gt;Even though AWS SAM takes some of the work off my shoulders, currently updating the website still means some manual effort. AWS SAM has to be installed locally, then, the application has to be built and then deployed. All this costs time and should therefore be automated. For front-end CI/CD, I used GitHub Actions to configure AWS credentials, deploy the changes to the S3 bucket (which stores HTML/CSS/Js/images content), and then invalidate the CloudFront distribution. This deployment workflow can then be configured to execute on each push to the master branch, updating the entire application stack without any additional intervention by me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Back-End - CI/CD
&lt;/h3&gt;

&lt;p&gt;A separate GitHub repo was created to store the back-end code, which included the Lambda function, SAM Template, and Python tests. Corresponding GitHub action is created to configure AWS credentials, run python tests, SAM builds and SAM deploy commands. AWS credentials are configured to securely store environment variables such as AWS Login Keys. These credentials are retrieved from secrets defined in the &lt;a href="https://github.com/SirTingling/resumecode" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;. After that, the same steps are performed that would also be executed locally on the developer's PC: build the application with npm and push the folder to S3 via the AWS CLI. Afterward, the CloudFront cache is invalidated so that pushed changes are displayed immediately.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttfed5hacq0pwi2paf9m.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttfed5hacq0pwi2paf9m.gif" alt=" " width="498" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🏅 That's it! The challenge was great, it covers many AWS Services and how to use them together along with programming languages (Js/Python). Overall, it was a great experience, challenging and frustrating at times, especially regarding AWS SAM but it was worth it.&lt;/p&gt;

&lt;p&gt;Big shoutout to: &lt;a href="https://dev.to/aws-builders"&gt;AWS Community Builders&lt;/a&gt; for their extremely helpful resources.&lt;/p&gt;

&lt;p&gt;Here is the final version of my resume:&lt;br&gt;
&lt;a href="https://jtinglingresume.com/index.html" rel="noopener noreferrer"&gt;Jordan_Tingling_Resume&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>cloud</category>
      <category>challenge</category>
    </item>
  </channel>
</rss>
