summaryrefslogtreecommitdiff
path: root/public/posts/2024-08-26-01.html
diff options
context:
space:
mode:
authora73x <[email protected]>2024-12-29 19:13:27 +0000
committera73x <[email protected]>2024-12-30 11:00:49 +0000
commita783270b09af3d873c08a01d13f802018b69fb02 (patch)
treebdac4e38357afa535515dd8dda790d7193f371d0 /public/posts/2024-08-26-01.html
parent71513b80ebc21240b5b68d8bbbf8b7ee2f54893e (diff)
new markdown renderer
since TOC has a title now and it can compact toc headers, we can use header 2 for everything use the built in goldmark extension for syntax highlighting
Diffstat (limited to 'public/posts/2024-08-26-01.html')
-rw-r--r--public/posts/2024-08-26-01.html428
1 files changed, 206 insertions, 222 deletions
diff --git a/public/posts/2024-08-26-01.html b/public/posts/2024-08-26-01.html
index 2272660..3dad915 100644
--- a/public/posts/2024-08-26-01.html
+++ b/public/posts/2024-08-26-01.html
@@ -25,254 +25,238 @@
<ul>
- <li><a class="no-decorations" href="/">home</a></li>
+ <li><a class="no-decorations" href="/">Home</a></li>
- <li><a class="no-decorations" href="/posts">posts</a></li>
+ <li><a class="no-decorations" href="/posts">Posts</a></li>
- <li><a class="no-decorations" href="/ethos">ethos</a></li>
+ <li><a class="no-decorations" href="/ethos">Ethos</a></li>
</ul>
</nav>
</div>
+ <hr />
<a href="/posts">← Posts</a>
<h1>Writing HTTP Handlers</h1>
-<p>I&rsquo;m sharing how I write handlers in Go.</p>
+<p>I'm sharing how I write handlers in Go.</p>
+<p>I write them like this for reasons that are probably fairly contextual. I've written a few applications and had to swap REST libraries or even swapped REST for GRPC, so things that make that easier speak to me a great deal.</p>
+<p>I've used <code>ints</code> instead of the <code>http.StatusXXXX</code> and omitted <code>JSON</code> tags in an attempt to try save up screen space.</p>
+<p>To begin with, you might have something like this:</p>
+<pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;white-space:pre-wrap;word-break:break-word;"><code><span style="color:#00a">package</span> main
-<p>I write them like this for reasons that are probably fairly contextual. I&rsquo;ve written a few applications and had to swap REST libraries or even swapped REST for GRPC, so things that make that easier speak to me a great deal.</p>
+<span style="color:#00a">import</span> (
+ <span style="color:#a50">&#34;fmt&#34;</span>
+ <span style="color:#a50">&#34;log&#34;</span>
+ <span style="color:#a50">&#34;net/http&#34;</span>
+)
-<p>I&rsquo;ve used <code>ints</code> instead of the <code>http.StatusXXXX</code> and omitted <code>JSON</code> tags in an attempt to try save up screen space.</p>
+<span style="color:#00a">func</span> <span style="color:#0a0">handler</span>(w http.ResponseWriter, r *http.Request) {
+ fmt.<span style="color:#0a0">Fprintf</span>(w, <span style="color:#a50">&#34;Hello, World!&#34;</span>)
+}
-<p>To begin with, you might have something like this:</p>
-<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
-</span></span><span class="line"><span class="cl"> <span class="s">&#34;fmt&#34;</span>
-</span></span><span class="line"><span class="cl"> <span class="s">&#34;log&#34;</span>
-</span></span><span class="line"><span class="cl"> <span class="s">&#34;net/http&#34;</span>
-</span></span><span class="line"><span class="cl"><span class="p">)</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">handler</span><span class="p">(</span><span class="nx">w</span> <span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="nx">r</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Fprintf</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span> <span class="s">&#34;Hello, World!&#34;</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">http</span><span class="p">.</span><span class="nf">HandleFunc</span><span class="p">(</span><span class="s">&#34;/&#34;</span><span class="p">,</span> <span class="nx">handler</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nf">ListenAndServe</span><span class="p">(</span><span class="s">&#34;:8080&#34;</span><span class="p">,</span> <span class="kc">nil</span><span class="p">))</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span></code></pre>
-<p>Then you might get told off because you&rsquo;ve just registered routes with the default mux, which isn&rsquo;t very testable.</p>
+<span style="color:#00a">func</span> <span style="color:#0a0">main</span>() {
+ http.<span style="color:#0a0">HandleFunc</span>(<span style="color:#a50">&#34;/&#34;</span>, handler)
+ log.<span style="color:#0a0">Fatal</span>(http.<span style="color:#0a0">ListenAndServe</span>(<span style="color:#a50">&#34;:8080&#34;</span>, <span style="color:#00a">nil</span>))
+}
+</code></pre><p>Then you might get told off because you've just registered routes with the default mux, which isn't very testable.</p>
<p>So you tweak it a little bit.</p>
-<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
-</span></span><span class="line"><span class="cl"> <span class="s">&#34;fmt&#34;</span>
-</span></span><span class="line"><span class="cl"> <span class="s">&#34;log&#34;</span>
-</span></span><span class="line"><span class="cl"> <span class="s">&#34;net/http&#34;</span>
-</span></span><span class="line"><span class="cl"><span class="p">)</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">handler</span><span class="p">(</span><span class="nx">w</span> <span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="nx">r</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Fprintf</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span> <span class="s">&#34;Hello, World!&#34;</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">newMux</span><span class="p">()</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">ServeMux</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">mux</span> <span class="o">:=</span> <span class="nx">http</span><span class="p">.</span><span class="nf">NewServeMux</span><span class="p">()</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">mux</span><span class="p">.</span><span class="nf">HandleFunc</span><span class="p">(</span><span class="s">&#34;/&#34;</span><span class="p">,</span> <span class="nx">handler</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">mux</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">Run</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">mux</span> <span class="o">:=</span> <span class="nf">newMux</span><span class="p">()</span>
-</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">http</span><span class="p">.</span><span class="nf">ListenAndServe</span><span class="p">(</span><span class="s">&#34;:8080&#34;</span><span class="p">,</span> <span class="nx">mux</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">Run</span><span class="p">();</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span></code></pre>
-<p><code>newMux()</code> gives you a <code>mux</code> to use when testing.</p>
+<pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;white-space:pre-wrap;word-break:break-word;"><code><span style="color:#00a">package</span> main
-<p><code>Run</code> keeps <code>main</code> nice and clean, so you can just return errors as needed instead of going <code>log.Fatal</code> and just generally being messy.</p>
+<span style="color:#00a">import</span> (
+ <span style="color:#a50">&#34;fmt&#34;</span>
+ <span style="color:#a50">&#34;log&#34;</span>
+ <span style="color:#a50">&#34;net/http&#34;</span>
+)
+
+<span style="color:#00a">func</span> <span style="color:#0a0">handler</span>(w http.ResponseWriter, r *http.Request) {
+ fmt.<span style="color:#0a0">Fprintf</span>(w, <span style="color:#a50">&#34;Hello, World!&#34;</span>)
+}
+
+<span style="color:#00a">func</span> <span style="color:#0a0">newMux</span>() *http.ServeMux {
+ mux := http.<span style="color:#0a0">NewServeMux</span>()
+ mux.<span style="color:#0a0">HandleFunc</span>(<span style="color:#a50">&#34;/&#34;</span>, handler)
+
+ <span style="color:#00a">return</span> mux
+}
+<span style="color:#00a">func</span> <span style="color:#0a0">Run</span>() <span style="color:#0aa">error</span> {
+ mux := <span style="color:#0a0">newMux</span>()
+ <span style="color:#00a">return</span> http.<span style="color:#0a0">ListenAndServe</span>(<span style="color:#a50">&#34;:8080&#34;</span>, mux)
+}
+
+<span style="color:#00a">func</span> <span style="color:#0a0">main</span>() {
+ <span style="color:#00a">if</span> err := <span style="color:#0a0">Run</span>(); err != <span style="color:#00a">nil</span> {
+ log.<span style="color:#0a0">Fatal</span>(err)
+ }
+}
+</code></pre><p><code>newMux()</code> gives you a <code>mux</code> to use when testing.</p>
+<p><code>Run</code> keeps <code>main</code> nice and clean, so you can just return errors as needed instead of going <code>log.Fatal</code> and just generally being messy.</p>
<p>But now you need to do something real, you want to store and fetch data.</p>
-<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
-</span></span><span class="line"><span class="cl"> <span class="s">&#34;encoding/json&#34;</span>
-</span></span><span class="line"><span class="cl"> <span class="s">&#34;fmt&#34;</span>
-</span></span><span class="line"><span class="cl"> <span class="s">&#34;log&#34;</span>
-</span></span><span class="line"><span class="cl"> <span class="s">&#34;net/http&#34;</span>
-</span></span><span class="line"><span class="cl"> <span class="s">&#34;strconv&#34;</span>
-</span></span><span class="line"><span class="cl"><span class="p">)</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">NewMux</span><span class="p">()</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">ServeMux</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">mux</span> <span class="o">:=</span> <span class="nx">http</span><span class="p">.</span><span class="nf">NewServeMux</span><span class="p">()</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">s</span> <span class="o">:=</span> <span class="nx">Server</span><span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">data</span><span class="p">:</span> <span class="nb">make</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">int</span><span class="p">]</span><span class="nx">Content</span><span class="p">),</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"> <span class="nx">s</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="nx">mux</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">mux</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">Run</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">mux</span> <span class="o">:=</span> <span class="nf">NewMux</span><span class="p">()</span>
-</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">http</span><span class="p">.</span><span class="nf">ListenAndServe</span><span class="p">(</span><span class="s">&#34;:8080&#34;</span><span class="p">,</span> <span class="nx">mux</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Server</span> <span class="kd">struct</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">data</span> <span class="kd">map</span><span class="p">[</span><span class="kt">int</span><span class="p">]</span><span class="nx">Content</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="o">*</span><span class="nx">Server</span><span class="p">)</span> <span class="nf">Register</span><span class="p">(</span><span class="nx">mux</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">ServeMux</span><span class="p">)</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">mux</span><span class="p">.</span><span class="nf">HandleFunc</span><span class="p">(</span><span class="s">&#34;GET /{id}&#34;</span><span class="p">,</span> <span class="nx">s</span><span class="p">.</span><span class="nx">Get</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">mux</span><span class="p">.</span><span class="nf">HandleFunc</span><span class="p">(</span><span class="s">&#34;POST /&#34;</span><span class="p">,</span> <span class="nx">s</span><span class="p">.</span><span class="nx">Post</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="o">*</span><span class="nx">Server</span><span class="p">)</span> <span class="nf">Get</span><span class="p">(</span><span class="nx">w</span> <span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="nx">r</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">idStr</span> <span class="o">:=</span> <span class="nx">r</span><span class="p">.</span><span class="nf">PathValue</span><span class="p">(</span><span class="s">&#34;id&#34;</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">id</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">strconv</span><span class="p">.</span><span class="nf">Atoi</span><span class="p">(</span><span class="nx">idStr</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">WriteHeader</span><span class="p">(</span><span class="mi">400</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">Write</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;failed to parse id: %v&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)))</span>
-</span></span><span class="line"><span class="cl"> <span class="k">return</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">data</span><span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="nx">s</span><span class="p">.</span><span class="nx">data</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span>
-</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">!</span><span class="nx">ok</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">WriteHeader</span><span class="p">(</span><span class="mi">404</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">Write</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&#34;not found&#34;</span><span class="p">))</span>
-</span></span><span class="line"><span class="cl"> <span class="k">return</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">Header</span><span class="p">().</span><span class="nf">Set</span><span class="p">(</span><span class="s">&#34;Content-Type&#34;</span><span class="p">,</span> <span class="s">&#34;application/json&#34;</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">WriteHeader</span><span class="p">(</span><span class="mi">200</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">json</span><span class="p">.</span><span class="nf">NewEncoder</span><span class="p">(</span><span class="nx">w</span><span class="p">).</span><span class="nf">Encode</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">ContentPostReq</span> <span class="kd">struct</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Foo</span> <span class="kt">string</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="o">*</span><span class="nx">Server</span><span class="p">)</span> <span class="nf">Post</span><span class="p">(</span><span class="nx">w</span> <span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="nx">r</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">req</span> <span class="o">:=</span> <span class="nx">ContentPostReq</span><span class="p">{}</span>
-</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">json</span><span class="p">.</span><span class="nf">NewDecoder</span><span class="p">(</span><span class="nx">r</span><span class="p">.</span><span class="nx">Body</span><span class="p">).</span><span class="nf">Decode</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">req</span><span class="p">);</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">WriteHeader</span><span class="p">(</span><span class="mi">400</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">Write</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;failed to parse request: %v&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)))</span>
-</span></span><span class="line"><span class="cl"> <span class="k">return</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">id</span> <span class="o">:=</span> <span class="nb">len</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">content</span> <span class="o">:=</span> <span class="nx">Content</span><span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">ID</span><span class="p">:</span> <span class="nx">id</span><span class="p">,</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Foo</span><span class="p">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">Foo</span><span class="p">,</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">s</span><span class="p">.</span><span class="nx">data</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="p">=</span> <span class="nx">content</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">WriteHeader</span><span class="p">(</span><span class="mi">200</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">json</span><span class="p">.</span><span class="nf">NewEncoder</span><span class="p">(</span><span class="nx">w</span><span class="p">).</span><span class="nf">Encode</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Content</span> <span class="kd">struct</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">ID</span> <span class="kt">int</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Foo</span> <span class="kt">string</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">Run</span><span class="p">();</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span></code></pre><pre tabindex="0" class="chroma"><code><span class="line"><span class="cl">❯ curl -X POST localhost:8080 --header <span class="s2">&#34;Content-Type: application/json&#34;</span> -d <span class="s1">&#39;{&#34;foo&#34;:&#34;bar&#34;}&#39;</span>
-</span></span><span class="line"><span class="cl"><span class="o">{</span><span class="s2">&#34;ID&#34;</span>:0,<span class="s2">&#34;Foo&#34;</span>:<span class="s2">&#34;bar&#34;</span><span class="o">}</span>
-</span></span><span class="line"><span class="cl">❯ curl -X GET localhost:8080/0
-</span></span><span class="line"><span class="cl"><span class="o">{</span><span class="s2">&#34;ID&#34;</span>:0,<span class="s2">&#34;Foo&#34;</span>:<span class="s2">&#34;bar&#34;</span><span class="o">}</span>
-</span></span></code></pre>
-<p>Erm, well, okay. Quite a bit has changed here, but I&rsquo;m sure you can read it. We now save and fetch very, very safely from a map and return the response as <code>JSON</code>. I&rsquo;ve done some things for brevity because I want to get to the main point.</p>
-
-<p>This API is inconsistent. It sometimes returns <code>JSON</code>, and the others return strings. Overall, it&rsquo;s just a mess.</p>
-
-<p>So let&rsquo;s try to standardise things.
-First, let&rsquo;s design some form of REST spec.</p>
-<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">JSONResp</span><span class="p">[</span><span class="nx">T</span> <span class="nx">any</span><span class="p">]</span> <span class="kd">struct</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Resources</span> <span class="p">[]</span><span class="nx">T</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Errs</span> <span class="p">[]</span><span class="nx">ErrorResp</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">ErrorResp</span> <span class="kd">struct</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Status</span> <span class="kt">int</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Msg</span> <span class="kt">string</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span></code></pre>
-<p>We want to be able to support fetching multiple resources at once, if we can only fetch some resources, let&rsquo;s return them under <code>resources</code> and show the errors under <code>errs</code></p>
+<pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;white-space:pre-wrap;word-break:break-word;"><code><span style="color:#00a">package</span> main
+
+<span style="color:#00a">import</span> (
+ <span style="color:#a50">&#34;encoding/json&#34;</span>
+ <span style="color:#a50">&#34;fmt&#34;</span>
+ <span style="color:#a50">&#34;log&#34;</span>
+ <span style="color:#a50">&#34;net/http&#34;</span>
+ <span style="color:#a50">&#34;strconv&#34;</span>
+)
+
+<span style="color:#00a">func</span> <span style="color:#0a0">NewMux</span>() *http.ServeMux {
+ mux := http.<span style="color:#0a0">NewServeMux</span>()
+ s := Server{
+ data: <span style="color:#0aa">make</span>(<span style="color:#00a">map</span>[<span style="color:#0aa">int</span>]Content),
+ }
+
+ s.<span style="color:#0a0">Register</span>(mux)
+ <span style="color:#00a">return</span> mux
+}
+
+<span style="color:#00a">func</span> <span style="color:#0a0">Run</span>() <span style="color:#0aa">error</span> {
+ mux := <span style="color:#0a0">NewMux</span>()
+ <span style="color:#00a">return</span> http.<span style="color:#0a0">ListenAndServe</span>(<span style="color:#a50">&#34;:8080&#34;</span>, mux)
+}
+
+<span style="color:#00a">type</span> Server <span style="color:#00a">struct</span> {
+ data <span style="color:#00a">map</span>[<span style="color:#0aa">int</span>]Content
+}
+<span style="color:#00a">func</span> (s *Server) <span style="color:#0a0">Register</span>(mux *http.ServeMux) {
+ mux.<span style="color:#0a0">HandleFunc</span>(<span style="color:#a50">&#34;GET /{id}&#34;</span>, s.Get)
+ mux.<span style="color:#0a0">HandleFunc</span>(<span style="color:#a50">&#34;POST /&#34;</span>, s.Post)
+}
+
+<span style="color:#00a">func</span> (s *Server) <span style="color:#0a0">Get</span>(w http.ResponseWriter, r *http.Request) {
+ idStr := r.<span style="color:#0a0">PathValue</span>(<span style="color:#a50">&#34;id&#34;</span>)
+ id, err := strconv.<span style="color:#0a0">Atoi</span>(idStr)
+ <span style="color:#00a">if</span> err != <span style="color:#00a">nil</span> {
+ w.<span style="color:#0a0">WriteHeader</span>(<span style="color:#099">400</span>)
+ w.<span style="color:#0a0">Write</span>([]<span style="color:#0aa">byte</span>(fmt.<span style="color:#0a0">Sprintf</span>(<span style="color:#a50">&#34;failed to parse id: %v&#34;</span>, err)))
+ <span style="color:#00a">return</span>
+ }
+ data, ok := s.data[id]
+ <span style="color:#00a">if</span> !ok {
+ w.<span style="color:#0a0">WriteHeader</span>(<span style="color:#099">404</span>)
+ w.<span style="color:#0a0">Write</span>([]<span style="color:#0aa">byte</span>(<span style="color:#a50">&#34;not found&#34;</span>))
+ <span style="color:#00a">return</span>
+ }
+ w.<span style="color:#0a0">Header</span>().<span style="color:#0a0">Set</span>(<span style="color:#a50">&#34;Content-Type&#34;</span>, <span style="color:#a50">&#34;application/json&#34;</span>)
+ w.<span style="color:#0a0">WriteHeader</span>(<span style="color:#099">200</span>)
+ json.<span style="color:#0a0">NewEncoder</span>(w).<span style="color:#0a0">Encode</span>(data)
+}
+
+<span style="color:#00a">type</span> ContentPostReq <span style="color:#00a">struct</span> {
+ Foo <span style="color:#0aa">string</span>
+}
+
+<span style="color:#00a">func</span> (s *Server) <span style="color:#0a0">Post</span>(w http.ResponseWriter, r *http.Request) {
+ req := ContentPostReq{}
+ <span style="color:#00a">if</span> err := json.<span style="color:#0a0">NewDecoder</span>(r.Body).<span style="color:#0a0">Decode</span>(&amp;req); err != <span style="color:#00a">nil</span> {
+ w.<span style="color:#0a0">WriteHeader</span>(<span style="color:#099">400</span>)
+ w.<span style="color:#0a0">Write</span>([]<span style="color:#0aa">byte</span>(fmt.<span style="color:#0a0">Sprintf</span>(<span style="color:#a50">&#34;failed to parse request: %v&#34;</span>, err)))
+ <span style="color:#00a">return</span>
+ }
+ id := <span style="color:#0aa">len</span>(s.data)
+ content := Content{
+ ID: id,
+ Foo: req.Foo,
+ }
+ s.data[id] = content
+
+ w.<span style="color:#0a0">WriteHeader</span>(<span style="color:#099">200</span>)
+ json.<span style="color:#0a0">NewEncoder</span>(w).<span style="color:#0a0">Encode</span>(content)
+}
+
+<span style="color:#00a">type</span> Content <span style="color:#00a">struct</span> {
+ ID <span style="color:#0aa">int</span>
+ Foo <span style="color:#0aa">string</span>
+}
+
+<span style="color:#00a">func</span> <span style="color:#0a0">main</span>() {
+ <span style="color:#00a">if</span> err := <span style="color:#0a0">Run</span>(); err != <span style="color:#00a">nil</span> {
+ log.<span style="color:#0a0">Fatal</span>(err)
+ }
+}
+</code></pre><pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;white-space:pre-wrap;word-break:break-word;"><code>❯ curl -X POST localhost:8080 --header <span style="color:#a50">&#34;Content-Type: application/json&#34;</span> -d <span style="color:#a50">&#39;{&#34;foo&#34;:&#34;bar&#34;}&#39;</span>
+{<span style="color:#a50">&#34;ID&#34;</span>:0,<span style="color:#a50">&#34;Foo&#34;</span>:<span style="color:#a50">&#34;bar&#34;</span>}
+❯ curl -X GET localhost:8080/0
+{<span style="color:#a50">&#34;ID&#34;</span>:0,<span style="color:#a50">&#34;Foo&#34;</span>:<span style="color:#a50">&#34;bar&#34;</span>}
+</code></pre><p>Erm, well, okay. Quite a bit has changed here, but I'm sure you can read it. We now save and fetch very, very safely from a map and return the response as <code>JSON</code>. I've done some things for brevity because I want to get to the main point.</p>
+<p>This API is inconsistent. It sometimes returns <code>JSON</code>, and the others return strings. Overall, it's just a mess.</p>
+<p>So let's try to standardise things.<br />
+First, let's design some form of REST spec.</p>
+<pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;white-space:pre-wrap;word-break:break-word;"><code><span style="color:#00a">type</span> JSONResp[T any] <span style="color:#00a">struct</span> {
+ Resources []T
+ Errs []ErrorResp
+}
+
+<span style="color:#00a">type</span> ErrorResp <span style="color:#00a">struct</span> {
+ Status <span style="color:#0aa">int</span>
+ Msg <span style="color:#0aa">string</span>
+}
+</code></pre><p>We want to be able to support fetching multiple resources at once, if we can only fetch some resources, let's return them under <code>resources</code> and show the errors under <code>errs</code></p>
<p>Now, add some helpful functions to handle things.</p>
-<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nx">Post</span><span class="p">[</span><span class="nx">In</span> <span class="nx">any</span><span class="p">,</span> <span class="nx">Out</span> <span class="nx">any</span><span class="p">](</span><span class="nx">successCode</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">fn</span> <span class="kd">func</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span> <span class="nx">In</span><span class="p">)</span> <span class="p">([]</span><span class="nx">Out</span><span class="p">,</span> <span class="p">[]</span><span class="nx">ErrorResp</span><span class="p">))</span> <span class="kd">func</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kd">func</span><span class="p">(</span><span class="nx">w</span> <span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="nx">r</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">v</span> <span class="nx">In</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">json</span><span class="p">.</span><span class="nf">NewDecoder</span><span class="p">(</span><span class="nx">r</span><span class="p">.</span><span class="nx">Body</span><span class="p">).</span><span class="nf">Decode</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">v</span><span class="p">);</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">writeJSONResp</span><span class="p">[</span><span class="nx">Out</span><span class="p">](</span><span class="nx">w</span><span class="p">,</span> <span class="nx">http</span><span class="p">.</span><span class="nx">StatusBadRequest</span><span class="p">,</span> <span class="kc">nil</span><span class="p">,</span> <span class="p">[]</span><span class="nx">ErrorResp</span><span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Status</span><span class="p">:</span> <span class="nx">http</span><span class="p">.</span><span class="nx">StatusBadRequest</span><span class="p">,</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Msg</span><span class="p">:</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;failed to parse request: %v&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">),</span>
-</span></span><span class="line"><span class="cl"> <span class="p">},</span>
-</span></span><span class="line"><span class="cl"> <span class="p">})</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"> <span class="k">return</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"> <span class="nx">res</span><span class="p">,</span> <span class="nx">errs</span> <span class="o">:=</span> <span class="nf">fn</span><span class="p">(</span><span class="nx">r</span><span class="p">.</span><span class="nf">Context</span><span class="p">(),</span> <span class="nx">v</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nf">writeJSONResp</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span> <span class="nx">successCode</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">errs</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nx">writeJSONResp</span><span class="p">[</span><span class="nx">T</span> <span class="nx">any</span><span class="p">](</span><span class="nx">w</span> <span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="nx">successCode</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">res</span> <span class="p">[]</span><span class="nx">T</span><span class="p">,</span> <span class="nx">errs</span> <span class="p">[]</span><span class="nx">ErrorResp</span><span class="p">)</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">body</span> <span class="o">:=</span> <span class="nx">JSONResp</span><span class="p">[</span><span class="nx">T</span><span class="p">]{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Resources</span><span class="p">:</span> <span class="nx">res</span><span class="p">,</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Errs</span><span class="p">:</span> <span class="nx">errs</span><span class="p">,</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"> <span class="nx">status</span> <span class="o">:=</span> <span class="nx">successCode</span>
-</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">e</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">errs</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">e</span><span class="p">.</span><span class="nx">Status</span> <span class="p">&gt;</span> <span class="nx">status</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">status</span> <span class="p">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">Status</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">Header</span><span class="p">().</span><span class="nf">Set</span><span class="p">(</span><span class="s">&#34;Content-Type&#34;</span><span class="p">,</span> <span class="s">&#34;application/json&#34;</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">WriteHeader</span><span class="p">(</span><span class="nx">status</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">json</span><span class="p">.</span><span class="nf">NewEncoder</span><span class="p">(</span><span class="nx">w</span><span class="p">).</span><span class="nf">Encode</span><span class="p">(</span><span class="nx">body</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span></code></pre>
-<p>And we&rsquo;ve standardised all <code>POST</code> requests!</p>
-
-<p>This function can be used by all <code>POST</code> requests, ensuring they adhere to the spec. It also removes the repetitive code around marshalling and unmarshalling to <code>JSON</code> and handles errors in a consistent manner.
+<pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;white-space:pre-wrap;word-break:break-word;"><code><span style="color:#00a">func</span> Post[In any, Out any](successCode <span style="color:#0aa">int</span>, fn <span style="color:#00a">func</span>(context.Context, In) ([]Out, []ErrorResp)) <span style="color:#00a">func</span>(http.ResponseWriter, *http.Request) {
+ <span style="color:#00a">return</span> <span style="color:#00a">func</span>(w http.ResponseWriter, r *http.Request) {
+ <span style="color:#00a">var</span> v In
+
+ <span style="color:#00a">if</span> err := json.<span style="color:#0a0">NewDecoder</span>(r.Body).<span style="color:#0a0">Decode</span>(&amp;v); err != <span style="color:#00a">nil</span> {
+ writeJSONResp[Out](w, http.StatusBadRequest, <span style="color:#00a">nil</span>, []ErrorResp{
+ {
+ Status: http.StatusBadRequest,
+ Msg: fmt.<span style="color:#0a0">Sprintf</span>(<span style="color:#a50">&#34;failed to parse request: %v&#34;</span>, err),
+ },
+ })
+
+ <span style="color:#00a">return</span>
+ }
+
+ res, errs := <span style="color:#0a0">fn</span>(r.<span style="color:#0a0">Context</span>(), v)
+ <span style="color:#0a0">writeJSONResp</span>(w, successCode, res, errs)
+ }
+}
+
+<span style="color:#00a">func</span> writeJSONResp[T any](w http.ResponseWriter, successCode <span style="color:#0aa">int</span>, res []T, errs []ErrorResp) {
+ body := JSONResp[T]{
+ Resources: res,
+ Errs: errs,
+ }
+
+ status := successCode
+ <span style="color:#00a">for</span> _, e := <span style="color:#00a">range</span> errs {
+ <span style="color:#00a">if</span> e.Status &gt; status {
+ status = e.Status
+ }
+ }
+ w.<span style="color:#0a0">Header</span>().<span style="color:#0a0">Set</span>(<span style="color:#a50">&#34;Content-Type&#34;</span>, <span style="color:#a50">&#34;application/json&#34;</span>)
+ w.<span style="color:#0a0">WriteHeader</span>(status)
+ json.<span style="color:#0a0">NewEncoder</span>(w).<span style="color:#0a0">Encode</span>(body)
+}
+</code></pre><p>And we've standardised all <code>POST</code> requests!</p>
+<p>This function can be used by all <code>POST</code> requests, ensuring they adhere to the spec. It also removes the repetitive code around marshalling and unmarshalling to <code>JSON</code> and handles errors in a consistent manner.<br />
The handler functions accept a <code>context</code> param and their expected struct input.</p>
-<pre tabindex="0" class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="o">*</span><span class="nx">Server</span><span class="p">)</span> <span class="nf">Register</span><span class="p">(</span><span class="nx">mux</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">ServeMux</span><span class="p">)</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"><span class="o">...</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">mux</span><span class="p">.</span><span class="nf">HandleFunc</span><span class="p">(</span><span class="s">&#34;POST /&#34;</span><span class="p">,</span> <span class="nf">Post</span><span class="p">(</span><span class="mi">201</span><span class="p">,</span> <span class="nx">s</span><span class="p">.</span><span class="nx">Post</span><span class="p">))</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="o">*</span><span class="nx">Server</span><span class="p">)</span> <span class="nf">Post</span><span class="p">(</span><span class="nx">ctx</span> <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span> <span class="nx">req</span> <span class="nx">ContentPostReq</span><span class="p">)</span> <span class="p">([]</span><span class="nx">Content</span><span class="p">,</span> <span class="p">[]</span><span class="nx">ErrorResp</span><span class="p">)</span> <span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">id</span> <span class="o">:=</span> <span class="nb">len</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">content</span> <span class="o">:=</span> <span class="nx">Content</span><span class="p">{</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">ID</span><span class="p">:</span> <span class="nx">id</span><span class="p">,</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">Foo</span><span class="p">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">Foo</span><span class="p">,</span>
-</span></span><span class="line"><span class="cl"> <span class="p">}</span>
-</span></span><span class="line"><span class="cl"> <span class="nx">s</span><span class="p">.</span><span class="nx">data</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="p">=</span> <span class="nx">content</span>
-</span></span><span class="line"><span class="cl">
-</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">[]</span><span class="nx">Content</span><span class="p">{</span><span class="nx">content</span><span class="p">},</span> <span class="kc">nil</span>
-</span></span><span class="line"><span class="cl"><span class="p">}</span>
-</span></span></code></pre>
-<p>As you can see, the post function is fairly cleaner now.</p>
+<pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;white-space:pre-wrap;word-break:break-word;"><code><span style="color:#00a">func</span> (s *Server) <span style="color:#0a0">Register</span>(mux *http.ServeMux) {
+...
+ mux.<span style="color:#0a0">HandleFunc</span>(<span style="color:#a50">&#34;POST /&#34;</span>, <span style="color:#0a0">Post</span>(<span style="color:#099">201</span>, s.Post))
+}
+
+<span style="color:#00a">func</span> (s *Server) <span style="color:#0a0">Post</span>(ctx context.Context, req ContentPostReq) ([]Content, []ErrorResp) {
+ id := <span style="color:#0aa">len</span>(s.data)
+ content := Content{
+ ID: id,
+ Foo: req.Foo,
+ }
+ s.data[id] = content
+ <span style="color:#00a">return</span> []Content{content}, <span style="color:#00a">nil</span>
+}
+</code></pre><p>As you can see, the post function is fairly cleaner now.</p>
<p>You can extend this to all the other request types. If you have query or path parameters, you could either pass in the request, write a custom struct tag parser, or find someone else who has already done it: <a href="https://github.com/gorilla/schema">https://github.com/gorilla/schema</a>.</p>