<?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.us-east-2.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>The Mechanics of CLI Mistakes: Pipes, Redirection, and Stream Adjacency</title>
      <dc:creator>David Jesse Odhiambo</dc:creator>
      <pubDate>Fri, 09 Oct 2026 05:19:50 +0000</pubDate>
      <link>https://dev.to/davjesse/the-mechanics-of-cli-mistakes-pipes-redirection-and-stream-adjacency-42if</link>
      <guid>https://dev.to/davjesse/the-mechanics-of-cli-mistakes-pipes-redirection-and-stream-adjacency-42if</guid>
      <description>&lt;p&gt;It is 1:30 AM. PagerDuty just woke you up. An alert is firing across a production cluster, your terminal history is a blur of half-remembered flags, and every second the incident remains unmitigated feels like an eternity.&lt;/p&gt;

&lt;p&gt;You need to locate an errant service dump or isolate a single anomalous IP hammering your endpoints. You type a command you have executed a million times. You hit Enter.&lt;/p&gt;

&lt;p&gt;Instead of a clean output, your terminal buffer explodes with a thousand lines of unreadable Permission denied errors, blowing past your scrollback limit. Or worse: the prompt returns quietly in milliseconds with an empty output—or dirty data—giving you zero indication of what failed.&lt;/p&gt;

&lt;p&gt;You sit there in the dark, squinting at the screen, frustrated, asking yourself: “Why didn't that work? I swear, that command was right.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr0zse6fo9xtbd0czsyo9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr0zse6fo9xtbd0czsyo9.gif" alt=" " width="500" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was not right. It was muscle memory betraying you.&lt;/p&gt;

&lt;p&gt;Small syntactic oversights in the shell rarely trigger helpful stack traces. Instead, they betray how Unix handles standard streams and file descriptors under the hood.&lt;/p&gt;

&lt;p&gt;This guide dissects two insidious command-line mistakes that routinely trip up engineers during high-pressure audits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Pipeline Fallacy:&lt;/strong&gt; Why chaining &lt;code&gt;| 2&amp;gt;/dev/null&lt;/code&gt; fails to suppress standard error.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stream Adjacency:&lt;/strong&gt; Why &lt;code&gt;uniq&lt;/code&gt; silently passes duplicate records unless fed a sorted stream.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We examine the exact Unix mechanics behind both failures, provide battle-tested fixes, and outline the production contexts where these errors cost real engineering hours.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Companion Resource:&lt;/strong&gt; Production debugging patterns, terminal syntax breakdowns, and incident response playbooks are documented in the open-source &lt;a href="https://github.com/DavJesse/devops-playbook/" rel="noopener noreferrer"&gt;devops-playbook repository&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Case Study 1: The Pipeline Fallacy (&lt;code&gt;| 2&amp;gt;/dev/null&lt;/code&gt;)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Incident Scenario
&lt;/h3&gt;

&lt;p&gt;You are investigating an alert on an unfamiliar host. An unprivileged application process crashed, leaving behind an orphaned credential or state file. You know three attributes of the target file:&lt;/p&gt;

&lt;p&gt;Target owner: bill&lt;/p&gt;

&lt;p&gt;Target group: ted&lt;/p&gt;

&lt;p&gt;Exact file size: 254 bytes&lt;/p&gt;

&lt;p&gt;You execute a recursive search starting from the root directory (/):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find / &lt;span class="nt"&gt;-user&lt;/span&gt; bill &lt;span class="nt"&gt;-group&lt;/span&gt; ted &lt;span class="nt"&gt;-size&lt;/span&gt; 254c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because you are running the command as an unprivileged user, &lt;code&gt;find&lt;/code&gt; attempts to traverse restricted directories such as &lt;code&gt;/root&lt;/code&gt;, &lt;code&gt;/etc/ssl/private&lt;/code&gt;, and &lt;code&gt;/proc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The result is immediate noise. Hundreds of error lines flood the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;find: ‘/root’: Permission denied
find: ‘/etc/polkit-1/localauthority’: Permission denied
find: ‘/var/spool/cron/crontabs’: Permission denied
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The single matching path you need is buried somewhere in that wall of text.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Failed Fix: The Broken Pipe
&lt;/h3&gt;

&lt;p&gt;To eliminate the noise, muscle memory kicks in: pipe the errors away. So you append &lt;code&gt;| 2&amp;gt;/dev/null&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find / &lt;span class="nt"&gt;-user&lt;/span&gt; bill &lt;span class="nt"&gt;-group&lt;/span&gt; ted &lt;span class="nt"&gt;-size&lt;/span&gt; 254c | 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result? The exact same flood of Permission denied errors coats your screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvrkepmthj42jt2uwnyvl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvrkepmthj42jt2uwnyvl.gif" alt=" " width="400" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depending on your shell, you might even receive an additional parsing complaint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bash: 2&amp;gt;/dev/null: command not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why It Fails: Unix Stream Mechanics
&lt;/h3&gt;

&lt;p&gt;To understand this failure, consider how the shell manages Unix standard streams and file descriptors (FDs):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Standard Input (stdin / FD 0):&lt;/strong&gt; The stream the process reads for input.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Standard Output (stdout / FD 1):&lt;/strong&gt; The stream where the process sends normal runtime output.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Standard Error (stderr / FD 2):&lt;/strong&gt; The stream where the process writes error diagnostics and status warnings.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+---------------------------------------+
|  find / ...                           |
|    FD 1 (stdout) ------&amp;gt; [ Pipe | ] ------&amp;gt; Expects executable command
|    FD 2 (stderr) -------------------------&amp;gt; Attached to Terminal (Unfiltered)
+---------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you construct the command &lt;code&gt;find ... | 2&amp;gt;/dev/null&lt;/code&gt;, two distinct breakdowns occur:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pipes redirect &lt;code&gt;stdout&lt;/code&gt;, not &lt;code&gt;stderr&lt;/code&gt;:&lt;/strong&gt; The pipe operator (|) connects the &lt;code&gt;stdout&lt;/code&gt; (FD 1) of the command on the left to the stdin (FD 0) of the command on the right. It leaves stderr (FD 2) untouched and attached to your interactive terminal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The right side of a pipe requires a command:&lt;/strong&gt; A pipe expects an executable binary, shell builtin, or function on its receiving end. The syntax &lt;code&gt;2&amp;gt;/dev/null&lt;/code&gt; is an I/O redirection directive, not an executable. The shell cannot execute a redirection operator as a program.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because find continues writing its permission failures directly to FD 2, the error stream completely bypasses the pipe.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Correct Pattern
&lt;/h3&gt;

&lt;p&gt;Apply the redirection operator directly to the invocation of &lt;code&gt;find&lt;/code&gt;, without a pipe operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find / &lt;span class="nt"&gt;-user&lt;/span&gt; bill &lt;span class="nt"&gt;-group&lt;/span&gt; ted &lt;span class="nt"&gt;-size&lt;/span&gt; 254c 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Syntax Breakdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;find /&lt;/code&gt;:&lt;/strong&gt; Recursively search the file hierarchy starting at the root directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;-user bill&lt;/code&gt;:&lt;/strong&gt; Filter entries owned by user bandit7.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;-group ted&lt;/code&gt;:&lt;/strong&gt; Filter entries owned by group bandit6.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;-size 254c&lt;/code&gt;:&lt;/strong&gt; Match files with an exact size of 33 bytes (the suffix c specifies bytes).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;2&amp;gt;/dev/null&lt;/code&gt;:&lt;/strong&gt; Redirect file descriptor 2 (stderr) away from the terminal and into the &lt;code&gt;/dev/null&lt;/code&gt; pseudo-device (a bit bucket that discards all data written to it).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Clean Terminal Output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/var/lib/dpkg/info/timetravel.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdlskzy4z8osmilddszs7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdlskzy4z8osmilddszs7.gif" alt=" " width="374" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By discarding FD 2 at the source, stdout passes cleanly to the screen, surfacing the target artifact immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Production Impact
&lt;/h3&gt;

&lt;p&gt;On production systems, running broad discovery searches as an unprivileged service account or during a restricted audit session is standard practice.&lt;/p&gt;

&lt;p&gt;Failing to redirect file descriptors correctly introduces operational risk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Log Contamination:&lt;/strong&gt; Appending noisy commands to CI/CD diagnostic steps or incident runbooks pollutes central aggregation engines (Datadog, CloudWatch, Loki) with gigabytes of useless permission logs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Masked Success Criteria:&lt;/strong&gt; When piping command outputs into automated scrapers or monitoring scripts, leaked stderr lines can cause downstream JSON or regex parsers to throw parse exceptions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Case Study 2: The Adjacency Trap (&lt;code&gt;uniq -u&lt;/code&gt;)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Incident Scenario
&lt;/h3&gt;

&lt;p&gt;A distributed API endpoint is reporting anomalous spike latencies. You pull an unsorted raw telemetry extract, &lt;code&gt;data.txt&lt;/code&gt;, containing hundreds of request tokens and service signatures.&lt;/p&gt;

&lt;p&gt;Your task is triage isolation: find the single, non-recurring anomaly—the exact unique string that appeared once when the downstream service choked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbxpmn3tf4w3gbgcinv0m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbxpmn3tf4w3gbgcinv0m.gif" alt=" " width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You know the standard GNU core utility designed for this exact purpose: &lt;code&gt;uniq&lt;/code&gt;. Because you need only lines that occur exactly once, you supply the -u (unique) flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; data.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Silent Failure: False Positives
&lt;/h3&gt;

&lt;p&gt;Instead of isolating that single anomalous record, the terminal prints dozens of lines. When you inspect the output, you spot duplicate entries staring right back at you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi5hevkigh2m8ie5o60pg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi5hevkigh2m8ie5o60pg.gif" alt=" " width="498" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a simplified trace of what &lt;code&gt;data.txt&lt;/code&gt; contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;token_alpha
token_beta
token_alpha
token_gamma
token_beta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you execute &lt;code&gt;uniq -u data.txt&lt;/code&gt;, the terminal returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;token_alpha
token_beta
token_alpha
token_gamma
token_beta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait, shouldn't &lt;code&gt;uniq -u&lt;/code&gt; return unique lines? The command did not fail with a non-zero exit code. It did not produce an error message. It simply failed to perform the logical deduplication you expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why It Fails: Stream Adjacency Mechanics
&lt;/h3&gt;

&lt;p&gt;The behavior of &lt;code&gt;uniq&lt;/code&gt; is not broken; it is adhering strictly to its Unix design constraints.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;uniq&lt;/code&gt; was engineered as a low-overhead, memory-bounded stream processor. It does not ingest the entire dataset into an in-memory hash set or balanced binary tree. Doing so on a multi-gigabyte log file would exhaust system RAM and invoke the Linux Out-Of-Memory (OOM) killer.&lt;/p&gt;

&lt;p&gt;Instead, &lt;code&gt;uniq&lt;/code&gt; performs a state machine comparison using an internal single-line buffer:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F966ndzl3kt9iyup8lvvt.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F966ndzl3kt9iyup8lvvt.png" alt=" " width="235" height="130"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stream Input:
[token_alpha] -&amp;gt; Buffer holds: token_alpha  (First line: kept)
[token_beta]  -&amp;gt; Compare with: token_alpha  (Different: previous emitted, new buffered)
[token_alpha] -&amp;gt; Compare with: token_beta   (Different: previous emitted, new buffered)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;token_alpha&lt;/code&gt; was separated by &lt;code&gt;token_beta&lt;/code&gt;, &lt;code&gt;uniq&lt;/code&gt; evaluates the second occurrence of &lt;code&gt;token_alpha&lt;/code&gt; as a fresh entity. It has no memory of what it read two lines ago.&lt;/p&gt;

&lt;p&gt;To &lt;code&gt;uniq&lt;/code&gt;, duplicate entries are only duplicates if they are adjacent.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Correct Pattern
&lt;/h3&gt;

&lt;p&gt;Precondition the input stream by piping the raw file through sort before executing &lt;code&gt;uniq&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sort &lt;/span&gt;data.txt | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Syntax Breakdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;sort data.txt&lt;/code&gt;:&lt;/strong&gt; Reads the entire dataset, orders records lexicographically, and writes the sorted stream to standard output (&lt;code&gt;stdout&lt;/code&gt;). This groups identical tokens into contiguous blocks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;|:&lt;/code&gt;&lt;/strong&gt; Standard Unix pipe, connecting the &lt;code&gt;stdout&lt;/code&gt; of sort to the standard input (stdin) of &lt;code&gt;uniq&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;uniq -u&lt;/code&gt;:&lt;/strong&gt; Filters the contiguous stream, discarding any token cluster with a frequency count greater than 1, emitting only lines that appear exactly once.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Clean Terminal Output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;token_gamma
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo6svn3x6opesydkhc5kg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo6svn3x6opesydkhc5kg.gif" alt=" " width="318" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The sorting pass clusters identical lines together (&lt;code&gt;token_alpha&lt;/code&gt;, &lt;code&gt;token_alpha&lt;/code&gt;, &lt;code&gt;token_beta&lt;/code&gt;, &lt;code&gt;token_beta&lt;/code&gt;, &lt;code&gt;token_gamma&lt;/code&gt;), enabling &lt;code&gt;uniq&lt;/code&gt;'s two-line sliding window to correctly identify and drop the duplicates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Production Impact
&lt;/h3&gt;

&lt;p&gt;Relying on &lt;code&gt;uniq&lt;/code&gt; without an upstream sort during live incident mitigation introduces severe risks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Corrupted Root Cause Analysis (RCA):&lt;/strong&gt; If you pipe an unsorted stream into &lt;code&gt;uniq -c&lt;/code&gt; to calculate event frequencies or error distributions, your metric counts will be fragmented across multiple separate lines rather than aggregated into true totals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU and Memory Trade-offs:&lt;/strong&gt; While &lt;code&gt;uniq&lt;/code&gt; is &lt;code&gt;O(N)&lt;/code&gt; with tiny memory overhead, &lt;code&gt;sort&lt;/code&gt; requires &lt;code&gt;O(N \log N)&lt;/code&gt; compute time and buffers data in memory (spilling to &lt;code&gt;/tmp&lt;/code&gt; for large sets). In high-volume log investigations, understanding this trade-off tells you when to run &lt;code&gt;sort | uniq&lt;/code&gt; versus using an in-memory aggregation tool like &lt;code&gt;awk '!seen[$0]++'&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mastering the Subtleties of the Shell
&lt;/h2&gt;

&lt;p&gt;The difference between a frantic incident investigation and a fast, surgical fix rarely comes down to esoteric kernel tuning. It comes down to standard I/O mechanics, file descriptors, and stream buffers.&lt;/p&gt;

&lt;p&gt;When you understand that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pipes link standard output to standard input, leaving file descriptor 2 attached to your terminal, and&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;uniq&lt;/code&gt; is a lightweight streaming filter that relies entirely on contiguous adjacency,&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;you stop wrestling with unexpected terminal noise and start constructing predictable, deterministic pipelines. Muscle memory is useful, but foundational mechanics keep systems running when everything else is breaking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contribute to the Playbook
&lt;/h2&gt;

&lt;p&gt;We are building an open-source collection of real-world Linux command breakdowns, edge cases, and incident mitigation patterns over at &lt;a href="https://github.com/DavJesse/devops-playbook" rel="noopener noreferrer"&gt;devops-playbook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Whether it is a subtle flag combination in &lt;code&gt;xxd&lt;/code&gt;, a trap inside &lt;code&gt;tar&lt;/code&gt; extraction paths, or an edge case in &lt;code&gt;awk&lt;/code&gt;, every utility has failure modes that cost engineers hours.&lt;/p&gt;

&lt;p&gt;Star the repo to keep these quick-reference patterns in your toolkit.&lt;/p&gt;

&lt;p&gt;Open a PR or issue with the CLI syntax friction points you have run into during your own late-night debugging sessions.&lt;/p&gt;

&lt;p&gt;Let's build a zero-fluff manual that saves engineers from unnecessary production headaches.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Felco7fh26lupwrxcwzna.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Felco7fh26lupwrxcwzna.gif" alt=" " width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>devops</category>
      <category>cli</category>
      <category>p</category>
    </item>
    <item>
      <title>Demystifying SSH Key Management and Security Inside Windows Subsystem for Linux (WSL)</title>
      <dc:creator>David Jesse Odhiambo</dc:creator>
      <pubDate>Wed, 16 Sep 2026 19:44:29 +0000</pubDate>
      <link>https://dev.to/davjesse/demystifying-ssh-key-management-and-security-inside-windows-subsystem-for-linux-wsl-2ldm</link>
      <guid>https://dev.to/davjesse/demystifying-ssh-key-management-and-security-inside-windows-subsystem-for-linux-wsl-2ldm</guid>
      <description>&lt;p&gt;Transitioning from GUI-assisted tools to the command line gives you complete control over your systems workflows. However, running Secure Shell (SSH) inside Windows Subsystem for Linux (WSL) often exposes friction across environment boundaries. Sharing keys directly from the host Windows file system triggers silent permission mismatches and fatal &lt;code&gt;Permissions 0777 are too open&lt;/code&gt; errors because the underlying NTFS drive mounts ignore standard POSIX access controls. This guide shows you how to isolate cryptographic keys natively within the WSL file system, enforce strict file permissions, and automate credential handling with &lt;code&gt;ssh-agent&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture: Host vs. WSL Boundary
&lt;/h2&gt;

&lt;p&gt;WSL mounts your Windows host drives under &lt;code&gt;/mnt/c/&lt;/code&gt; through a translation file system (DrvFs/9P). While this lets you access Windows files from Linux, it creates a critical architectural divide between two separate file systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Host Mount (&lt;code&gt;/mnt/c/Users/&amp;lt;user&amp;gt;/.ssh&lt;/code&gt;):&lt;/strong&gt; Stored on Windows NTFS. By default, DrvFs translates NTFS Access Control Lists (ACLs) by assigning permissive &lt;code&gt;0777&lt;/code&gt; permissions to every file, ignoring standard POSIX ownership.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native Linux Directory (&lt;code&gt;~/.ssh&lt;/code&gt; or &lt;code&gt;/home/&amp;lt;user&amp;gt;/.ssh&lt;/code&gt;):&lt;/strong&gt; Stored inside WSL's virtual ext4 disk (&lt;code&gt;ext4.vhdx&lt;/code&gt;), which fully supports native Linux file modes and ownership.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the OpenSSH client requires private keys to be accessible exclusively by the owner, pointing SSH to keys in &lt;code&gt;/mnt/c/&lt;/code&gt; causes immediate authentication failures. To maintain security and avoid permission rejections, store and manage your SSH keys strictly within the native Linux file system at &lt;code&gt;~/.ssh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg8jf051ag6r5hh7sl3z7.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg8jf051ag6r5hh7sl3z7.png" alt="An infographic illustrating the architectural flow and outcome of SSH key management between Windows (NTFS) and the WSL (ext4) filesystem" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqesoyl6y1pmm8l2vp0hu.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqesoyl6y1pmm8l2vp0hu.png" alt="stylized terminal window showing the exact OpenSSH rejection banner" width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating and Securing Keys Inside WSL
&lt;/h2&gt;

&lt;p&gt;Generate an asymmetric key pair inside your WSL terminal using the modern Ed25519 algorithm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"wsl-dev"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefer Ed25519 over legacy RSA. It produces compact 256-bit keys that offer stronger cryptographic resistance against side-channel attacks, faster signature generation, and smaller payload footprints than typical 2048-bit or 4096-bit RSA keys.&lt;/p&gt;

&lt;p&gt;Once generated, enforce strict POSIX permissions. The OpenSSH client audits file modes on execution and aborts connections if keys are readable by other system users:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Required Permission&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Directory&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.ssh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;700 (drwx------)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;chmod 700 ~/.ssh&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Private Key&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.ssh/id_ed25519&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;600 (-rw-------)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;chmod 600 ~/.ssh/id_ed25519&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Public Key&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.ssh/id_ed25519.pub&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;644 (-rw-r--r--)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;chmod 644 ~/.ssh/id_ed25519.pub&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Verifying these octal modes ensures compliance with OpenSSH's security checks and protects your private keys from exposure across shared local environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streamlining Sessions with ssh-agent
&lt;/h2&gt;

&lt;p&gt;Protecting your private key with a passphrase is essential, but re-entering it for every SSH session, Git push, or remote server transition interrupts terminal workflows. You can eliminate this friction using &lt;code&gt;ssh-agent&lt;/code&gt;, a background program that caches your unencrypted keys in memory.&lt;/p&gt;

&lt;p&gt;Initialize the agent and load your key into the active session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;ssh-agent &lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
ssh-add ~/.ssh/id_ed25519
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once loaded, OpenSSH authenticates automatically without prompting for your passphrase until the session closes.&lt;/p&gt;

&lt;p&gt;To automate this across all new WSL shell sessions without launching duplicate background processes every time you open a tab, append this lightweight check to your &lt;code&gt;~/.bashrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;ssh-agent &lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
    ssh-add ~/.ssh/id_ed25519 2&amp;gt;/dev/null
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Pitfalls: The Drvfs Mount Trap
&lt;/h2&gt;

&lt;p&gt;Attempting to fix permissions on Windows-mounted keys by running &lt;code&gt;chmod 600 /mnt/c/Users/&amp;lt;user&amp;gt;/.ssh/id_rsa&lt;/code&gt; fails silently. The command exits with status &lt;code&gt;0&lt;/code&gt;, but &lt;code&gt;ls -l&lt;/code&gt; reveals the permissions remain &lt;code&gt;0777&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This happens because the DrvFs driver ignores POSIX file metadata updates unless explicitly enabled in &lt;code&gt;/etc/wsl.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[automount]&lt;/span&gt;
&lt;span class="py"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"metadata"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While adding &lt;code&gt;metadata&lt;/code&gt; allows &lt;code&gt;chmod&lt;/code&gt; to persist on NTFS files, relying on host mounts introduces unnecessary cross-filesystem overhead and risks ACL collisions. The production standard remains absolute: generate and keep your SSH keys strictly within the native WSL ext4 filesystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Isolating your keys inside the native WSL ext4 filesystem prevents NTFS permission rejections. Enforce strict &lt;code&gt;700&lt;/code&gt; and &lt;code&gt;600&lt;/code&gt; modes to satisfy OpenSSH security standards, and automate &lt;code&gt;ssh-agent&lt;/code&gt; in your &lt;code&gt;~/.bashrc&lt;/code&gt; to maintain secure, frictionless terminal workflows.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>devops</category>
      <category>security</category>
      <category>wsl</category>
    </item>
    <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>
