paint-brush
Simple HTTP middleware with Goby@gbbr
18,332 reads
18,332 reads

Simple HTTP middleware with Go

by Gabriel AszalosSeptember 11th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

It is a common requirement to encounter the necessity of having various operations needed around incoming <a href="https://hackernoon.com/tagged/http" target="_blank">HTTP</a> requests to your server. The most prevalent examples would be logging and tracing. Although there are various frameworks out there that provide this out of the box, I’d like to illustrate how simple it is to create this logic using nothing but the standard library. Building your own implementation gives you full flexibility and control over the behaviour, reducing the need for external dependencies.

Coin Mentioned

Mention Thumbnail
featured image - Simple HTTP middleware with Go
Gabriel Aszalos HackerNoon profile picture

Using nothing but the standard library

It is a common requirement to encounter the necessity of having various operations needed around incoming HTTP requests to your server. The most prevalent examples would be logging and tracing. Although there are various frameworks out there that provide this out of the box, I’d like to illustrate how simple it is to create this logic using nothing but the standard library. Building your own implementation gives you full flexibility and control over the behaviour, reducing the need for external dependencies.

Ideally, I would prefer the API to look something like this, within the context of my naive example:

In the above example, I used chainMiddleware to create a wrapper for all my handlers, which augments both home and about with the logging and tracing middleware that I’ve defined and passed as parameters to this function.

In order for this to work, we need to define a middleware type. It can be defined as:

Thereby, a middleware will be defined as a function that returns a new handler which will perform some operations before (or after) calling the next handler that is provided as an argument. For the sake of brevity when illustrating these examples, we’ll be using [http.HandlerFunc](https://golang.org/pkg/net/http#HandlerFunc) instead of the classical [http.Handler](https://golang.org/pkg/net/http#Handler). The behaviour is the same.

Using this pattern we define the dummy withLogging and withTracing middleware as such:

Our middleware is purely illustrative and does nothing but log that an action has been taken.

We could theoretically already use this implementation, without the need for chainMiddleware, simply by defining each route as such:

This is good and it works but can quickly become tedious and verbose if we introduce more middleware. Thus, our chain function provides nice syntactic sugar for chaining multiple middleware into one.

Let’s look at the implementation:

By making use of the functional programming features of Go, we can use the above implementation to link a chain of middleware which call into one another in the provided order, returning a new wrapper for our handlers. We take each middleware function in the list in reverse order and pass its return value as an argument to the one before it, starting with the final handler. In this way, the chain happens in the order that it is passed in.

Now, if we run the program and visit http://localhost:8080 in the browser, we should expect to see something similar to the following output in the console, before the final handler is called:


main.go:34: Logged connection from [::1]:54962main.go:41: Tracing request for /

Simple as that! You can find the full running example here.