personal-blog/public/posts/writing-a-golang-middleware.../index.html

468 lines
42 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="en-us">
<head>
<link rel="preload" href="/lib/font-awesome/webfonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/lib/font-awesome/webfonts/fa-regular-400.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/lib/font-awesome/webfonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/lib/JetBrainsMono/web/woff2/JetBrainsMono-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<script type="text/javascript" src="https://latest.cactus.chat/cactus.js"></script>
<link rel="stylesheet" href="https://latest.cactus.chat/style.css" type="text/css">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title> Writing a Middleware for your HTTP handler Golang | Basit&#39;s Blog</title>
<link rel = 'canonical' href = 'https://blog.rjbasitali.com/posts/writing-a-golang-middleware-for-your-http-handler/'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="all,follow">
<meta name="googlebot" content="index,follow,snippet,archive">
<meta property="og:title" content="Writing a Middleware for your HTTP handler Golang" />
<meta property="og:description" content="If you are a backend developer working daily with HTTP requests then you have most likely already encountered situations where you want a common functionality across all the incoming HTTP requests, which can be as simple as checking if the Content-Type header only has the value application/json if you only support json, or maybe you want to spoof your HTTP request to change the method type from POST,GET or PUT to something else based on the X-HTTP-Method-Override header, or of course authenticate before finally passing the request to the destination HTTP handler." />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://blog.rjbasitali.com/posts/writing-a-golang-middleware-for-your-http-handler/" /><meta property="article:section" content="posts" />
<meta property="article:published_time" content="2021-08-01T22:05:04+05:00" />
<meta property="article:modified_time" content="2021-08-01T22:05:04+05:00" />
<meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Writing a Middleware for your HTTP handler Golang"/>
<meta name="twitter:description" content="If you are a backend developer working daily with HTTP requests then you have most likely already encountered situations where you want a common functionality across all the incoming HTTP requests, which can be as simple as checking if the Content-Type header only has the value application/json if you only support json, or maybe you want to spoof your HTTP request to change the method type from POST,GET or PUT to something else based on the X-HTTP-Method-Override header, or of course authenticate before finally passing the request to the destination HTTP handler."/>
<link rel="stylesheet" href="https://blog.rjbasitali.com/css/styles.94f653e9e151e28067a7c5dbbc4600cbd5a3c721e79faaf971e523c40f3b249b8e4f20bb57810dfffa8d559ca5c140fd56eb4cd9c0853113ad08e66afdb08bdd.css" integrity="sha512-lPZT6eFR4oBnp8XbvEYAy9WjxyHnn6r5ceUjxA87JJuOTyC7V4EN//qNVZylwUD9VutM2cCFMROtCOZq/bCL3Q==">
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<link rel="icon" type="image/png" href="https://blog.rjbasitali.com/images/favicon.ico" />
<script async src="https://www.googletagmanager.com/gtag/js?id=G-N33SDFP4VQ"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-N33SDFP4VQ');
</script>
</head>
<body class="max-width mx-auto px3 ltr">
<div class="content index py4">
<div id="header-post">
<a id="menu-icon" href="#"><i class="fas fa-bars fa-lg"></i></a>
<a id="menu-icon-tablet" href="#"><i class="fas fa-bars fa-lg"></i></a>
<a id="top-icon-tablet" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');" style="display:none;" aria-label="Top of Page"><i class="fas fa-chevron-up fa-lg"></i></a>
<span id="menu">
<span id="nav">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/tags">Tags</a></li>
<li><a href="/about">About</a></li>
</ul>
</span>
<br/>
<span id="actions">
<ul>
<li>
<a class="icon" href=" https://blog.rjbasitali.com/contact/" aria-label="Previous">
<i class="fas fa-chevron-left" aria-hidden="true" onmouseover="$('#i-prev').toggle();" onmouseout="$('#i-prev').toggle();"></i>
</a>
</li>
<li>
<a class="icon" href="https://blog.rjbasitali.com/posts/writing-your-own-reverse-proxy-using-golang/" aria-label="Next">
<i class="fas fa-chevron-right" aria-hidden="true" onmouseover="$('#i-next').toggle();" onmouseout="$('#i-next').toggle();"></i>
</a>
</li>
<li>
<a class="icon" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');" aria-label="Top of Page">
<i class="fas fa-chevron-up" aria-hidden="true" onmouseover="$('#i-top').toggle();" onmouseout="$('#i-top').toggle();"></i>
</a>
</li>
<li>
<a class="icon" href="#" aria-label="Share">
<i class="fas fa-share-alt" aria-hidden="true" onmouseover="$('#i-share').toggle();" onmouseout="$('#i-share').toggle();" onclick="$('#share').toggle();return false;"></i>
</a>
</li>
</ul>
<span id="i-prev" class="info" style="display:none;">Previous post</span>
<span id="i-next" class="info" style="display:none;">Next post</span>
<span id="i-top" class="info" style="display:none;">Back to top</span>
<span id="i-share" class="info" style="display:none;">Share post</span>
</span>
<br/>
<div id="share" style="display: none">
<ul>
<li>
<a class="icon" href="http://www.facebook.com/sharer.php?u=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f" aria-label="Facebook">
<i class="fab fa-facebook " aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://twitter.com/share?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&text=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="Twitter">
<i class="fab fa-twitter " aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="http://www.linkedin.com/shareArticle?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&title=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="Linkedin">
<i class="fab fa-linkedin " aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://pinterest.com/pin/create/bookmarklet/?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&is_video=false&description=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="Pinterest">
<i class="fab fa-pinterest " aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="mailto:?subject=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang&body=Check out this article: https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f" aria-label="Email">
<i class="fas fa-envelope " aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://getpocket.com/save?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&title=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="Pocket">
<i class="fab fa-get-pocket " aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="http://reddit.com/submit?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&title=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="reddit">
<i class="fab fa-reddit " aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="http://www.tumblr.com/share/link?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&name=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang&description=If%20you%20are%20a%20backend%20developer%20working%20daily%20with%20HTTP%20requests%20then%20you%20have%20most%20likely%20already%20encountered%20situations%20where%20you%20want%20a%20common%20functionality%20across%20all%20the%20incoming%20HTTP%20requests%2c%20which%20can%20be%20as%20simple%20as%20checking%20if%20the%20Content-Type%20header%20only%20has%20the%20value%20application%2fjson%20if%20you%20only%20support%20json%2c%20or%20maybe%20you%20want%20to%20spoof%20your%20HTTP%20request%20to%20change%20the%20method%20type%20from%20POST%2cGET%20or%20PUT%20to%20something%20else%20based%20on%20the%20X-HTTP-Method-Override%20header%2c%20or%20of%20course%20authenticate%20before%20finally%20passing%20the%20request%20to%20the%20destination%20HTTP%20handler." aria-label="Tumblr">
<i class="fab fa-tumblr " aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://news.ycombinator.com/submitlink?u=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&t=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="Hacker News">
<i class="fab fa-hacker-news " aria-hidden="true"></i>
</a>
</li>
</ul>
</div>
<div id="toc">
<nav id="TableOfContents"></nav>
</div>
</span>
</div>
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<header>
<h1 class="posttitle" itemprop="name headline">
Writing a Middleware for your HTTP handler Golang
</h1>
<div class="meta">
<div class="postdate">
<time datetime="2021-08-01 22:05:04 &#43;0500 PKT" itemprop="datePublished">2021-08-01</time>
</div>
<div class="article-read-time">
<i class="far fa-clock"></i>
4 minute read
</div>
<div class="article-tag">
<i class="fas fa-tag"></i>
<a class="tag-link" href="/tags/golang" rel="tag">golang</a>
,
<a class="tag-link" href="/tags/middleware" rel="tag">middleware</a>
,
<a class="tag-link" href="/tags/http" rel="tag">http</a>
,
<a class="tag-link" href="/tags/handler" rel="tag">handler</a>
</div>
</div>
</header>
<div class="content" itemprop="articleBody">
<p>If you are a backend developer working daily with HTTP requests then you have most likely already encountered situations where you want a common functionality across all the incoming HTTP requests, which can be as simple as checking if the <code>Content-Type</code> header only has the value <code>application/json</code> if you only support json, or maybe you want to spoof your HTTP request to change the method type from <code>POST</code>,<code>GET</code> or <code>PUT</code> to something else based on the <code>X-HTTP-Method-Override</code> header, or of course authenticate before finally passing the request to the destination HTTP handler.</p>
<p><img src="/posts/img/2021/middleware-header.png" alt="middlewares"></p>
<p>You can achieve the following behaviour by writing a <code>middleware</code>, also known as a <code>filter</code> in some other backend frameworks. You can have as many middlewares as you want, each with a separate responsibility, and can chain them together to funnel incoming HTTP requests.</p>
<p>Writing a <code>middleware</code> in Go is pretty simple, you just need to <strong>wrap</strong> your <code>middleware</code> around the base HTTP handler, which so to speak is a thin <strong>wrapper</strong> around your HTTP handler.</p>
<p>Lets start with <code>http</code> package&rsquo;s <code>ListenAndServe</code> method, which listens for incoming connections and serves with the handler to handle the requests, and lets write a handler for root <code>&quot;/&quot;</code> path which checks for the header <code>Content-Type</code> to see if it&rsquo;s <code>application/json</code>, because our API only accepts JSON, and respond with following json <code>{&quot;msg&quot;:&quot;Hello world!&quot;}</code> to any incoming request:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">main</span>() {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span> mux <span style="color:#ff79c6">:=</span> http.<span style="color:#50fa7b">NewServeMux</span>()
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span> mux.<span style="color:#50fa7b">HandleFunc</span>(<span style="color:#f1fa8c">&#34;/&#34;</span>, rootHandler)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span> http.<span style="color:#50fa7b">ListenAndServe</span>(<span style="color:#f1fa8c">&#34;:8080&#34;</span>, mux)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span> }
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">rootHandler</span>(w http.ResponseWriter, r <span style="color:#ff79c6">*</span>http.Request) {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span> <span style="color:#ff79c6">if</span> r.Header.<span style="color:#50fa7b">Get</span>(<span style="color:#f1fa8c">&#34;Content-Type&#34;</span>) <span style="color:#ff79c6">!=</span> <span style="color:#f1fa8c">&#34;application/json&#34;</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span> http.<span style="color:#50fa7b">Error</span>(w, <span style="color:#f1fa8c">&#34;Only application/json content type supported&#34;</span>, http.StatusUnsupportedMediaType)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span> <span style="color:#ff79c6">return</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span> }
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span> w.<span style="color:#50fa7b">Write</span>([]<span style="color:#8be9fd;font-style:italic">byte</span>(<span style="color:#f1fa8c">`{&#34;msg&#34;:&#34;Hello world!&#34;}`</span>))
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13</span><span> }
</span></span></code></pre></div><p>Of course in reality you could have a dozen of handlers each with a different endpoint, but lets keep it simple for this tutorial.</p>
<p>Now let&rsquo;s assume we have a dozen request handlers in our project and we want each handler to check for <code>Content-Type</code> header as we did in our <code>rootHandler</code>, we want our code to be DRY <em>(Don&rsquo;t Repeat Yourself)</em>.</p>
<p>Which brings us to writing a <code>middleware</code> to check the <code>Content-Type</code> header for each incoming request. Lets write a middleware and call it <code>wrap</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">wrap</span>(next http.Handler) http.Handler {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2</span><span> <span style="color:#ff79c6">return</span> http.<span style="color:#50fa7b">HandlerFunc</span>(<span style="color:#8be9fd;font-style:italic">func</span>(w http.ResponseWriter, r <span style="color:#ff79c6">*</span>http.Request) {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3</span><span> <span style="color:#6272a4">// middleware logic
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4</span><span><span style="color:#6272a4"></span> next.<span style="color:#50fa7b">ServeHTTP</span>(w, r)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5</span><span> })
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6</span><span> }
</span></span></code></pre></div><p>The <code>wrap</code> function takes in a <code>Handler</code> and returns a <code>Handler</code>, this syntax allows it to be used where we would normally use a request handler, and also allow us to chain multiple middlewares together. Now we can do something like <code>wrap(handler)</code> instead of just using <code>handler</code>, this would call our <code>middleware</code> logic before calling <code>next.ServeHTTP(w, r)</code> which can be the next middleware in the chain or a final call to our request handler.</p>
<p>In the following example, we are wrapping our <code>wrap</code> middleware around <code>mux</code> so every incoming request will pass through our middleware first:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">main</span>() {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span> mux <span style="color:#ff79c6">:=</span> http.<span style="color:#50fa7b">NewServeMux</span>()
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span> mux.<span style="color:#50fa7b">HandleFunc</span>(<span style="color:#f1fa8c">&#34;/&#34;</span>, rootHandler)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span> http.<span style="color:#50fa7b">ListenAndServe</span>(<span style="color:#f1fa8c">&#34;:8080&#34;</span>, <span style="color:#50fa7b">wrap</span>(mux))
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span> }
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">rootHandler</span>(w http.ResponseWriter, r <span style="color:#ff79c6">*</span>http.Request) {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span> w.<span style="color:#50fa7b">Write</span>([]<span style="color:#8be9fd;font-style:italic">byte</span>(<span style="color:#f1fa8c">`{&#34;msg&#34;:&#34;Hello world!&#34;}`</span>))
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span> }
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">wrap</span>(next http.Handler) http.Handler {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span> <span style="color:#ff79c6">return</span> http.<span style="color:#50fa7b">HandlerFunc</span>(<span style="color:#8be9fd;font-style:italic">func</span>(w http.ResponseWriter, r <span style="color:#ff79c6">*</span>http.Request) {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13</span><span> <span style="color:#ff79c6">if</span> r.Header.<span style="color:#50fa7b">Get</span>(<span style="color:#f1fa8c">&#34;Content-Type&#34;</span>) <span style="color:#ff79c6">!=</span> <span style="color:#f1fa8c">&#34;application/json&#34;</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14</span><span> http.<span style="color:#50fa7b">Error</span>(w, <span style="color:#f1fa8c">&#34;Only application/json content type supported&#34;</span>, http.StatusUnsupportedMediaType)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15</span><span> <span style="color:#ff79c6">return</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16</span><span> }
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17</span><span> next.<span style="color:#50fa7b">ServeHTTP</span>(w, r)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18</span><span> })
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19</span><span> }
</span></span></code></pre></div><p>So far we&rsquo;ve been using a single middleware, lets see multiple middlewares chained together in action. We can define multiple middlewares with the same signature as of <code>wrap</code>, replacing the comment <code>// middleware logic</code> with our code.</p>
<blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">wrap</span>(next http.Handler) http.Handler {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2</span><span> <span style="color:#ff79c6">return</span> http.<span style="color:#50fa7b">HandlerFunc</span>(<span style="color:#8be9fd;font-style:italic">func</span>(w http.ResponseWriter, r <span style="color:#ff79c6">*</span>http.Request) {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3</span><span> <span style="color:#6272a4">// middleware logic
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4</span><span><span style="color:#6272a4"></span> next.<span style="color:#50fa7b">ServeHTTP</span>(w, r)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5</span><span> })
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6</span><span> }
</span></span></code></pre></div></blockquote>
<p>Lets rename <code>wrap</code> to <code>enforceJSON</code>, and write another <code>middleware</code> which will log every incoming request&rsquo;s method and path, and chain them both together:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">main</span>() {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span> mux <span style="color:#ff79c6">:=</span> http.<span style="color:#50fa7b">NewServeMux</span>()
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span> mux.<span style="color:#50fa7b">HandleFunc</span>(<span style="color:#f1fa8c">&#34;/&#34;</span>, rootHandler)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span> http.<span style="color:#50fa7b">ListenAndServe</span>(<span style="color:#f1fa8c">&#34;:8080&#34;</span>, <span style="color:#50fa7b">logRequest</span>(<span style="color:#50fa7b">enforceJSON</span>(mux)))
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span> }
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">rootHandler</span>(w ResponseWriter, r <span style="color:#ff79c6">*</span>Request) {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span> w.<span style="color:#50fa7b">Write</span>([]<span style="color:#8be9fd;font-style:italic">byte</span>(<span style="color:#f1fa8c">`{&#34;msg&#34;:&#34;Hello world!&#34;}`</span>))
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span> }
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">logRequest</span>(next http.Handler) http.Handler {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span> <span style="color:#ff79c6">return</span> http.<span style="color:#50fa7b">HandlerFunc</span>(<span style="color:#8be9fd;font-style:italic">func</span>(w http.ResponseWriter, r <span style="color:#ff79c6">*</span>http.Request) {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13</span><span> fmt.<span style="color:#50fa7b">Println</span>(r.Method, r.URL.Path) <span style="color:#6272a4">// logs: GET /v1/users/1234
</span></span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14</span><span><span style="color:#6272a4"></span> next.<span style="color:#50fa7b">ServeHTTP</span>(w, r)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15</span><span> })
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16</span><span> }
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">enforceJSON</span>(next http.Handler) http.Handler {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19</span><span> <span style="color:#ff79c6">return</span> http.<span style="color:#50fa7b">HandlerFunc</span>(<span style="color:#8be9fd;font-style:italic">func</span>(w http.ResponseWriter, r <span style="color:#ff79c6">*</span>http.Request) {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20</span><span> <span style="color:#ff79c6">if</span> r.Header.<span style="color:#50fa7b">Get</span>(<span style="color:#f1fa8c">&#34;Content-Type&#34;</span>) <span style="color:#ff79c6">!=</span> <span style="color:#f1fa8c">&#34;application/json&#34;</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21</span><span> http.<span style="color:#50fa7b">Error</span>(w, <span style="color:#f1fa8c">&#34;Only application/json content type supported&#34;</span>, http.StatusUnsupportedMediaType)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22</span><span> <span style="color:#ff79c6">return</span>
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23</span><span> }
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24</span><span> next.<span style="color:#50fa7b">ServeHTTP</span>(w, r)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25</span><span> })
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26</span><span> }
</span></span></code></pre></div><p>See how we are using <code>logRequest(enforceJSON(mux))</code> instead of <code>wrap(mux)</code>? Now every incoming HTTP request will be logged and then checked for <code>Content-Type</code> before being passed onto the handler.</p>
<p>A cleaner way to chain multiple handlers is writing a single <code>wrap</code> middleware and chain all the middlewares inside <code>wrap</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span> <span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">wrap</span>(handler http.Handler) http.Handler {
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2</span><span> handler = <span style="color:#50fa7b">enforceJSON</span>(handler)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3</span><span> handler = <span style="color:#50fa7b">logRequest</span>(handler)
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4</span><span> <span style="color:#ff79c6">return</span> handler
</span></span><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5</span><span> }
</span></span></code></pre></div><p>And then instead of:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span> http.<span style="color:#50fa7b">ListenAndServe</span>(<span style="color:#f1fa8c">&#34;:8080&#34;</span>, <span style="color:#50fa7b">logRequest</span>(<span style="color:#50fa7b">enforceJSON</span>(mux)))
</span></span></code></pre></div><p>We can use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span style="white-space:pre;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span> http.<span style="color:#50fa7b">ListenAndServe</span>(<span style="color:#f1fa8c">&#34;:8080&#34;</span>, <span style="color:#50fa7b">wrap</span>(mux))
</span></span></code></pre></div><hr>
<p>That&rsquo;s all on middlewares in golang today. Hope it was useful with your understanding on middlewares or how to write them.</p>
</div>
</article>
<div id="footer-post-container">
<div id="footer-post">
<div id="nav-footer" style="display: none">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/tags">Tags</a></li>
<li><a href="/about">About</a></li>
</ul>
</div>
<div id="toc-footer" style="display: none">
<nav id="TableOfContents"></nav>
</div>
<div id="share-footer" style="display: none">
<ul>
<li>
<a class="icon" href="http://www.facebook.com/sharer.php?u=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f" aria-label="Facebook">
<i class="fab fa-facebook fa-lg" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://twitter.com/share?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&text=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="Twitter">
<i class="fab fa-twitter fa-lg" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="http://www.linkedin.com/shareArticle?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&title=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="Linkedin">
<i class="fab fa-linkedin fa-lg" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://pinterest.com/pin/create/bookmarklet/?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&is_video=false&description=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="Pinterest">
<i class="fab fa-pinterest fa-lg" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="mailto:?subject=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang&body=Check out this article: https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f" aria-label="Email">
<i class="fas fa-envelope fa-lg" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://getpocket.com/save?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&title=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="Pocket">
<i class="fab fa-get-pocket fa-lg" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="http://reddit.com/submit?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&title=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="reddit">
<i class="fab fa-reddit fa-lg" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="http://www.tumblr.com/share/link?url=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&name=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang&description=If%20you%20are%20a%20backend%20developer%20working%20daily%20with%20HTTP%20requests%20then%20you%20have%20most%20likely%20already%20encountered%20situations%20where%20you%20want%20a%20common%20functionality%20across%20all%20the%20incoming%20HTTP%20requests%2c%20which%20can%20be%20as%20simple%20as%20checking%20if%20the%20Content-Type%20header%20only%20has%20the%20value%20application%2fjson%20if%20you%20only%20support%20json%2c%20or%20maybe%20you%20want%20to%20spoof%20your%20HTTP%20request%20to%20change%20the%20method%20type%20from%20POST%2cGET%20or%20PUT%20to%20something%20else%20based%20on%20the%20X-HTTP-Method-Override%20header%2c%20or%20of%20course%20authenticate%20before%20finally%20passing%20the%20request%20to%20the%20destination%20HTTP%20handler." aria-label="Tumblr">
<i class="fab fa-tumblr fa-lg" aria-hidden="true"></i>
</a>
</li>
<li>
<a class="icon" href="https://news.ycombinator.com/submitlink?u=https%3a%2f%2fblog.rjbasitali.com%2fposts%2fwriting-a-golang-middleware-for-your-http-handler%2f&t=Writing%20a%20Middleware%20for%20your%20HTTP%20handler%20%e2%80%93%20Golang" aria-label="Hacker News">
<i class="fab fa-hacker-news fa-lg" aria-hidden="true"></i>
</a>
</li>
</ul>
</div>
<div id="actions-footer">
<a id="menu-toggle" class="icon" href="#" onclick="$('#nav-footer').toggle();return false;" aria-label="Menu">
<i class="fas fa-bars fa-lg" aria-hidden="true"></i> Menu</a>
<a id="toc-toggle" class="icon" href="#" onclick="$('#toc-footer').toggle();return false;" aria-label="TOC">
<i class="fas fa-list fa-lg" aria-hidden="true"></i> TOC</a>
<a id="share-toggle" class="icon" href="#" onclick="$('#share-footer').toggle();return false;" aria-label="Share">
<i class="fas fa-share-alt fa-lg" aria-hidden="true"></i> share</a>
<a id="top" style="display:none" class="icon" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');" aria-label="Top of Page">
<i class="fas fa-chevron-up fa-lg" aria-hidden="true"></i> Top</a>
</div>
</div>
</div>
<footer id="footer">
<div class="footer-left">
Copyright &copy; 2022 Basit Ali
</div>
<div class="footer-right">
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/tags">Tags</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</div>
</footer>
</div>
</body>
<link rel="stylesheet" href=/lib/font-awesome/css/all.min.css>
<script src=/lib/jquery/jquery.min.js></script>
<script src=/js/main.js></script>
<script src=/js/code-copy.js></script>
</html>