<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Mike Talks Tech]]></title><description><![CDATA[Mike Talks Tech]]></description><link>https://blog.flexicon.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 06 May 2026 15:53:38 GMT</lastBuildDate><atom:link href="https://blog.flexicon.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Gophers on the Web: Getting Started with Go and WebAssembly]]></title><description><![CDATA[Have you ever wanted to solve some specific problems in your web application, but JavaScript just wasn't spicy enough or you thought you could use more processing power?
Perhaps you're a fan of Web Development with Go and wanted to use it for more th...]]></description><link>https://blog.flexicon.dev/getting-started-with-go-and-webassembly</link><guid isPermaLink="true">https://blog.flexicon.dev/getting-started-with-go-and-webassembly</guid><category><![CDATA[Go Language]]></category><category><![CDATA[WebAssembly]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[wasm]]></category><dc:creator><![CDATA[Mike Repec]]></dc:creator><pubDate>Wed, 17 Apr 2024 07:01:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Om-Z4TDfv7o/upload/2eac3d785497443b6e29a3b78b33d577.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever wanted to solve some specific problems in your web application, but JavaScript just wasn't spicy enough or you thought you could use <em>more processing power</em>?</p>
<p>Perhaps you're a fan of Web Development with Go and wanted to use it for more than just the backend?</p>
<p>Or maybe you've been hearing all the hubbub around <a target="_blank" href="https://webassembly.org/">WebAssembly</a> (Wasm) and wanted to see what the big fuss was all about?</p>
<p>Well if you even remotely found yourself responding with an <em>"eh, I guess"</em> to any of the above: look no further. On this page you'll find a minimal, barebones, step-by-step guide of what it takes to get a Go program compiled down to a Wasm module, running in your browser and interacting with it using a simple HTML form.</p>
<h2 id="heading-what-is-webassembly">What is WebAssembly?</h2>
<p>To quote the <a target="_blank" href="https://webassembly.org/">Official Website</a>:</p>
<blockquote>
<p>WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications.</p>
</blockquote>
<p>In the context of this post, you can think of it as a way for us to run code written in programming languages other than native web JavaScript in the browser.</p>
<h2 id="heading-the-goal-for-today">The Goal for today</h2>
<p>Let's keep things simple here.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713083331209/e0e039ca-6fa5-49a1-b5e5-e4d9e1cc953a.png" alt class="image--center mx-auto" /></p>
<p>We'll build a basic web page with a single input form. The form will take a number from the user and when submitted will display its square root.</p>
<p>About as simple as can be, and straightforward to achieve in vanilla JavaScript. However we're complicated individuals and we don't want to use JavaScripts math or parsing features here - all input parsing and calculations will happen in a Wasm module written in Go instead.</p>
<h2 id="heading-the-solution">The Solution</h2>
<p>Looking to jump straight into the solution? I respect your moxie. In that case <a target="_blank" href="https://github.com/Flexicon/go-in-the-browser">check out the Git repo</a>.<br />The key files to check are <code>web/index.html</code> to see how the Wasm module is hooked up to our HTML, and the Go Wasm source code itself under <code>cmds/wasm/main.go</code>.</p>
<p><strong>🚨 Spoiler alert:</strong> here's a <a target="_blank" href="https://go-in-the-browser.pages.dev/">live version</a> of the finished web page.</p>
<p>Otherwise, keep on reading and we'll break down the solution step-by-step.</p>
<h2 id="heading-a-simple-wasm-module">A simple Wasm Module</h2>
<p>The most minimal setup for a Go Wasm module doesn't differ in any way from a generic <em>"Hello, World"</em> program.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    fmt.Println(<span class="hljs-string">"Go Wasm module instantiated!"</span>)
}
</code></pre>
<p>The secret sauce is all in how we <em>compile</em> the code from here on out.</p>
<p>In a regular Go program, we might do something like <code>go build .</code> , but when targeting Wasm we must specify more arguments and variables.</p>
<pre><code class="lang-bash">GOARCH=wasm GOOS=js go build -o app.wasm .
</code></pre>
<p>The <code>GOOS</code> variable tells the compiler what operating system we want our target binary to run on, and the <code>GOARCH</code> variables tells it what architecture should be used for the binary. This is also the standard way for cross compiling Go programs, for example to target <code>darwin</code> for macOS and <code>arm64</code> for Apple silicon architecture.</p>
<h2 id="heading-running-the-wasm-in-a-browser">Running the Wasm in a browser</h2>
<p>First things first, we'll need a bit of JavaScript to run and instantiate our Go-based Wasm module in the browser - luckily the standard library provides this with every installation of Go, we must simply copy it over to our working directory.</p>
<pre><code class="lang-bash">cp <span class="hljs-string">"<span class="hljs-subst">$(go env GOROOT)</span>/misc/wasm/wasm_exec.js"</span> .
</code></pre>
<p>Now we have a <code>wasm_exec.js</code> file which we can load in our browser - great, let's do that now.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"wasm_exec.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>We can add the above snippet to the head of any HTML document where we want to execute Wasm. Let's create a skeleton document now.</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Using Go in the Browser<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"wasm_exec.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Okay, so we've copied the code that will execute our Wasm module and loaded it in our HTML. Now we have to actually tell the browser to fetch, instantiate and run our <code>app.wasm</code> module. Add the following script tag below the one which loads <code>wasm_exec.js</code> in the head of the document.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-comment">// Creates an instance of the Go wasm_exec class,</span>
  <span class="hljs-comment">// streams in the Wasm module using fetch</span>
  <span class="hljs-comment">// and finally runs it. 🚀</span>
  <span class="hljs-keyword">const</span> go = <span class="hljs-keyword">new</span> Go();
  WebAssembly.instantiateStreaming(fetch(<span class="hljs-string">'app.wasm'</span>), go.importObject).then(<span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
    go.run(result.instance);
  });
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Let's test this out and see it come together in action. You should now be able to serve your <code>index.html</code> file along with the <code>wasm_exec.js</code> and <code>app.wasm</code> files using any preferred method. I personally like using <a target="_blank" href="https://github.com/sno6/gommand">gommand</a> for quick demos like this one.</p>
<pre><code class="lang-bash">go install github.com/sno6/gommand@latest
<span class="hljs-comment"># Now serve assets in your current directory</span>
gommand <span class="hljs-string">'http.Handle("/", http.FileServer(http.Dir("."))); fmt.Println(http.ListenAndServe(":8080", nil))'</span>
</code></pre>
<p>The snippet runs a simple Go HTTP File Server based on your current working directory. Once it's running navigate to your web page (if using <code>gommand</code> <a target="_blank" href="http://localhost:8080/">http://localhost:8080/</a>) and check your console - you should see the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713087758323/bfa664c3-44c2-4bca-8d1d-add97ed844f8.png" alt class="image--center mx-auto" /></p>
<p>🚀 Great success! Our Wasm module has been successfully loaded, and the standard output from our Go program has landed in our browser console.</p>
<h2 id="heading-adding-the-form-and-some-spice">Adding the Form and some Spice 🌶️</h2>
<p>Currently our web page is empty and our Wasm module doesn't really do much - nothing to write home about in any case. Let's fix that.</p>
<p>Here's the markup for our form:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"sqrt-form"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"sqrt-num"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"sqrt-num"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter some number"</span> <span class="hljs-attr">required</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Calculate Square Root<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"sqrt-answer"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
</code></pre>
<p>Save it and refresh the page to see... a bit more, but still not that much.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713097630394/4eda1620-87f5-4766-bbe1-dcd0d63defa7.png" alt class="image--center mx-auto" /></p>
<p>Let's quickly <em>spice things up a notch</em> by dropping in a little semantic CSS, courtesy of <a target="_blank" href="https://picocss.com/">Pico</a> ✨</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.violet.min.css"</span> /&gt;</span>
</code></pre>
<p>... and adding a tiny bit of style to the body tag:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"max-width: 900px; margin: 0 auto"</span>&gt;</span>
</code></pre>
<p>And - channeling my inner <a target="_blank" href="https://en.wikipedia.org/wiki/Emeril_Lagasse">Emeril Lagasse</a> - bam!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713098014381/5ae3831b-f204-40db-adef-37af3d1e84a3.png" alt class="image--center mx-auto" /></p>
<p>Nice - that's a little more presentable at least, and immediately matches our earlier mockup.</p>
<h2 id="heading-extending-the-wasm-module">Extending the Wasm Module</h2>
<p>Now that we have our form set up and markup thoroughly spiced, we can move on back to the actual Wasm code. So far, all it does is print a message to standard output and exits. In order to be able to have it calculate square roots for us, we'll need to do a few things:</p>
<ol>
<li><p>Export a function for the JavaScript runtime to call</p>
</li>
<li><p>Keep the Go program running and waiting for calls to said function</p>
</li>
</ol>
<p>We can achieve #2 fairly easily by adding a blocking channel receiver call on a perpetually empty channel.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    fmt.Printf(<span class="hljs-string">"Go Wasm module instantiated!\n"</span>)

    &lt;-<span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">bool</span>)
}
</code></pre>
<p>Cool. Now our program will actually wait around to receive calls. But what sort of calls is it listening for? Well at present: none. Let's change that.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    fmt.Printf(<span class="hljs-string">"Go Wasm module instantiated!\n"</span>)

    <span class="hljs-comment">// 1</span>
    js.Global().Set(<span class="hljs-string">"GoSqrt"</span>, js.FuncOf(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(this js.Value, args []js.Value)</span> <span class="hljs-title">any</span></span> {
        <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(args) &lt; <span class="hljs-number">1</span> { <span class="hljs-comment">// 2</span>
            <span class="hljs-keyword">return</span> math.NaN() <span class="hljs-comment">// 3</span>
        }

        <span class="hljs-keyword">return</span> math.Sqrt(parseFloatJS(args[<span class="hljs-number">0</span>])) <span class="hljs-comment">// 4</span>
    }))

    &lt;-<span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">bool</span>)
}
</code></pre>
<p>Now let's unpack a bit what exactly is happening here:</p>
<ol>
<li><p>We call the <code>syscall/js.Global</code> func, which allows us to use the standard library to interact with JavaScript's Global namespace (ie: the <code>window</code> object). In this particular case we <code>Set</code> (or declare) a new global function - named <code>GoSqrt</code> - which receives a reference to JavaScript's <code>this</code> scope for the function and a slice of <code>js.Value</code> arguments.</p>
</li>
<li><p>We then do some initial argument validation, since our newly declared function requires one argument to be passed to it - the number for which we want to find a square root.</p>
</li>
<li><p>If the function was called without any arguments, we return a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a>.</p>
</li>
<li><p>If all is well, we call the standard library <code>math.Sqrt</code> func with the argument received from the browser after having parsed it.</p>
</li>
</ol>
<p>Ah, I mentioned parsing. Well since JavaScript is not strongly typed, we can't really enforce what type of data gets passed to our function from the browser. What we <em>can</em> do is <em>handle</em> the types passed in Go, and in our case we can handle either a JavaScript <code>number</code> or <code>string</code> type. The <code>js.Value</code> struct provides some nice helpers to make this easier.</p>
<p>Here's how we do that:</p>
<pre><code class="lang-go"><span class="hljs-comment">// parseFloatJS returns a float64 from a js.Value, based on either a `number` or `string` js type. NaN otherwise.</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">parseFloatJS</span><span class="hljs-params">(v js.Value)</span> <span class="hljs-title">float64</span></span> {
    <span class="hljs-keyword">switch</span> v.Type() {
    <span class="hljs-keyword">case</span> js.TypeNumber:
        <span class="hljs-keyword">return</span> v.Float()
    <span class="hljs-keyword">case</span> js.TypeString:
        <span class="hljs-keyword">if</span> f, err := strconv.ParseFloat(v.String(), <span class="hljs-number">64</span>); err == <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">return</span> f
        }
    }
    <span class="hljs-keyword">return</span> math.NaN()
}
</code></pre>
<p>The logic is fairly basic. We essentially return a <code>float64</code> when the argument is a JavaScript <code>number</code> type, and if it is a <code>string</code> we use Go's standard <code>strconv</code> package to parse a <code>float64</code> out of it and return the result if all went well. In all other cases we return <code>NaN</code>.</p>
<h2 id="heading-wiring-everything-together">Wiring everything together</h2>
<p>Phew, almost there. The last step is to wire it all up, with some standard DOM JavaScript. What we want to do here is listen to the form submit event, read the current value from our number input and pass it to our global <code>GoSqrt</code> function exported by our Wasm module. Finally we display the returned result from said function below our form.</p>
<p>So let's wrap this up by updating our script tag with the following:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">wireItAllUp</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> sqrtNumInput = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'sqrt-num'</span>);
  <span class="hljs-keyword">const</span> sqrtForm = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'sqrt-form'</span>);
  <span class="hljs-keyword">const</span> sqrtAnswerDiv = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'sqrt-answer'</span>);

  sqrtForm.addEventListener(<span class="hljs-string">'submit'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">e</span>) </span>{
    e.preventDefault();
    <span class="hljs-keyword">const</span> value = sqrtNumInput.value;
    <span class="hljs-comment">// This is the 👇 part where we call out to Wasm.</span>
    <span class="hljs-keyword">const</span> result = GoSqrt(value);

    sqrtAnswerDiv.innerHTML = <span class="hljs-string">`🤓 The square root of <span class="hljs-subst">${value}</span> is <span class="hljs-subst">${result}</span>.&lt;br&gt;So sayeth the Gopher.`</span>;
  });
}

<span class="hljs-comment">// This statement is unchanged apart from the wireItAllUp call.</span>
WebAssembly.instantiateStreaming(fetch(<span class="hljs-string">'app.wasm'</span>), go.importObject).then(<span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
  go.run(result.instance);
  wireItAllUp(); <span class="hljs-comment">// 👈 This line is new.</span>
});
</code></pre>
<p>Now if we save our changes (make sure to rebuild your <code>app.wasm</code> file after making any changes to it) and refresh the page, we should be able to finally use the form and calculate any and all square roots we could possibly want.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713100835331/77ee4b42-3fe1-43e4-9e85-c8866d267a9f.png" alt class="image--center mx-auto" /></p>
<p>And there you have it - Go running in the browser and doing math. The possibilities from here are essentially endless.</p>
<p>Here's a link to <a target="_blank" href="https://github.com/Flexicon/go-in-the-browser">the complete project</a> as well as a <a target="_blank" href="https://go-in-the-browser.pages.dev/">live version</a> to play around with.</p>
<h2 id="heading-whats-next">What's Next?</h2>
<p>To greatly reduce the size of your Wasm binary file, consider using <a target="_blank" href="https://tinygo.org/">TinyGo</a> as your compiler. Also, explore more real-world uses for your Wasm module, like generating images or using third-party packages for heavy processing tasks. Stay tuned and follow the blog to get updates when new posts are published.</p>
<h2 id="heading-further-reading">Further Reading</h2>
<ul>
<li><p>The official <a target="_blank" href="https://github.com/golang/go/wiki/WebAssembly">Go WebAssembly docs</a> to start diving a little deeper on the topic.</p>
</li>
<li><p>The <a target="_blank" href="https://webassembly.org/">WebAssembly Docs</a> themselves.</p>
</li>
<li><p>The growing <a target="_blank" href="https://awesome-go.com/#webassembly">WebAssembly section of awesome-go</a> for neat libraries and tools in the ecosystem.</p>
</li>
<li><p>The list of <a target="_blank" href="https://github.com/mbasso/awesome-wasm">awesome-wasm</a> things in the community - not just using Go.</p>
</li>
<li><p><a target="_blank" href="https://go-app.dev/">go-app.dev</a> - the up and coming package for building <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps">PWA's (Progressive Web Apps)</a> using Go and Wasm.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Read Go HTTP Request body multiple times]]></title><description><![CDATA[I think we can all agree that writing HTTP servers in Go is an overall simple and pleasant affair. But what happens when we find ourselves needing to read the body of an incoming request multiple times? A common use case would be a middleware that ne...]]></description><link>https://blog.flexicon.dev/read-go-http-request-body-multiple-times</link><guid isPermaLink="true">https://blog.flexicon.dev/read-go-http-request-body-multiple-times</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[software development]]></category><category><![CDATA[design patterns]]></category><dc:creator><![CDATA[Mike Repec]]></dc:creator><pubDate>Tue, 15 Mar 2022 19:34:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/OTDyDgPoJ_0/upload/v1647131616999/Tus0rBWDu.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I think we can all agree that writing HTTP servers in Go is an overall simple and pleasant affair. But what happens when we find ourselves needing to read the body of an incoming request multiple times? A common use case would be a middleware that needs to read and verify the request body before it can be processed further, or another that needs to log the request body while still allowing the body to be read later on.</p>
<h2 id="heading-the-problem">The Problem</h2>
<p>After reading once from the <code>io.Reader</code> implemented by the body field of Go http requests, it becomes impossible to read from it again. There is also no builtin way to simply <em>"reset"</em> the body as part of the interface.</p>
<h2 id="heading-the-simplest-solution">The simplest solution</h2>
<p>For the simplest solution, we simply need to make sure that every time we read through the request body, we read through it fully and then replace it with a new reader. Simple.</p>
<pre><code class="lang-go">body, err := io.ReadAll(r.Body)
<span class="hljs-comment">// Replace the body with a new reader after reading from the original</span>
r.Body = io.NopCloser(bytes.NewBuffer(body))
</code></pre>
<p>We can even make use of an <code>io.TeeReader</code> and <code>bytes.Buffer</code>.</p>
<pre><code class="lang-go">buf := bytes.Buffer{} <span class="hljs-comment">// A Buffer is both a Reader and Writer</span>
req.Body = io.TeeReader(req.Body, &amp;buf)
<span class="hljs-comment">// Do some body reading, then replace the body with the buffer</span>
req.Body = &amp;buf
</code></pre>
<h2 id="heading-simple-reusable-reader-implementation">Simple Reusable Reader implementation</h2>
<p>Because Go's interfaces work via <a target="_blank" href="https://en.wikipedia.org/wiki/Structural_type_system">structural typing</a>, we can very easily implement the <code>io.Reader</code> interface with a custom type as a drop-in replacement. Thus creating an <code>io.Reader</code> that can be <em>"read from"</em> an infinite number of times.</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> reusableReader <span class="hljs-keyword">struct</span> {
    io.Reader
    readBuf *bytes.Buffer
    backBuf *bytes.Buffer
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">ReusableReader</span><span class="hljs-params">(r io.Reader)</span> <span class="hljs-title">io</span>.<span class="hljs-title">Reader</span></span> {
    readBuf := bytes.Buffer{}
    readBuf.ReadFrom(r) <span class="hljs-comment">// error handling ignored for brevity</span>
    backBuf := bytes.Buffer{}

    <span class="hljs-keyword">return</span> reusableReader{
        io.TeeReader(&amp;readBuf, &amp;backBuf),
        &amp;readBuf,
        &amp;backBuf,
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(r reusableReader)</span> <span class="hljs-title">Read</span><span class="hljs-params">(p []<span class="hljs-keyword">byte</span>)</span> <span class="hljs-params">(<span class="hljs-keyword">int</span>, error)</span></span> {
    n, err := r.Reader.Read(p)
    <span class="hljs-keyword">if</span> err == io.EOF {
        r.reset()
    }
    <span class="hljs-keyword">return</span> n, err
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(r reusableReader)</span> <span class="hljs-title">reset</span><span class="hljs-params">()</span></span> {
    io.Copy(r.readBuf, r.backBuf) <span class="hljs-comment">// nolint: errcheck</span>
}
</code></pre>
<h2 id="heading-basic-usage">Basic usage</h2>
<p>A simple example of using our reusable reader with basically any <code>io.Reader</code> implementation.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    text := <span class="hljs-string">"Lorem ipsum dolor sit amet"</span>
    r := ReusableReader(strings.NewReader(text))

    readAndPrint(r)
    readAndPrint(r)
    readAndPrint(r)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">readAndPrint</span><span class="hljs-params">(r io.Reader)</span></span> {
    b, _ := io.ReadAll(r)
    fmt.Printf(<span class="hljs-string">"%s\n"</span>, <span class="hljs-keyword">string</span>(b))
}

<span class="hljs-comment">// "Lorem ipsum dolor sit amet"</span>
<span class="hljs-comment">// "Lorem ipsum dolor sit amet"</span>
<span class="hljs-comment">// "Lorem ipsum dolor sit amet"</span>
</code></pre>
<p><em>Worth noting that if only dealing with <code>strings.Reader</code>s or <code>bytes.Reader</code>s, it is infinitely easier to simply seek back to the beginning of those readers since they implement the <code>io.Seeker</code> interface</em></p>
<pre><code class="lang-go">r := strings.NewReader(text)
r.Seek(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>) <span class="hljs-comment">// will effectively reset the reader back to the beginning</span>
</code></pre>
<h2 id="heading-request-body-usage">Request body usage</h2>
<p>Things get more complicated when dealing with <code>http.Request</code> body fields, which don't implement the <code>io.Seeker</code> interface. In that case, for any <code>http.Request</code> we can easily use our reusable reader in place of its <code>Body</code>.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">handler</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
    r.Body = io.NopCloser(ReusableReader(r.Body))
    <span class="hljs-comment">// Perform any reads however much we like from here on out</span>
}
</code></pre>
<p>We needed to wrap our <code>ReusableReader</code> with an <code>io.NopCloser</code> in order to adhere to the <code>io.ReadCloser</code> interface. We could realistically simplify this case by implementing the <code>io.Closer</code> interface, just like the <code>io.NopCloser</code> does.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(r ReusableReader)</span> <span class="hljs-title">Close</span><span class="hljs-params">()</span> <span class="hljs-title">error</span></span> { <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> }
</code></pre>
<p>Which would allow the above example to be a tad simpler.</p>
<pre><code class="lang-go">r.Body = ReusableReader(r.Body)
</code></pre>
<h2 id="heading-a-more-real-world-example">A more real-world example</h2>
<p>Infinitely re-reading a static byte reader isn't all that exciting. So let's assume that we are building a web application and have created the following middleware for our request handlers, which both require the reading of the request body.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">logRequest</span><span class="hljs-params">(next http.Handler)</span> <span class="hljs-title">http</span>.<span class="hljs-title">Handler</span></span> {
    <span class="hljs-keyword">return</span> http.HandlerFunc(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
        msg := fmt.Sprintf(<span class="hljs-string">"%s %s"</span>, r.Method, r.URL.Path)

        <span class="hljs-keyword">if</span> body, _ := io.ReadAll(r.Body); <span class="hljs-built_in">len</span>(body) &gt; <span class="hljs-number">0</span> {
            msg += fmt.Sprintf(<span class="hljs-string">" Body: %s"</span>, <span class="hljs-keyword">string</span>(body))
        }

        log.Print(msg)
        next.ServeHTTP(w, r)
    })
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">verifyRequest</span><span class="hljs-params">(next http.Handler)</span> <span class="hljs-title">http</span>.<span class="hljs-title">Handler</span></span> {
    <span class="hljs-keyword">return</span> http.HandlerFunc(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
        body, err := io.ReadAll(r.Body)
        <span class="hljs-comment">// Perform some request verification here</span>
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> || <span class="hljs-built_in">len</span>(body) == <span class="hljs-number">0</span> {
            log.Printf(<span class="hljs-string">"%d: Request verification failed"</span>, http.StatusBadRequest)
            w.WriteHeader(http.StatusBadRequest)
            <span class="hljs-keyword">return</span>
        }

        log.Printf(<span class="hljs-string">"Request verified: %s"</span>, <span class="hljs-keyword">string</span>(body))
        next.ServeHTTP(w, r)
    })
}
</code></pre>
<p>If used as is, then whichever of these middleware that we would run second would not be able to read the request body, since it would have already been read from by the first. This is where our reusable reader can come in handy, and we could simply wrap it's logic around a third middleware that should be ran first in the chain.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">reuseBody</span><span class="hljs-params">(next http.Handler)</span> <span class="hljs-title">http</span>.<span class="hljs-title">Handler</span></span> {
    <span class="hljs-keyword">return</span> http.HandlerFunc(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
        r.Body = io.NopCloser(ReusableReader(r.Body))
        next.ServeHTTP(w, r)
    })
}
</code></pre>
<p>Now that we have all middleware in place, we can setup our http server and make use of the infinitely readable <code>http.Request</code> body.</p>
<p>Let's assume we have a handler called <code>greet</code> which will greet the user based on the request body payload - again needing to read from the request body after passing it through both of the other middleware already.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    greetHandler := http.HandlerFunc(greet)

    mux := http.NewServeMux()
    mux.Handle(<span class="hljs-string">"/greet"</span>, reuseBody(logRequest(verifyRequest(greetHandler))))

    fmt.Println(<span class="hljs-string">"Listening on port http://localhost:9000/"</span>)
    log.Fatalln(http.ListenAndServe(<span class="hljs-string">":9000"</span>, mux))
}
</code></pre>
<h2 id="heading-final-thoughts-and-drawbacks">Final thoughts and drawbacks</h2>
<p>While this is all fine and dandy with the simple examples above, it's important to remember that this reusable reader is by nature not a very efficient implementation of the <code>io.Reader</code> interface; mainly because we require reading all of the data up front into a buffer. Which won't work well for anything large like files or larger streams of data.</p>
<p>Another issue with this approach is that we are assuming that everyone attempting to read from the reader knows and assumes that it is an instance of a <code>ReusableReader</code>. At which point it might be better/safer for middleware to simply read from the reader, process any data and replace the reader with a new one like mentioned before.</p>
]]></content:encoded></item></channel></rss>