<?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: David Jesse Odhiambo</title>
    <description>The latest articles on DEV Community by David Jesse Odhiambo (@davjesse).</description>
    <link>https://dev.to/davjesse</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%2F1474563%2Ff18d4cb9-7eba-4774-953a-a0f2350bd6ec.jpeg</url>
      <title>DEV Community: David Jesse Odhiambo</title>
      <link>https://dev.to/davjesse</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/davjesse"/>
    <language>en</language>
    <item>
      <title>Full-Stack Interview Prep #2: XSS (Cross-Site Scripting) Explained Simply (with Go &amp; Node.js Examples)</title>
      <dc:creator>David Jesse Odhiambo</dc:creator>
      <pubDate>Tue, 02 Sep 2025 16:32:55 +0000</pubDate>
      <link>https://dev.to/davjesse/full-stack-interview-prep-2-xss-cross-site-scripting-explained-simply-with-go-nodejs-8ee</link>
      <guid>https://dev.to/davjesse/full-stack-interview-prep-2-xss-cross-site-scripting-explained-simply-with-go-nodejs-8ee</guid>
      <description>&lt;p&gt;You’re in a technical interview. The interviewer leans back and asks:&lt;br&gt;
&lt;em&gt;“How would you protect a web app from Cross-Site Scripting (XSS)?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For a moment, your mind races. You know XSS is common, but how do you explain it clearly under pressure?&lt;/p&gt;

&lt;p&gt;Let’s break it down with a simple example: imagine a user comment box on a blog. Instead of leaving normal feedback, an attacker types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hacked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;If the site displays that comment without filtering or escaping it, the attacker’s code will run in the browser of anyone who visits the page. What should have been a friendly comment section just became a tool for stealing sessions, hijacking accounts, or tricking users into clicking malicious links.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;That’s Cross-Site Scripting in a nutshell: when untrusted input makes its way into a webpage, and browsers treat it as executable code instead of harmless text.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why does this matter? Because XSS is still listed in the &lt;a href="https://owasp.org/www-project-top-ten/" rel="noopener noreferrer"&gt;&lt;strong&gt;OWASP Top 10&lt;/strong&gt;&lt;/a&gt; — which means that even after two decades, it continues to affect real-world applications. From social media platforms to e-commerce sites, XSS has caused data leaks, account takeovers, and reputational damage for companies that overlooked secure coding practices.&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%2Fzlwp1xlcyn0cxtz2e2la.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%2Fzlwp1xlcyn0cxtz2e2la.png" alt="Scripting Explained" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is XSS? (Explained Simply)
&lt;/h2&gt;

&lt;p&gt;Think of XSS like this: imagine a suggestion box at a store. Customers drop in notes with feedback. Most are normal, like &lt;em&gt;“Great service!”&lt;/em&gt; But one prankster slips in a fake note that says &lt;em&gt;“Read this out loud and embarrass yourself.”&lt;/em&gt; The staff reads it, not realizing it’s a trick.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;That’s what Cross-Site Scripting does — only instead of words, the “fake note” is malicious code, and the victim is every user’s browser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  A Plain-English Example
&lt;/h3&gt;

&lt;p&gt;Imagine a blog with a comment section. A normal user writes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;Great&lt;/span&gt; &lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;thanks&lt;/span&gt; &lt;span class="nt"&gt;for&lt;/span&gt; &lt;span class="nt"&gt;sharing&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;But an attacker posts: &lt;code&gt;&amp;lt;script&amp;gt;alert('hacked')&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If the site displays that input without escaping it, the browser doesn’t see it as a comment. It sees it as code to run. The result? Every visitor who loads that page gets an unexpected popup — or worse, the attacker could steal cookies, hijack accounts, or inject fake login forms.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Flow of an XSS Attack
&lt;/h3&gt;

&lt;p&gt;Here’s the basic lifecycle of how XSS sneaks in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;Attacker&lt;/span&gt; &lt;span class="nt"&gt;Input&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nt"&gt;Saved&lt;/span&gt; &lt;span class="nt"&gt;in&lt;/span&gt; &lt;span class="nt"&gt;Database&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nt"&gt;Rendered&lt;/span&gt; &lt;span class="nt"&gt;in&lt;/span&gt; &lt;span class="nt"&gt;HTML&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nt"&gt;Browser&lt;/span&gt; &lt;span class="nt"&gt;Executes&lt;/span&gt; &lt;span class="nt"&gt;Script&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;At first glance, it looks like harmless text. But once it reaches the browser, the line between “data” and “code” becomes indistinguishable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Types of XSS (Quick Overview)
&lt;/h3&gt;

&lt;p&gt;There are three common flavors of XSS:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stored XSS&lt;/strong&gt; → malicious input is saved in the database (e.g., a comment or profile field).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflected XSS&lt;/strong&gt; → the malicious input comes from a URL or form, and the server reflects it back in the response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DOM-based XSS&lt;/strong&gt; → the attack happens entirely in the browser when client-side JavaScript inserts untrusted input into the page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Don’t worry if these terms feel new — we’ll use simple code examples in the next section to make them concrete.&lt;/p&gt;




&lt;h2&gt;
  
  
  XSS in Practice (Bad Examples)
&lt;/h2&gt;

&lt;p&gt;So far we’ve talked about XSS in theory — now let’s see what it looks like in real code.&lt;/p&gt;

&lt;p&gt;Imagine we’re building a simple comment feature for a website. A user types something, we save it, and then we display it back on the page. Straightforward, right? But if we’re not careful, this is exactly where XSS slips in.  &lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ Go Example (Vulnerable Template Rendering)
&lt;/h3&gt;

&lt;p&gt;In Go, if we use the &lt;code&gt;text/template&lt;/code&gt; package or print raw input without escaping, we risk injecting user input directly into the HTML:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handler&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;comment&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"comment"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// ❌ Vulnerable: directly writing unescaped input to the response&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;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;User Comment:&amp;lt;/h1&amp;gt; %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment&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;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now if an attacker visits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8080/?comment=&amp;lt;script&amp;gt;alert('XSS')&amp;lt;/script&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Instead of displaying harmless text, the browser executes the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag, and everyone sees an alert box pop up.&lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ Node.js Example (Express App Rendering Input Directly)
&lt;/h3&gt;

&lt;p&gt;The same issue happens in Node.js if we inject user input straight into the HTML without escaping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// ❌ Vulnerable: directly embedding user input in HTML&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;h1&amp;gt;User Comment:&amp;lt;/h1&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server running on http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;If someone visits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000/?comment=&amp;lt;script&amp;gt;alert('XSS')&amp;lt;/script&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Boom — the browser pops up the alert box again. What should have been &lt;em&gt;“just text”&lt;/em&gt; was treated as code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Key Takeaway&lt;/strong&gt;: This is a simple example of how XSS works in practice. As we saw earlier, it can appear as stored, reflected, or DOM-based attacks — the form changes, but the root cause is always the same: untrusted input being injected into a page without proper handling.&lt;/p&gt;
&lt;/blockquote&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%2Flnnct47ekzc5tn4xy012.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%2Flnnct47ekzc5tn4xy012.png" alt="Preventing XSS" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Prevent XSS (Best Practices)
&lt;/h2&gt;

&lt;p&gt;Now that we’ve seen how XSS sneaks into your program, let’s focus on defense. The good news is: &lt;strong&gt;protecting against XSS doesn’t require magic — just discipline and the right tools.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think of prevention as layers of defense: some fixes are essential, others add extra safety nets. Together, they make your app resilient.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Output Encoding / Escaping
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The golden rule:&lt;/strong&gt; never trust user input when rendering it back to a page. Instead, escape it so the browser treats it as text, not code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  🚨 Vulnerable vs. ✅ Safe (Quick Comparison)
&lt;/h4&gt;

&lt;p&gt;Sometimes, the fix is just one small change — but it makes all the difference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Golang&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;// ❌ Vulnerable: text/template does NOT escape input&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"text/template"&lt;/span&gt;

&lt;span class="c"&gt;// ✅ Safe: html/template auto-escapes &amp;lt;script&amp;gt; and other dangerous tags&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"html/template"&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In Node.js → if you use template engines like EJS, Pug, or Handlebars, they escape output by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Vulnerable: raw string interpolation, user input becomes HTML&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;h1&amp;gt;User Comment:&amp;lt;/h1&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Safe: use a template engine (EJS, Pug, Handlebars)&lt;/span&gt;
&lt;span class="c1"&gt;// Escaping happens by default&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;comment&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interview Tip:&lt;/strong&gt; Be ready to explain that secure defaults (like Go’s html/template or Express template engines) are your best defense. Interviewers love to hear that you understand both the why and the how.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Use Security Libraries
&lt;/h3&gt;

&lt;p&gt;Sometimes you do want to allow limited HTML (like bold or italic tags in a blog comment). In that case, use a sanitization library that strips dangerous tags and attributes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node.js →&lt;/strong&gt; &lt;a href="https://github.com/cure53/DOMPurify?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;DOMPurify&lt;/a&gt; is a battle-tested option (often used with server-side rendering).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go →&lt;/strong&gt; packages like &lt;a href="https://github.com/microcosm-cc/bluemonday?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;bluemonday&lt;/a&gt; provide configurable sanitizers.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Content Security Policy (CSP)
&lt;/h3&gt;

&lt;p&gt;CSP is like a seatbelt: it won’t prevent an accident, but it can reduce the damage. By setting a CSP header, you can tell browsers to only run scripts from trusted sources.&lt;/p&gt;

&lt;p&gt;Example header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Content-Security-Policy: script-src 'self'

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

&lt;/div&gt;



&lt;p&gt;This means: only run JavaScript that comes from my own site, not from injected code.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Input Validation (Secondary Layer)
&lt;/h3&gt;

&lt;p&gt;Validation alone won’t stop XSS (attackers can always craft clever payloads), but it can reduce noise. For example:&lt;/p&gt;

&lt;p&gt;Reject inputs that are clearly invalid for the field (like a birthdate containing &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Limit length of input to reduce payload size.&lt;/p&gt;

&lt;p&gt;Think of this as cleaning the water before it reaches your filters.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Principle of Least Privilege
&lt;/h3&gt;

&lt;p&gt;Finally, even if something slips through, you can reduce the impact by limiting what the attacker can do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cookies →&lt;/strong&gt; mark them HttpOnly and Secure, so even if a script runs, it can’t steal them easily.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database / API access →&lt;/strong&gt; don’t give your web app more permissions than it needs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaway&lt;/strong&gt;:&lt;br&gt;
If you remember only one thing:&lt;br&gt;
&lt;em&gt;Always escape untrusted output.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Everything else — &lt;strong&gt;sanitization, CSP, validation, least privilege&lt;/strong&gt; — are extra shields. But escaping is your first and strongest line of defense.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Interviewers Ask About XSS
&lt;/h2&gt;

&lt;p&gt;At this point, you might be wondering: why does XSS keep showing up in interviews? It’s not because interviewers enjoy watching developers sweat — it’s because this single vulnerability reveals a lot about how you think as an engineer.&lt;/p&gt;

&lt;p&gt;Here’s what they’re really looking for:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Do you know client-side vulnerabilities, not just backend ones?
&lt;/h3&gt;

&lt;p&gt;Many developers focus only on the server. But XSS is a reminder that security isn’t just about the database — the browser is part of the attack surface too.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Can you explain attack → defense clearly?
&lt;/h3&gt;

&lt;p&gt;It’s one thing to say &lt;em&gt;“XSS is bad.”&lt;/em&gt; It’s another to walk through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how it works (untrusted input becomes code), and&lt;/li&gt;
&lt;li&gt;how to fix it (escape output, sanitize input, use CSP).
That step-by-step clarity is exactly what interviewers want to hear.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. How do you handle pressure?
&lt;/h3&gt;

&lt;p&gt;Sometimes the question isn’t asked in a calm, textbook way. Instead, you’ll hear things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;“What’s the difference between stored and reflected XSS?”&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“How would you prevent XSS in your favorite language?”&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Can you give me a real-world consequence of XSS?”&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These versions test whether you can stay calm, think out loud, and structure your answer under pressure.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Do you understand the real-world impact?
&lt;/h3&gt;

&lt;p&gt;Interviewers want to know if you see beyond code snippets. For example, XSS can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Steal a user’s session cookies.&lt;/li&gt;
&lt;li&gt;Hijack an account.&lt;/li&gt;
&lt;li&gt;Inject fake login forms to harvest passwords.&lt;/li&gt;
&lt;li&gt;Damage a company’s reputation when users lose trust.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  A Simple Answer Framework
&lt;/h2&gt;

&lt;p&gt;Here’s a 3-step structure you can use to answer almost any XSS interview question:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Define it simply
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;&amp;gt; “XSS happens when untrusted input is inserted into a webpage and executed as code in the browser.”&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Give a quick example
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;&amp;gt; “For instance, if a site displays alert(&amp;amp;#39;hacked&amp;amp;#39;) from a comment box without escaping, that code will run for every visitor.”&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Show how to prevent it
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;&amp;gt; “The fix is to always escape output (Go’s html/template, Node’s template engines), sanitize inputs, and enforce a Content Security Policy as backup.”&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The key takeaway:&lt;/strong&gt; XSS questions aren’t trivia. They’re a way for interviewers to test your security fundamentals, your ability to reason through problems, and your communication skills under pressure.&lt;/p&gt;
&lt;/blockquote&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%2F9htdpe2l38zolmzm3arq.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%2F9htdpe2l38zolmzm3arq.png" alt="Pop Quiz" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pop Quiz: Test Your Understanding
&lt;/h2&gt;

&lt;p&gt;Before we wrap up, let’s do a quick self-check. These aren’t trick questions — just simple ways to reinforce what you’ve learned. Try answering them in the comments to share your take and help others learn too.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Scenario Check
&lt;/h3&gt;

&lt;p&gt;Imagine a blog comment box that doesn’t escape &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags. What happens if an attacker submits this as a comment?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hacked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. True or False
&lt;/h3&gt;

&lt;p&gt;Input validation alone is enough to completely stop XSS attacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Fix the Code (Go)
&lt;/h3&gt;

&lt;p&gt;Here’s a vulnerable Go snippet:&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;p&amp;gt;%s&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Rewrite it using a safe approach so that &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags are not executed in the browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Fix the Code (Node.js)
&lt;/h3&gt;

&lt;p&gt;Here’s a similar vulnerable snippet in Node.js (Express):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Rewrite it using a templating engine or escaping function to prevent XSS.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; Don’t worry about being “perfect.” The goal is to practice identifying vulnerable code and thinking of safer alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion / Call to Action
&lt;/h2&gt;

&lt;p&gt;Cross-Site Scripting (XSS) is dangerous because it hijacks user trust — but it’s also preventable with a few simple practices. If you remember one rule, let it be this: never trust unescaped user input in your HTML output. Add layers like sanitization, CSP, and cookie protections, and you’ll be ahead of most real-world vulnerabilities.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XSS happens when untrusted input is executed as code in the browser.&lt;/li&gt;
&lt;li&gt;Output escaping (Go html/template, Node templating engines) is your first line of defense.&lt;/li&gt;
&lt;li&gt;Sanitization libraries (like DOMPurify) help when HTML input is unavoidable.&lt;/li&gt;
&lt;li&gt;Content Security Policy (CSP) and secure cookie flags (HttpOnly, Secure) provide safety nets.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Your Next Steps&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Audit your code for any direct string interpolation into HTML.&lt;/li&gt;
&lt;li&gt;Use safe defaults: html/template in Go, EJS/Pug/Handlebars in Node.&lt;/li&gt;
&lt;li&gt;Add or tighten a CSP header for your app.&lt;/li&gt;
&lt;li&gt;Set cookies with HttpOnly and Secure to limit exposure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Over to You&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Have you ever discovered an XSS issue in your own project — maybe even by accident?&lt;/p&gt;

&lt;p&gt;What fixes or defensive tricks have you found most useful? Drop your answers and quiz responses in the comments — let’s learn from each other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Up Next in the Series&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This was Full-Stack Interview Prep #2: XSS Explained Simply (with Go &amp;amp; Node.js Examples), a follow up to &lt;a href="https://dev.to/davjesse/full-stack-interview-prep-1-sql-injection-explained-simply-with-go-nodejs-examples-lg6"&gt;#1: SQL Injection Explained Simply&lt;/a&gt;.&lt;br&gt;
Stay tuned for #3: CSRF (Cross-Site Request Forgery) Explained Simply with Go &amp;amp; Node.js Examples.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>html</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Full-Stack Interview Prep #1: SQL Injection Explained Simply (with Go &amp; Node.js Examples)</title>
      <dc:creator>David Jesse Odhiambo</dc:creator>
      <pubDate>Wed, 27 Aug 2025 15:06:54 +0000</pubDate>
      <link>https://dev.to/davjesse/full-stack-interview-prep-1-sql-injection-explained-simply-with-go-nodejs-examples-lg6</link>
      <guid>https://dev.to/davjesse/full-stack-interview-prep-1-sql-injection-explained-simply-with-go-nodejs-examples-lg6</guid>
      <description>&lt;p&gt;You’re in a technical interview. The interviewer looks up from their notes and asks: &lt;em&gt;“How would you protect a login form from SQL injection?”&lt;/em&gt; In that moment, your answer isn’t just about passing the interview — it’s about whether you understand one of the web’s most common security threats.&lt;/p&gt;

&lt;p&gt;SQL Injection is when an attacker sneaks malicious input into a database query. Imagine a login form where you enter a username and password. Normally, the database should only check if those values exist. But if the code isn’t secure, an attacker could type something like &lt;code&gt;admin' OR '1'='1&lt;/code&gt;. The database, confused, runs it as a valid command — and suddenly the attacker is logged in without ever knowing the real password.&lt;/p&gt;

&lt;p&gt;More technically, &lt;strong&gt;SQL Injection happens when untrusted user input is placed directly inside an SQL query string&lt;/strong&gt;. This breaks the separation between code and data, allowing attackers to alter the query’s logic — for example, turning a simple credential check into a query that returns every user in the database.&lt;/p&gt;

&lt;p&gt;There’s a reason this topic keeps coming up in interviews: it’s not just theory. SQL Injection is still in the OWASP Top 10 after more than two decades, and a single overlooked query has cost companies millions in data breaches and lost trust.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;💡 This article is the first in my Full-Stack Interview Prep series, where I break down common interview questions into simple explanations, real-world scenarios, and practical code examples in Go and Node.js. Each part of the series focuses on one core concept — from security topics like SQL Injection, XSS, and CSRF, to backend fundamentals like caching and authentication, and even frontend/system design essentials. My goal is to make these topics easier for developers preparing for interviews, while also showing recruiters how I approach teaching, collaboration, and writing clean, secure code.&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%2Fbcufjg86cv0hibg6wqt2.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%2Fbcufjg86cv0hibg6wqt2.png" alt="What is SQL Injection" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is SQL Injection? (Explained Simply)
&lt;/h2&gt;

&lt;p&gt;Now that we’ve set the stage, let’s break down what SQL Injection really is — step by step, and in plain language.&lt;/p&gt;

&lt;p&gt;Think of your SQL query as a conversation with the database. Normally, you ask a simple question like:&lt;br&gt;
 &lt;em&gt;“Does a user named John exist with this password?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But with SQL Injection, an attacker interrupts that conversation and sneaks in their own instructions. Instead of just typing John, they might type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;John&lt;/span&gt;&lt;span class="s1"&gt;' OR '&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="s1"&gt;'='&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That small addition changes the meaning of the query. The database is tricked into thinking the condition is always true — which means the attacker could log in without knowing any real password.&lt;/p&gt;

&lt;p&gt;Here’s a simplified SQL example to show what happens behind the scenes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Normal query&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'John'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'secret'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Injected query&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'John'&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="s1"&gt;'1'&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'1'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'secret'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the injected version, '1'='1' is always true. That makes the whole condition true, and the database happily returns a row — even if the password is wrong.&lt;/p&gt;

&lt;p&gt;This is the essence of SQL Injection: &lt;strong&gt;when user input isn’t handled safely, it can alter the logic of a database query in dangerous ways&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  SQL Injection in Practice (Bad Examples)
&lt;/h2&gt;

&lt;p&gt;Let’s see how SQL Injection sneaks in through everyday code. These examples might look harmless, but they show what happens when user input is inserted directly into a query string.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vulnerable Example in Go
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ❌ Vulnerable code&lt;/span&gt;
&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"SELECT * FROM users WHERE username='"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"' AND password='"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"'"&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this looks like a straightforward way to check if a user exists. But notice how we’re building the query by &lt;strong&gt;concatenating strings&lt;/strong&gt;. That means whatever the user types in &lt;code&gt;username&lt;/code&gt; or &lt;code&gt;password&lt;/code&gt; gets injected directly into the SQL command.&lt;/p&gt;

&lt;p&gt;Now imagine the attacker types this as the username:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;admin&lt;/span&gt;&lt;span class="s1"&gt;' OR '&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="s1"&gt;'='&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The query becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'admin'&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="s1"&gt;'1'&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'1'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'whatever'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since &lt;code&gt;'1'='1'&lt;/code&gt; is always true, the database happily returns a row — and the attacker is logged in without knowing a real password.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vulnerable Example in Node.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Vulnerable code&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`SELECT * FROM users WHERE username = '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' AND password = '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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 same issue appears here. By embedding &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; directly in the query string, we’re giving attackers a chance to alter the logic.&lt;/p&gt;

&lt;p&gt;If the attacker enters the same payload (&lt;code&gt;admin' OR '1'='1&lt;/code&gt;), the query becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="s1"&gt;'1'&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'1'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'doesntmatter'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, the condition always evaluates to true, so the attacker bypasses authentication.&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%2F1lpnsdjgmvb7lfeof3k9.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%2F1lpnsdjgmvb7lfeof3k9.png" alt="Preventing SQL Injection" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Prevent SQL Injection (Best Practices)
&lt;/h2&gt;

&lt;p&gt;The good news is that SQL Injection is preventable. With a few best practices, you can protect your application — and your users — from this attack. Let’s walk through the most important defenses.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Prepared Statements / Parameterized Queries
&lt;/h3&gt;

&lt;p&gt;SQL Injection prevention starts with using &lt;strong&gt;prepared statements&lt;/strong&gt;, sometimes called &lt;strong&gt;parameterized queries&lt;/strong&gt;. Instead of directly inserting user input into a string, you pass the input as parameters. This keeps data separate from the query logic.&lt;/p&gt;

&lt;p&gt;In Go (using &lt;code&gt;database/sql&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="c"&gt;// ✅ Safe code using parameters&lt;/span&gt;
&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"SELECT * FROM users WHERE username=$1 AND password=$2"&lt;/span&gt;
&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;$1&lt;/code&gt; and &lt;code&gt;$2&lt;/code&gt; act as placeholders. The database ensures that username and password are treated as values, not code.&lt;/p&gt;

&lt;p&gt;In Node.js (using &lt;code&gt;mysql2&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ Safe code using parameters&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM users WHERE username = ? AND password = ?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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;?&lt;/code&gt; placeholders ensure the same protection. No matter what an attacker types, it will always be treated as data, never as part of the SQL command.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ ORMs &amp;amp; Query Builders
&lt;/h3&gt;

&lt;p&gt;Another way to reduce risk is by using an &lt;strong&gt;ORM (Object-Relational Mapper)&lt;/strong&gt; or &lt;strong&gt;query builder&lt;/strong&gt;. Tools like &lt;strong&gt;GORM (Go)&lt;/strong&gt; or &lt;strong&gt;Prisma (Node.js)&lt;/strong&gt; abstract away SQL and usually handle parameterization for you by default.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Prisma in Node.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ORMs aren’t foolproof, but they help developers write cleaner queries with safer defaults.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Input Validation &amp;amp; Escaping
&lt;/h3&gt;

&lt;p&gt;While prepared statements are your primary shield, it’s also good practice to validate input. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure usernames only contain expected characters (letters, numbers).&lt;/li&gt;
&lt;li&gt;Validate that email fields actually look like emails.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn’t enough on its own — but combined with parameterization, it makes your app much harder to exploit.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Principle of Least Privilege
&lt;/h3&gt;

&lt;p&gt;Even with secure queries, you should avoid giving your database user more permissions than it needs. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your application’s database account should not have rights to drop tables or manage users.&lt;/li&gt;
&lt;li&gt;Restrict it to just what the app needs: &lt;code&gt;SELECT&lt;/code&gt;, &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This way, even if something goes wrong, the damage is limited.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Interviewers Ask This Question
&lt;/h2&gt;

&lt;p&gt;So why do interviewers love asking about SQL Injection? It’s not just to check if you’ve memorized a definition. They use this question to see how you think, how you explain, and how you handle pressure.&lt;/p&gt;

&lt;p&gt;Here are the main things they’re looking for:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔹 1. Core Knowledge
&lt;/h3&gt;

&lt;p&gt;Do you understand what SQL Injection is and why it matters? Interviewers want to confirm that you’re aware of common web vulnerabilities and can recognize insecure code when you see it.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔹 2. Communication Skills
&lt;/h3&gt;

&lt;p&gt;Can you explain the attack and its prevention clearly? Being able to walk through attack → defense in a way others can follow shows that you’re not only a good developer, but also someone who can mentor teammates and document your work.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔹 3. Handling Pressure
&lt;/h3&gt;

&lt;p&gt;Most interviewers won’t stop at a single question. They’ll push a little further to see if you can stay calm and keep your answers structured. For example, they might ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;“What’s SQL Injection?”&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Can you give me an example in your favorite language?”&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“How would you prevent it in Go/Node?”&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“What happens if a company ignores this vulnerability?”&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These follow-ups aren’t designed to trick you — they’re a chance to show that you understand the fundamentals and can adapt your answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pop Quiz!
&lt;/h2&gt;

&lt;p&gt;Before we wrap up, here’s a quick quiz to test your understanding. Don’t worry — this isn’t an exam. The goal is to practice, reinforce the concepts, and maybe even teach others by sharing your answers in the comments.&lt;/p&gt;

&lt;h3&gt;
  
  
  📝 Questions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Concept Check&lt;/strong&gt;&lt;br&gt;
What does the condition OR &lt;code&gt;'1'='1&lt;/code&gt; do when it appears in an SQL query?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. True or False&lt;/strong&gt;&lt;br&gt;
Input validation alone is enough to completely prevent SQL Injection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.0. Fix the Vulnerable Code (Go)&lt;/strong&gt;&lt;br&gt;
Here’s a vulnerable Go query:&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;query&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"SELECT * FROM users WHERE username='"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"' AND password='"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"'"&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How would you rewrite this using a prepared statement to make it safe?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.1. Fix the Vulnerable Code (Node.js)&lt;/strong&gt;&lt;br&gt;
Here’s a vulnerable Node.js query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`SELECT * FROM users WHERE username = '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' AND password = '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="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;Rewrite it using parameterized queries to prevent injection.&lt;/p&gt;

&lt;p&gt;💬 &lt;em&gt;Try answering in the comments. Even if you’re not fully confident, writing out your thought process is one of the best ways to learn — and your answer might help another developer too.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;SQL Injection is one of the simplest attacks to exploit, but also one of the simplest to prevent — as long as we use secure coding practices like prepared statements, validation, and proper permissions.&lt;/p&gt;

&lt;p&gt;I’ll admit — early in my career, I wrote queries just like the vulnerable ones we saw earlier. It’s easy to do without realizing the risk. The important part is learning how to spot these mistakes and fix them before they reach production.&lt;/p&gt;

&lt;p&gt;💬 &lt;em&gt;Have you ever discovered SQL Injection risks in your own code? Share your experience in the comments — your story might help another developer catch the same mistake. And don’t forget to drop your answers to the quiz above; I’ll be checking in to give feedback.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;👉 Next up in this series: &lt;strong&gt;&lt;a href="https://dev.to/davjesse/full-stack-interview-prep-2-xss-cross-site-scripting-explained-simply-with-go-nodejs-8ee"&gt;XSS (Cross-Site Scripting) explained simply with Go &amp;amp; Node.js examples&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At the end of the day, secure coding isn’t just about passing interviews — it’s about protecting real people who trust us with their data.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>fullstack</category>
      <category>database</category>
    </item>
    <item>
      <title>Real-Time Messaging with Go and JavaScript</title>
      <dc:creator>David Jesse Odhiambo</dc:creator>
      <pubDate>Mon, 02 Jun 2025 12:21:01 +0000</pubDate>
      <link>https://dev.to/davjesse/real-time-messaging-with-go-and-javascript-42a3</link>
      <guid>https://dev.to/davjesse/real-time-messaging-with-go-and-javascript-42a3</guid>
      <description>&lt;p&gt;WebSockets allow your frontend and backend to talk &lt;strong&gt;instantly&lt;/strong&gt;, without the old HTTP request/response delay. In this tutorial, we'll show you how to build a &lt;strong&gt;real-time chat application&lt;/strong&gt; using &lt;strong&gt;Go&lt;/strong&gt; on the backend and &lt;strong&gt;JavaScript&lt;/strong&gt; on the frontend.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚀 This is &lt;strong&gt;Part 3&lt;/strong&gt; of the WebSocket series. If you're just joining:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start with &lt;a href="https://dev.to/davjesse/http-vs-websockets-what-every-beginner-needs-to-know-5goi"&gt;Part 1: HTTP vs WebSockets: What Every Beginner Needs Know&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Then check out &lt;a href="https://dev.to/davjesse/how-to-build-a-simple-websocket-server-in-go-step-by-step-guide-4bdi"&gt;Part 2: How to Build a Simple WebSocket Server in Go&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s put all of it to work now.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;We’re building a very basic chat room where users can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send messages using a frontend form&lt;/li&gt;
&lt;li&gt;Receive messages instantly from other users via WebSocket&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tech stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Go (Golang)&lt;/strong&gt; + &lt;a href="https://github.com/gorilla/websocket" rel="noopener noreferrer"&gt;Gorilla WebSocket&lt;/a&gt; backend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML + JavaScript&lt;/strong&gt; frontend&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Backend Setup (Recap)
&lt;/h2&gt;

&lt;p&gt;Here’s the Go server we used in Part 2:&lt;br&gt;
&lt;/p&gt;

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

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

    &lt;span class="s"&gt;"github.com/gorilla/websocket"&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;upgrader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrader&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ReadBufferSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;WriteBufferSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c"&gt;// Allow all connections&lt;/span&gt;
    &lt;span class="n"&gt;CheckOrigin&lt;/span&gt;&lt;span class="o"&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;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="kt"&gt;bool&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;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handleWebSocket&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;conn&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;upgrader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrade&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="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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Upgrade error:"&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="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;conn&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;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;messageType&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="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Read error:"&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;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received: %s&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;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Echo message back to client&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;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messageType&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="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Write error:"&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;break&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;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ws"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handleWebSocket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Server started at http://localhost:8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This server listens for incoming WebSocket connections at &lt;code&gt;/ws&lt;/code&gt;, upgrades the HTTP connection, and echoes back any message it receives.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frontend Code (HTML + JavaScript)
&lt;/h2&gt;

&lt;p&gt;Here’s a minimal frontend you can save as &lt;code&gt;index.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Go WebSocket Chat&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;#messages&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#ccc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;overflow-y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;scroll&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Chat&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"msgInput"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Type a message..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"sendMessage()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Send&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ws://localhost:8080/ws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messagesDiv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;messagesDiv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msgInput&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ol&gt;
&lt;li&gt;The browser opens a WebSocket connection to &lt;code&gt;ws://localhost:8080/ws&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;When you type and click &lt;strong&gt;Send&lt;/strong&gt;, JavaScript sends the message to the Go backend.&lt;/li&gt;
&lt;li&gt;The Go server receives it and immediately echoes it back.&lt;/li&gt;
&lt;li&gt;JavaScript listens for incoming messages and displays them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's a direct two-way pipeline — no reloading, no polling!&lt;/p&gt;




&lt;h2&gt;
  
  
  Debugging Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browser Console Errors&lt;/strong&gt;: Open DevTools (F12) to see if WebSocket failed to connect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CORS Issues?&lt;/strong&gt; Make sure your WebSocket server is on the same origin or add CORS headers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection refused?&lt;/strong&gt; Ensure your server is running on the right port.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Possibilities Beyond Chat
&lt;/h2&gt;

&lt;p&gt;Now that you’ve got WebSockets working, here’s what else you can build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Real-time notifications&lt;/li&gt;
&lt;li&gt;✅ Multiplayer games&lt;/li&gt;
&lt;li&gt;✅ Live dashboards&lt;/li&gt;
&lt;li&gt;✅ Collaborative editors (like Google Docs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And with more tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔐 Add authentication with JWT&lt;/li&gt;
&lt;li&gt;🔁 Handle reconnects with backoff&lt;/li&gt;
&lt;li&gt;⚙️ Scale using Redis pub/sub or message queues&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Where We End
&lt;/h2&gt;

&lt;p&gt;This wraps up our 3-part WebSocket series:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HTTP vs WebSockets: Why it matters&lt;/li&gt;
&lt;li&gt;Building a WebSocket server in Go&lt;/li&gt;
&lt;li&gt;Connecting that server to a live frontend&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From here, you're ready to explore more advanced designs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Broadcasting to many clients&lt;/li&gt;
&lt;li&gt;Creating chat rooms&lt;/li&gt;
&lt;li&gt;Scaling with channels and goroutines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me know in the comments what you're building with Go and WebSockets 👇&lt;/p&gt;




</description>
      <category>go</category>
      <category>javascript</category>
      <category>websocket</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Build a Simple WebSocket Server in Go (Step-by-Step Guide)</title>
      <dc:creator>David Jesse Odhiambo</dc:creator>
      <pubDate>Wed, 28 May 2025 13:40:02 +0000</pubDate>
      <link>https://dev.to/davjesse/how-to-build-a-simple-websocket-server-in-go-step-by-step-guide-4bdi</link>
      <guid>https://dev.to/davjesse/how-to-build-a-simple-websocket-server-in-go-step-by-step-guide-4bdi</guid>
      <description>&lt;p&gt;In the previous article &lt;a href="https://dev.to/davjesse/http-vs-websockets-what-every-beginner-needs-to-know-5goi"&gt;HTTP vs WebSockets: What Every Beginner Needs to Know&lt;/a&gt; we learned about WebSockets and how they power real-time features like chat apps and live dashboards. But how do you actually build one with Go?&lt;/p&gt;

&lt;p&gt;In this beginner-friendly guide, we’ll walk through how to:&lt;/p&gt;

&lt;p&gt;✅ Set up a WebSocket server in Go&lt;br&gt;
✅ Handle real-time messages&lt;br&gt;
✅ Connect to it from a browser using JavaScript&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is &lt;strong&gt;Part 2&lt;/strong&gt; of the series. If you’re new to WebSockets, read Part 1: HTTP vs WebSockets—What Every Beginner Should Know first.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  🔌 What is Gorilla WebSocket?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/gorilla/websocket" rel="noopener noreferrer"&gt;Gorilla WebSocket&lt;/a&gt;&lt;/strong&gt; is a popular Go package that makes working with WebSockets easier.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Actively maintained&lt;/li&gt;
&lt;li&gt;✅ Full control over message handling&lt;/li&gt;
&lt;li&gt;✅ Works well with &lt;code&gt;net/http&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Setting up a WebSocket server in Go with Gorilla WebSocket
&lt;/h2&gt;
&lt;h3&gt;
  
  
  📦 Step 1: Install Gorilla WebSocket
&lt;/h3&gt;

&lt;p&gt;While in your Go project's directory, open your terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/gorilla/websoc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🛠️ Step 2: Build the WebSocket Server
&lt;/h3&gt;

&lt;p&gt;Let’s write a basic WebSocket server in Go.&lt;/p&gt;

&lt;p&gt;Create a file named main.go:&lt;br&gt;
&lt;/p&gt;

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

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

    &lt;span class="s"&gt;"github.com/gorilla/websocket"&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;upgrader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrader&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ReadBufferSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;WriteBufferSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c"&gt;// Allow all connections&lt;/span&gt;
    &lt;span class="n"&gt;CheckOrigin&lt;/span&gt;&lt;span class="o"&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;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="kt"&gt;bool&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;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handleWebSocket&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;conn&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;upgrader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrade&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="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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Upgrade error:"&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="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;conn&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;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;messageType&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="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Read error:"&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;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received: %s&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;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Echo message back to client&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;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messageType&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="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Write error:"&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;break&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;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ws"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handleWebSocket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Server started at http://localhost:8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🌐 Step 3: Simple Frontend (HTML + JavaScript)
&lt;/h3&gt;

&lt;p&gt;Create a file named index.html in the same folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;WebSocket Test&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;WebSocket Echo Client&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"msgInput"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Type a message..."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"sendMessage()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Send&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ws://localhost:8080/ws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;li&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Received: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msgInput&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ▶️ Step 4: Run Your Server
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Run the Go server:
&lt;/li&gt;
&lt;/ol&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;ol&gt;
&lt;li&gt;&lt;p&gt;Open index.html in your browser (just double-click it).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Type a message and click Send — you should see your message echoed back in the browser!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🧪 How It Works
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Your browser connects to /ws using WebSocket protocol.&lt;/li&gt;
&lt;li&gt;Messages are sent to the server.&lt;/li&gt;
&lt;li&gt;The server reads them and echoes them back.&lt;/li&gt;
&lt;li&gt;All communication happens over a persistent connection.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Next Steps?
&lt;/h2&gt;

&lt;p&gt;You’ve just built a real-time WebSocket server with Go! Now imagine what else you can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build a chat app 🗨️&lt;/li&gt;
&lt;li&gt;Add notifications 🔔&lt;/li&gt;
&lt;li&gt;Stream sensor data 📈&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next article, &lt;a href="https://dev.to/davjesse/real-time-messaging-with-go-and-javascript-42a3"&gt;Real-Time Messaging with Go and JavaScript&lt;/a&gt;, we’ll take this further with broadcasting messages to multiple clients (like a real chat room).&lt;/p&gt;

&lt;p&gt;✅ Follow me for more beginner-friendly Go tutorials!&lt;br&gt;
Drop a comment if you have questions, or if you’ve built something cool with WebSockets!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>websocket</category>
      <category>go</category>
      <category>backend</category>
    </item>
    <item>
      <title>HTTP vs WebSockets: What Every Beginner Needs to Know</title>
      <dc:creator>David Jesse Odhiambo</dc:creator>
      <pubDate>Tue, 27 May 2025 00:01:58 +0000</pubDate>
      <link>https://dev.to/davjesse/http-vs-websockets-what-every-beginner-needs-to-know-5goi</link>
      <guid>https://dev.to/davjesse/http-vs-websockets-what-every-beginner-needs-to-know-5goi</guid>
      <description>&lt;p&gt;If you’re learning how the web works—especially as a Go developer—you’ve probably been using REST APIs and exchanging data via JSON. But as soon as you dip your toes into &lt;strong&gt;real-time features&lt;/strong&gt; like live chat, stock tickers, or multiplayer games, you’ll hear about something called &lt;strong&gt;WebSockets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, what are WebSockets? Can they replace HTTP and JSON? And when should you use one over the other?&lt;/p&gt;

&lt;p&gt;Let’s break it down in the simplest way possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  HTTP: The Old Reliable
&lt;/h2&gt;

&lt;p&gt;HTTP (Hypertext Transfer Protocol) is the most common way for browsers and servers to communicate.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The client (like your browser) sends a &lt;strong&gt;request&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The server sends a &lt;strong&gt;response&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The connection &lt;strong&gt;closes&lt;/strong&gt; after each interaction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is perfect for actions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loading a webpage&lt;/li&gt;
&lt;li&gt;Submitting a form&lt;/li&gt;
&lt;li&gt;Fetching JSON data from an API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But what if you need &lt;strong&gt;real-time updates&lt;/strong&gt;? Like getting a new message the moment someone sends it?&lt;/p&gt;

&lt;p&gt;That’s where HTTP falls short.&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%2Fw9x5b6jp8ptbwdj1g12v.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%2Fw9x5b6jp8ptbwdj1g12v.png" alt="HTTP vs Websocket: Connection types" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter WebSockets: Persistent, Real-Time Connections
&lt;/h2&gt;

&lt;p&gt;WebSockets allow a browser and server to open a &lt;strong&gt;persistent connection&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The connection stays open.&lt;/li&gt;
&lt;li&gt;Both sides can send messages &lt;strong&gt;anytime&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;No need to repeatedly ask the server, "Is there anything new?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is called &lt;strong&gt;full-duplex communication&lt;/strong&gt;: both client and server can talk to each other continuously.&lt;/p&gt;

&lt;p&gt;Perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live chats&lt;/li&gt;
&lt;li&gt;Notifications&lt;/li&gt;
&lt;li&gt;Live dashboards&lt;/li&gt;
&lt;li&gt;Multiplayer games&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  WebSocket vs HTTP (with JSON)
&lt;/h2&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;HTTP (JSON)&lt;/th&gt;
&lt;th&gt;WebSockets&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Connection Model&lt;/td&gt;
&lt;td&gt;Request-response&lt;/td&gt;
&lt;td&gt;Persistent, open connection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Format&lt;/td&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;td&gt;JSON / binary / text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server-Initiated Msgs&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overhead&lt;/td&gt;
&lt;td&gt;High (headers per request)&lt;/td&gt;
&lt;td&gt;Low (single handshake)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best For&lt;/td&gt;
&lt;td&gt;CRUD, APIs&lt;/td&gt;
&lt;td&gt;Real-time updates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So yes, &lt;strong&gt;WebSockets can replace JSON over HTTP&lt;/strong&gt; in some cases—but they solve a different problem.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON is a &lt;strong&gt;data format&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;WebSocket is a &lt;strong&gt;communication protocol&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You can still use JSON &lt;strong&gt;over WebSockets&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real-World Example: Chat App
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Using HTTP + JSON:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You keep sending requests every few seconds: “Any new messages?”&lt;/li&gt;
&lt;li&gt;Server responds: “Nope. Still nothing.” (Wasted bandwidth)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using WebSocket:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You connect once.&lt;/li&gt;
&lt;li&gt;The server &lt;strong&gt;pushes&lt;/strong&gt; a message to you as soon as someone sends it.&lt;/li&gt;
&lt;li&gt;Efficient and instant.&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%2Fwtylwm47uy7e773ntxfr.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%2Fwtylwm47uy7e773ntxfr.png" alt="HTTP vs WebSocket: Chat application" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Should You Always Use WebSockets?
&lt;/h2&gt;

&lt;p&gt;Not really. Here's a quick guide:&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Use WebSockets when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You need real-time updates&lt;/li&gt;
&lt;li&gt;The server must push data to the client&lt;/li&gt;
&lt;li&gt;You’re building chat apps, live games, or notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✅ Use HTTP (with JSON) when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You're building standard CRUD APIs&lt;/li&gt;
&lt;li&gt;Data doesn’t change often&lt;/li&gt;
&lt;li&gt;SEO or caching is important&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;WebSockets don’t replace HTTP entirely—but they give you new possibilities. For Go developers (and frontend devs too), learning WebSockets opens the door to building real-time, modern web applications.&lt;/p&gt;

&lt;p&gt;In the next article, we’ll build a &lt;strong&gt;simple WebSocket server in Go&lt;/strong&gt;, and connect it to a browser using JavaScript. You’ll see just how easy (and powerful) it can be.&lt;/p&gt;

&lt;p&gt;Ready to go real-time? Let’s dive in!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Stay tuned for Part 2: "&lt;a href="https://dev.to/davjesse/how-to-build-a-simple-websocket-server-in-go-step-by-step-guide-4bdi"&gt;How to Build a Simple WebSocket Server in Go (Step-by-Step Guide)&lt;/a&gt;"&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>http</category>
      <category>websockets</category>
    </item>
  </channel>
</rss>
