<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Routing on WebDevStation</title>
    <link>https://webdevstation.com/tags/routing/</link>
    <description>2 articles tagged Routing — tutorials, code examples and notes from building real systems, newest first.</description>
    <generator>Hugo</generator>
    <language>en</language>
    <managingEditor>Alex</managingEditor>
    <webMaster>Alex</webMaster>
    <copyright>© 2026 WebDevStation</copyright>
    <lastBuildDate>Wed, 23 Dec 2020 19:10:56 +0000</lastBuildDate>
    <atom:link href="https://webdevstation.com/tags/routing/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>How to Control Router Access Permissions in Go Web Apps</title>
      <link>https://webdevstation.com/posts/how-to-control-router-access-permissions-in-go-web-apps/</link>
      <pubDate>Wed, 23 Dec 2020 19:10:56 +0000</pubDate>
      <author>Alex</author>
      <guid isPermaLink="true">https://webdevstation.com/posts/how-to-control-router-access-permissions-in-go-web-apps/</guid>
      <description>Learn how to implement URL-based access control and route permissions in Go web applications using the chi router middleware. A practical guide to securing your Go…</description>
      <content:encoded><![CDATA[<p>In this post I&rsquo;m going to describe how can we limit user access to the specific url in golang web application.
I will use <a href="https://github.com/go-chi/chi">chi</a> router - a lightweight, idiomatic and composable router for building
Go HTTP services.</p>
<p>Let&rsquo;s create our main package.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;net/http&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;github.com/go-chi/chi&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">chi</span>.<span style="color:#a6e22e">NewRouter</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;/&#34;</span>, <span style="color:#a6e22e">homePageHandler</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;/admin&#34;</span>, <span style="color:#a6e22e">adminPageHandler</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ListenAndServe</span>(<span style="color:#e6db74">&#34;:3000&#34;</span>, <span style="color:#a6e22e">r</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">homePageHandler</span>(<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">w</span>.<span style="color:#a6e22e">Write</span>([]byte(<span style="color:#e6db74">&#34;This is home page&#34;</span>)) 
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">adminPageHandler</span>(<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">w</span>.<span style="color:#a6e22e">Write</span>([]byte(<span style="color:#e6db74">&#34;This is admin page&#34;</span>)) 
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>After this, if we go to the <code>/admin</code> page, we will see &ldquo;This is admin page&rdquo;.</p>
<p>Now, let&rsquo;s make this path accessible only for admin.</p>
<p>We have to replace</p>
<p><code>r.Get(&quot;/admin&quot;, adminPageHandler)</code>
With
<code>r.Mount(&quot;/admin&quot;, adminRouter())</code></p>
<p>Mount attaches another http.Handler or chi Router as a subrouter along a routing path.</p>
<p>Then, we have to attach middleware inside adminRouter() function.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">adminRouter</span>() <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Handler</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">chi</span>.<span style="color:#a6e22e">NewRouter</span>()
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// Middleware with access rules for router.</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Use</span>(<span style="color:#a6e22e">AdminOnly</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;/&#34;</span>, <span style="color:#a6e22e">adminPageHandler</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">r</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>In this middleware we have a simple check is user authorized to access this page or not.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">AdminOnly</span>(<span style="color:#a6e22e">next</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Handler</span>) <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Handler</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">HandlerFunc</span>(<span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// If user is admin, allows access.</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">IsLoggedInAdmin</span>(<span style="color:#a6e22e">r</span>) {
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">next</span>.<span style="color:#a6e22e">ServeHTTP</span>(<span style="color:#a6e22e">w</span>, <span style="color:#a6e22e">r</span>)
</span></span><span style="display:flex;"><span>        } <span style="color:#66d9ef">else</span> {
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">// Otherwise, 403.</span>
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Error</span>(<span style="color:#a6e22e">w</span>, <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusText</span>(<span style="color:#ae81ff">403</span>), <span style="color:#ae81ff">403</span>)
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>In sake of demonstration, I&rsquo;m going just to use a random bool function to decide is used admin or not. You can modify this function according to your user authentication model.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">IsLoggedInAdmin</span>(<span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) <span style="color:#66d9ef">bool</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">rand</span>.<span style="color:#a6e22e">Float32</span>() &lt; <span style="color:#ae81ff">0.5</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>And that&rsquo;s it. Looks really simple, Isn&rsquo;t it?</p>
<p>Let&rsquo;s go to to the <code>/admin</code> page again.</p>
<p>As you see, now, sometimes (depends on our random decider), user has no access to this page anymore.</p>
<p>You can find source code <a href="https://github.com/alexsergivan/blog-examples/blob/master/route-auth/main.go">here</a></p>
<p>This builds directly on the pattern from <a href="/posts/go-middleware-example/">Go middleware example: how to alter a handler result</a>. For the authentication half of the problem, see <a href="/posts/user-authentication-with-go-using-jwt-token/">user authentication in Go Echo with JWT</a>.</p>]]></content:encoded>
      <category>Go Programming</category>
      <category>Web Development</category>
      <category>Security</category>
    </item>
    <item>
      <title>Go middleware example. How to alter a handler result</title>
      <link>https://webdevstation.com/posts/go-middleware-example/</link>
      <pubDate>Sun, 20 Dec 2020 20:12:51 +0000</pubDate>
      <author>Alex</author>
      <guid isPermaLink="true">https://webdevstation.com/posts/go-middleware-example/</guid>
      <description>Learn how to implement Go middleware to intercept and modify HTTP handler responses with practical examples using chi router, demonstrating request/response…</description>
      <content:encoded><![CDATA[<p>Let&rsquo;s imagine a situation when you want to alter the result, returned by some http handler to the client.
Fortunately, Golang provides an easy mechanism for that, called a middleware.
I&rsquo;m going to dive directly to the source code, to save your time.</p>
<p>Imagine, we have this simple web server (here I&rsquo;m using a chi router):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;bytes&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;github.com/go-chi/chi&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;io&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;log&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;net/http&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">chi</span>.<span style="color:#a6e22e">NewRouter</span>()
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;/&#34;</span>, <span style="color:#a6e22e">myFirstHandler</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ListenAndServe</span>(<span style="color:#e6db74">&#34;:3000&#34;</span>, <span style="color:#a6e22e">r</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">myFirstHandler</span>(<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">w</span>.<span style="color:#a6e22e">Write</span>([]byte(<span style="color:#e6db74">&#34;This is a main page&#34;</span>))
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>When we run this application and visit a frontpage htttp://localhost:3000/, we can see this:
<img src="/images/16122020/1.png" alt="Browser showing the JSON response returned by myFirstHandler on the front page" title="Response from the original Go handler"></p>
<p>Now we got a new requirement to create another handler which should get all response data
from myFirstHandler and add some modification on top.</p>
<p>We can do it easily in this way:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// Adds a new router handler with a middleware myMiddleware.  </span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">With</span>(<span style="color:#a6e22e">myMiddleware</span>).<span style="color:#a6e22e">Get</span>(<span style="color:#e6db74">&#34;/other&#34;</span>, <span style="color:#a6e22e">myFirstHandler</span>) 
</span></span></code></pre></div><p>To be able to read a response from other handler, we have to implement our own <code>ResponseWriter</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">MyResponseWriter</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>   <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>
</span></span><span style="display:flex;"><span>   <span style="color:#a6e22e">buf</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">bytes</span>.<span style="color:#a6e22e">Buffer</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Here we are implementing a Write() function from ResponseWriter with our custom instructions. </span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">myrw</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">MyResponseWriter</span>) <span style="color:#a6e22e">Write</span>(<span style="color:#a6e22e">p</span> []<span style="color:#66d9ef">byte</span>) (<span style="color:#66d9ef">int</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>   <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">myrw</span>.<span style="color:#a6e22e">buf</span>.<span style="color:#a6e22e">Write</span>(<span style="color:#a6e22e">p</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>And finally, let&rsquo;s write our middleware:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">myMiddleware</span>(<span style="color:#a6e22e">next</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Handler</span>) <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Handler</span> {
</span></span><span style="display:flex;"><span>   <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">HandlerFunc</span>(<span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">w</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">ResponseWriter</span>, <span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>) {
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">// Create a response writer:</span>
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">myResponseWriter</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">MyResponseWriter</span>{
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">ResponseWriter</span>: <span style="color:#a6e22e">w</span>,
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">buf</span>:            <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">bytes</span>.<span style="color:#a6e22e">Buffer</span>{},
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">// Here we are pssing our custom response writer to the next http handler.</span>
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">next</span>.<span style="color:#a6e22e">ServeHTTP</span>(<span style="color:#a6e22e">myResponseWriter</span>, <span style="color:#a6e22e">r</span>)
</span></span><span style="display:flex;"><span>      
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">// Here we are adding our custom stuff to the response, which we received after http handler execution. </span>
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">myResponseWriter</span>.<span style="color:#a6e22e">buf</span>.<span style="color:#a6e22e">WriteString</span>(<span style="color:#e6db74">&#34; and some additional modifications&#34;</span>)
</span></span><span style="display:flex;"><span>      
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">// And, finally, we are copiing everything back to the original response writer.  if _, err := io.Copy(w, myResponseWriter.buf); err != nil {</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">log</span>.<span style="color:#960050;background-color:#1e0010">`</span><span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Failed to send out response: %v&#34;</span>, <span style="color:#a6e22e">err</span>)
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>   })
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Now, if we run our server again and go to <code>/other</code> path, we will see this:
<img src="/images/16122020/2.png" alt="Browser showing the same response after the middleware appended its extra field" title="Response after the Go middleware altered it"></p>
<p>This was a silly example, which will never happen in real life, but, I hope you got an overview how you can play
with http handlers and middlewares.</p>
<p>The source code you can found in this repository: <a href="https://github.com/alexsergivan/blog-examples/tree/master/middleware">https://github.com/alexsergivan/blog-examples/tree/master/middleware</a></p>
<p>Middleware is where a lot of cross-cutting concerns end up living. Three I have written about since: <a href="/posts/how-to-control-router-access-permissions-in-go-web-apps/">controlling router access permissions</a>, <a href="/posts/rate-limiting-go-apis/">rate limiting your API</a>, and <a href="/posts/structured-logging-in-go-with-slog/">putting a request-scoped logger in the context</a>.</p>]]></content:encoded>
      <category>Go Programming</category>
      <category>Web Development</category>
    </item>
  </channel>
</rss>
