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:
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:
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
Hello! In this post, I will explain the cost-effective method I use to host my Go web applications with varying levels of complexity, all starting from as low as $5 per month. This method also allows to easy deploy and scale your golang application.
go hosting digitalocean dockerSince Go 1.19 we can use a new 103 (Early Hints)
http status code when we create web applications. Let’s figure out how and when this could help us.
We are going to create a simple golang web server that servers some html content. One html page will be served with 103
header and another one without.
After loading comparison we will see how early hints can improve page performance.
I guess that almost everyone in the go community was exciting when Go 1.18 was released, especially because of generics. Some days ago I decided to try generics in the real-world application, by refactoring some of its pieces, related to a caching logic.
go generics redis cacheThis time, I will show you how to work with the maps in go effectively and prevent the occurrence of the data race errors. Data races happen when several goroutines access the same resource concurrently and at least one of the accesses is a write.
go concurrent map data raceRecently, I discovered a surprisingly reliable memory caching solution, which I’m planning to use in all my further applications to increase performance. In this blog post, I will share some code examples of how you can integrate Ristretto caching library into your application.
go caching ristretto performance