Go middleware example. How to alter a handler result
20 Dec 2020

Go middleware example. How to alter a handler result

Let’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’m going to dive directly to the source code, to save your time.

Imagine, we have this simple web server (here I’m using a chi router):


package main

import (
  "bytes"
  "github.com/go-chi/chi"
  "io"
  "log"
  "net/http"
)

func main() {
  r := chi.NewRouter()
  r.Get("/", myFirstHandler)

  http.ListenAndServe(":3000", r)
}

func myFirstHandler(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("This is a main page"))
}

When we run this application and visit a frontpage htttp://localhost:3000/, we can see this: alt text

Now we got a new requirement to create another handler which should get all response data from myFirstHandler and add some modification on top.

We can do it easily in this way:

// Adds a new router handler with a middleware myMiddleware.  
r.With(myMiddleware).Get("/other", myFirstHandler) 

To be able to read a response from other handler, we have to implement our own ResponseWriter:

type MyResponseWriter struct {
   http.ResponseWriter
   buf *bytes.Buffer
}

// Here we are implementing a Write() function from ResponseWriter with our custom instructions. 
func (myrw *MyResponseWriter) Write(p []byte) (int, error) {
   return myrw.buf.Write(p)
}

And finally, let’s write our middleware:


func myMiddleware(next http.Handler) http.Handler {
   return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
      // Create a response writer:
      myResponseWriter := &MyResponseWriter{
         ResponseWriter: w,
         buf:            &bytes.Buffer{},
      }
      // Here we are pssing our custom response writer to the next http handler.
      next.ServeHTTP(myResponseWriter, r)
      
      // Here we are adding our custom stuff to the response, which we received after http handler execution. 
      myResponseWriter.buf.WriteString(" and some additional modifications")
      
      // And, finally, we are copiing everything back to the original response writer.  if _, err := io.Copy(w, myResponseWriter.buf); err != nil {
         log.`Printf("Failed to send out response: %v", err)
      }
   })
}

Now, if we run our server again and go to /other path, we will see this: alt text

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.

The source code you can found in this repository: https://github.com/alexsergivan/blog-examples/tree/master/middleware

Related posts

A Simple Queue Implementation in Golang with channels
12 Jan 2021

A Simple Queue Implementation in Golang with channels

In this post, I’m going to show the way how we can implement a simple queue in Golang, using channels.

go queue channel goroutine
How to Sort Strings With Go Alphabetically in Any Language
4 Jan 2021

How to Sort Strings With Go Alphabetically in Any Language

In this article I’m going to show how easy we can sort strings alphabetically in different languages, using Go. It seems like an easy task if we want to sort English words, however, it’s not so trivial if we want to sort correctly strings with special characters or in other languages, i.e Cyrillic based.

go sorting alphabetical sort
How to Control Router Access Permissions in Go Web Apps
23 Dec 2020

How to Control Router Access Permissions in Go Web Apps

In this post I’m going to describe how can we limit user access to the specific url in golang web application. I will use chi router - a lightweight, idiomatic and composable router for building Go HTTP services.

go router chi
How to test database interactions in golang applications
22 Dec 2020

How to test database interactions in golang applications

Testing of functions with database interactions always was challenging. Recently, I found a wonderful library go-sqlmock which will simplify writing tests and mocking database queries in golang applications a lot.

go testing sql