Skip to content

Instantly share code, notes, and snippets.

@didikz
Last active May 4, 2025 12:38
Show Gist options
  • Select an option

  • Save didikz/98de868f20887285f5aabc80f4dddcfa to your computer and use it in GitHub Desktop.

Select an option

Save didikz/98de868f20887285f5aabc80f4dddcfa to your computer and use it in GitHub Desktop.
Golang Middlewares
// you need to create the module first by running
// go mod init <yourpackage>
package main
import (
"context"
"encoding/json"
"errors"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
type defaultResponse struct {
Status string `json:"status"`
Description string `json:"description"`
}
type errorResponse struct {
Status int `json:"status"`
Error string `json:"error"`
Message string `json:"message"`
}
// Middleware type for cleaner middleware chaining
type Middleware func(http.Handler) http.Handler
// Chain creates a single middleware from multiple middlewares
func Chain(middlewares ...Middleware) Middleware {
return func(next http.Handler) http.Handler {
for i := len(middlewares) - 1; i >= 0; i-- {
next = middlewares[i](next)
}
return next
}
}
func logMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Print("Executing logMiddleware")
next.ServeHTTP(w, r)
})
}
func requestSignatureMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Print("Executing requestSignatureMiddleware")
h := r.Header.Get("x-signature")
if h == "" {
resp := errorResponse{
Status: http.StatusUnauthorized,
Error: "INVALID_MISSING_SIGNATURE",
Message: "missing request signature",
}
j, _ := json.Marshal(resp)
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
w.Write(j)
return
}
next.ServeHTTP(w, r)
})
}
func rootHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := defaultResponse{
Status: "OK",
Description: "Success",
}
j, _ := json.Marshal(resp)
w.Header().Add("Content-Type", "application/json")
w.Write(j)
})
}
func main() {
mux := http.NewServeMux()
// Create a chain of middlewares
middlewareChain := Chain(
func(next http.Handler) http.Handler { return logMiddleware(next) },
func(next http.Handler) http.Handler { return requestSignatureMiddleware(next) },
// Add more middlewares here as needed
)
mux.Handle("GET /", middlewareChain(rootHandler()))
s := &http.Server{
Addr: ":8080",
Handler: mux,
}
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
go func() {
if err := s.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
log.Fatal(err)
}
log.Println("Stopped serving new connections")
}()
<-stop
log.Println("Shutting down gracefully...")
shutdownCtx, shutdownRelease := context.WithTimeout(context.Background(), 10*time.Second)
defer shutdownRelease()
if err := s.Shutdown(shutdownCtx); err != nil {
log.Printf("server shutdown error: %v\n", err)
}
log.Println("Server stoppped")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment