Back to Home

Go Middleware - Part 1

  • February 6, 2019 |
  • 3 min read

This is the first in a series of simple tutorials explaining the usage of HTTP middleware in Go.

Middleware is useful for injecting logic before and after a request handler, without needing to modify the business logic of the handler itself. For instance, you can use the middleware pattern to log some basic information about every request sent to the server, then apply some standard authentication for those requests that need it, and finally apply the appropriate handler to run the actual business logic.

In this context middleware is a specific case of the decorator pattern; it is typically used to cleanly add logic to a web request handled by a server. Middleware can be chained to wrap multiple pieces of functionality around a single request (e.g. logging, authentication, authorization, request/response encoding, error handling). Historically, the term "middleware" has been used in SOA and enterprise architectures to cover any type of software that facilitates communication between two other systems (e.g. Service Bus), but is being used more frequently to refer to a logical layer within a single service.

This pattern helps encapsulate logic to adhere to the Single responsibility principle for SOLID design and Clean Architecture.

Part 1 - Loop Chain Middleware Example

Photo by Mike Alonzo

The code for this tutorial can be found here:
https://github.com/benjohns1/go-middleware-example/blob/master/loopchain/main.go

This simple approach uses a range loop to apply each middleware function in order. Technically, this isn't really the "middleware" pattern, but it serves the same purpose and provides a great introduction. We will build upon this simple approach with a more useful implementation in Part 2.

Step 1 - A Simple HTTP Server

First let's create a main func to start a simple server:

main.go:

We're using the standard http library to handle the "/api/v1" route with our aptly-named businessLogic function. You can run the server with:

go run main.go

and go to localhost:8080/api/v1 in your browser to see this in action.

One thing to note is that we're wrapping the function that handles the actual http request in a closure (the businessLogic function) so that we can inject some setup values into the handler when the server starts. The first injected value is just a static string, but the second value is a func that is run whenever a request is invoked. Try hitting the endpoint multiple times to see the pseudo-random numbers from runTimeFunc. This isn't important for this particular example, but is being shown now because closures are key to more advanced middleware implementations.

Step 2 - Adding Middleware

Now let's create a logging function that will log some generic information about a request:

main.go (partial):

How do we add this to our route handler in a way that can be reused? This is where the usefulness of middleware comes in! We can write a new function that will chain these handlers together and return a final handler that wraps all of this nicely and neatly for the route:

main.go (partial):

The chain function takes any number of http.HandlerFunc functions and returns a new http.Handler that runs all of them in order. We can create and add as many middleware function handlers as we want to this chain:

http.Handle("/api/v1", chain(logger, moreMiddleware, evenMoreMiddleware, businessLogic("99999", runTimeFunc)))

These handlers are completely decoupled from each other and can easily be applied to multiple routes in various configurations.

Part 2 will cover a slightly more advanced implementation approach using recursive functions that allow applying logic before and after the subsequent handler as well as short-circuiting the request chain.

Final Server Code

main.go:

Go Middleware - Part 2

Related Posts

The essential design concepts I use when developing an evolvable, distributed system.

Read More

How can we continuously integrate small changes while practicing acceptance test-driven development?

Read More

TDD and Testing Behavior

January 24, 2024

The importance of testing behavior when using test-driven development

Read More

When is it appropriate to use centralized orchestration versus event-driven choreography?

Read More

When defining a business problem and planning its solution, keep the two conversations separate...

Read More

Modern message brokers provide many important benefits to a distributed system...

Read More

Printable cheat sheets to help remember some of Uncle Bob's valuable contributions to the industry

Read More

Why Terraform?

December 25, 2019

Terraform leads the way in the infrastructure-as-code world...

Read More

I was looking for a quick and easy way to put together a personal static site and...

Read More

A few weeks ago, I decided to try Svelte's Sapper framework to handle the front-end of a simple app...

Read More

After years of consulting, I find myself continually coming back to three basic principles of system design...

Read More

In this fifth and final part of the Go middleware tutorial series, we'll use what we've learned to create a more structured API example...

Read More

Go Middleware - Part 4

February 24, 2019

In this fourth part of the Go middleware tutorial series, we'll discuss passing custom state along the request chain.

Read More

Go Middleware - Part 3

February 15, 2019

In this third part of the Go middleware tutorial series, we'll quickly look at a common variant on the recursive middleware implementation from part 2.

Read More

Go Middleware - Part 2

February 9, 2019

In this second part of the Go middleware tutorial series, we'll cover a recursive approach that provides a couple benefits beyond the simple loop chain example from part 1.

Read More

How do we manage the architectural complexity that inevitably arises from using cloud services?

Read More

This Old Blog

January 20, 2019

I've decided to resurrect this old blog to publish some nuggets about software architecture and development, and perhaps...

Read More

Drupal 6 Theme Info Error

September 14, 2011

Recently one of my client sites had an issue where the custom theme info was corrupted...

Read More

Here's a slight modification to the handy Google Bookmarks Bookmarklet...

Read More

While building a Drupal site for one of my clients, I was having a heck of a time integrating...

Read More