diff options
| author | a73x <[email protected]> | 2024-12-29 19:13:27 +0000 |
|---|---|---|
| committer | a73x <[email protected]> | 2024-12-30 11:00:49 +0000 |
| commit | a783270b09af3d873c08a01d13f802018b69fb02 (patch) | |
| tree | bdac4e38357afa535515dd8dda790d7193f371d0 /public/posts/2024-08-26-01.html | |
| parent | 71513b80ebc21240b5b68d8bbbf8b7ee2f54893e (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.html | 428 |
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’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’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">"fmt"</span> + <span style="color:#a50">"log"</span> + <span style="color:#a50">"net/http"</span> +) -<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> +<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">"Hello, World!"</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">"fmt"</span> -</span></span><span class="line"><span class="cl"> <span class="s">"log"</span> -</span></span><span class="line"><span class="cl"> <span class="s">"net/http"</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">"Hello, World!"</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">"/"</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">":8080"</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’ve just registered routes with the default mux, which isn’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">"/"</span>, handler) + log.<span style="color:#0a0">Fatal</span>(http.<span style="color:#0a0">ListenAndServe</span>(<span style="color:#a50">":8080"</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">"fmt"</span> -</span></span><span class="line"><span class="cl"> <span class="s">"log"</span> -</span></span><span class="line"><span class="cl"> <span class="s">"net/http"</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">"Hello, World!"</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">"/"</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">":8080"</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">"fmt"</span> + <span style="color:#a50">"log"</span> + <span style="color:#a50">"net/http"</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">"Hello, World!"</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">"/"</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">":8080"</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">"encoding/json"</span> -</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span> -</span></span><span class="line"><span class="cl"> <span class="s">"log"</span> -</span></span><span class="line"><span class="cl"> <span class="s">"net/http"</span> -</span></span><span class="line"><span class="cl"> <span class="s">"strconv"</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">":8080"</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">"GET /{id}"</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">"POST /"</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">"id"</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">"failed to parse id: %v"</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">"not found"</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">"Content-Type"</span><span class="p">,</span> <span class="s">"application/json"</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">&</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">"failed to parse request: %v"</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">"Content-Type: application/json"</span> -d <span class="s1">'{"foo":"bar"}'</span> -</span></span><span class="line"><span class="cl"><span class="o">{</span><span class="s2">"ID"</span>:0,<span class="s2">"Foo"</span>:<span class="s2">"bar"</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">"ID"</span>:0,<span class="s2">"Foo"</span>:<span class="s2">"bar"</span><span class="o">}</span> -</span></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. -First, let’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’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">"encoding/json"</span> + <span style="color:#a50">"fmt"</span> + <span style="color:#a50">"log"</span> + <span style="color:#a50">"net/http"</span> + <span style="color:#a50">"strconv"</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">":8080"</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">"GET /{id}"</span>, s.Get) + mux.<span style="color:#0a0">HandleFunc</span>(<span style="color:#a50">"POST /"</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">"id"</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">"failed to parse id: %v"</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">"not found"</span>)) + <span style="color:#00a">return</span> + } + w.<span style="color:#0a0">Header</span>().<span style="color:#0a0">Set</span>(<span style="color:#a50">"Content-Type"</span>, <span style="color:#a50">"application/json"</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>(&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">"failed to parse request: %v"</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">"Content-Type: application/json"</span> -d <span style="color:#a50">'{"foo":"bar"}'</span> +{<span style="color:#a50">"ID"</span>:0,<span style="color:#a50">"Foo"</span>:<span style="color:#a50">"bar"</span>} +❯ curl -X GET localhost:8080/0 +{<span style="color:#a50">"ID"</span>:0,<span style="color:#a50">"Foo"</span>:<span style="color:#a50">"bar"</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">&</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">"failed to parse request: %v"</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">></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">"Content-Type"</span><span class="p">,</span> <span class="s">"application/json"</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’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>(&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">"failed to parse request: %v"</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 > status { + status = e.Status + } + } + w.<span style="color:#0a0">Header</span>().<span style="color:#0a0">Set</span>(<span style="color:#a50">"Content-Type"</span>, <span style="color:#a50">"application/json"</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">"POST /"</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">"POST /"</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> |
