iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Go HTTP middleware is a handler wrapper: it takes an http.Handler, adds behavior before or after that handler runs, and returns another handler. Because the wrapped handler still satisfies the same interface, you can stack middleware around an endpoint or an entire mux using Go’s standard library.
What Go HTTP middleware does
The net/http package defines a server-side handler through the http.Handler interface. Its ServeHTTP(http.ResponseWriter, *http.Request) method responds to an HTTP request. Middleware uses that same interface to put shared behavior around a handler, such as request logging, timing, authentication checks, request IDs, or response headers. Go does not provide those features automatically; middleware is a way to implement and reuse them.
A middleware function commonly has the shape func(http.Handler) http.Handler: it receives the next handler and returns a handler that can do work on either side of the call. Go’s net/http API documentation defines the handler contract, and Effective Go explains how values with a ServeHTTP method can serve HTTP requests.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →How a request moves through middleware
Each wrapper receives the request first, can inspect or modify what it is permitted to, and then calls next.ServeHTTP(w, r) to pass the request inward. When the inner handler returns, the wrapper can do post-processing. In a chain such as outer(inner(endpoint)), the outer middleware’s pre-work runs first, while its post-work runs after the inner handler finishes.
#1 Best Overall
This nesting order matters for behavior such as timing and logging. A timer started before calling the next handler can measure the time spent in everything inside that wrapper. A middleware that rejects a request before calling next prevents the inner handler from running.
Build and apply a simple middleware
This example logs the method and path before the endpoint handles a request, then logs when handling has completed:
package main
import (
"log"
"net/http"
)
func logRequests(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("started %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
log.Printf("finished %s %s", r.Method, r.URL.Path)
})
}
func hello(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("hellon"))
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /hello", hello)
handler := logRequests(mux)
log.Fatal(http.ListenAndServe(":8080", handler))
}
-
Define the wrapper.
logRequestsaccepts the downstreamhttp.Handlerand returns anhttp.Handler.Recommended: Update Every Outdated Driver on Your PC in One Scan - Free →Recommended: Fix Windows Errors and Clear Junk Files in Minutes - Free Scan →Recommended: Crashes or Glitches? A Free Driver Scan Usually Finds the Culprit →Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy. -
Adapt the inline function.
http.HandlerFuncconverts a function with the handler signature into a value implementinghttp.Handler. -
Call the next handler.
next.ServeHTTP(w, r)hands the request to the mux; omitting that call is how middleware can deliberately stop the chain, for example after rejecting a request. -
Wrap the mux for global behavior. Passing
logRequests(mux)toListenAndServeapplies this middleware to requests handled through that mux.
The route pattern GET /hello uses the method-and-path pattern syntax introduced in Go 1.22. That syntax concerns ServeMux routing, not middleware. The net/http documentation describes the current patterns and the compatibility setting GODEBUG=httpmuxgo121=1, which restores earlier mux behavior and is read when the process starts. The standard-library package documentation also explains that ListenAndServe uses the default mux when passed a nil handler; constructing an explicit mux makes the wrapper and route composition clear.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Compose more than one middleware layer
Wrap handlers from the inside out to make the resulting order explicit:
handler := requestID(recoverPanics(logRequests(mux)))
Here, requestID is outermost: it runs first on the way in and last after the inner chain returns. A helper that applies a slice of middleware can obscure this order unless its convention is documented. For example, this helper treats the first listed middleware as the outermost layer:
Rank #4
func chain(h http.Handler, middleware ...func(http.Handler) http.Handler) http.Handler {
for i := len(middleware) - 1; i >= 0; i-- {
h = middleware[i](h)
}
return h
}
handler := chain(mux, requestID, recoverPanics, logRequests)
Write down or test the ordering convention when adding such a helper. Middleware that sets context or response headers may need to run before other layers, while timing or logging may need to surround them.
Middleware and handler details that can cause bugs
Finish response work before returning
A handler should write its reply and return. Do not keep using the http.ResponseWriter after ServeHTTP returns; its lifetime is limited to that call. Set response headers before the response is committed by writing the status or body. See the net/http handler documentation for the writer contract.
Free tools Windows power users keep installed
One-click scans. No signup required.
Read request bodies before writing responses
Generally, read the request body before writing a response if later code needs it. The API documentation cautions that, depending on the client, protocol version, and intermediaries, reading the body after writing to the response may not work. Avoid modifying the supplied request except where the API permits it; when downstream code needs a changed request, use the documented request-cloning or context patterns rather than assuming mutation is safe.
Best Value
Be careful when wrapping ResponseWriter
A middleware wrapper may want to observe status codes or bytes written. A custom ResponseWriter wrapper can affect optional capabilities that downstream handlers expect, so a wrapper should preserve or correctly expose relevant interfaces rather than assuming every writer supports only the basic methods. There is no single minimal wrapper that is safe for every handler and every optional capability; check the API contract for the operations your stack uses.
Use panic recovery as a boundary, not as error handling
Recovery middleware can prevent a panic from escaping through a handler chain and can support a controlled server response or logging policy. It does not replace checking errors and returning appropriate responses in ordinary application code. The documented server behavior when a handler panics is described in the net/http documentation.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.When standard-library middleware is enough
For a small service, composing http.Handler values directly keeps the dependency footprint low and makes wrapper order visible in code. A third-party router or framework may offer conveniences such as route-specific middleware or additional routing features, but those vary by project. Before adopting one, check its current documentation for how it orders global and per-route middleware and whether its response-writer handling fits the handlers you use.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteStart with the standard interfaces when the needed behavior is simple and shared across routes. Add a router or framework when its concrete routing or registration features solve a problem your explicit mux and wrappers do not.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

