News & Updates

Go Fiber Guide: Implement Custom Middleware Step‑by‑Step

By Dominic Hawke 10 min read 2598 views

Go Fiber Guide: Implement Custom Middleware Step‑by‑Step

When you dive into Go Fiber, the first thing you’ll notice is how lightweight the router feels. Yet, behind that simplicity lies a powerful extension point: middleware. Building your own middleware can feel like adding a secret sauce to every request, letting you log, validate, or transform data right where it matters.

Why Write Your Own Middleware?

Fiber ships with a handy set of built‑ins—compression, CORS, JWT verification—but the real world rarely fits a one‑size‑fits‑all mold. Custom middleware gives you:

  • Fine‑grained control over request lifecycles.
  • The ability to enforce business rules before hitting handlers.
  • Opportunities to inject tracing or metrics without polluting core code.

Think of it as a reusable wrapper that you can slip onto any route chain.

Core Concepts to Keep in Mind

Fiber treats a middleware as a function with the signature func(c *fiber.Ctx) error. The fiber.Ctx object is your gateway to the HTTP request, response, and a handful of helper methods.

Next() and Flow Control

Calling c.Next() hands the baton to the next middleware or the final handler. If you forget to call it, the chain stops dead—useful for early aborts, but easy to misuse.

Returning Errors

Any error you return bubbles up to Fiber’s error handler. Throwing an error after c.Next() lets you act on the response after the handler has run, perfect for logging response times.

Step‑by‑Step: Building a Simple Logger

Let’s start with something concrete: a logger that records the method, path, and how long the request took.

func Logger() fiber.Handler {

return func(c *fiber.Ctx) error {

start := time.Now()

// Continue down the chain

err := c.Next()

// After the handler finishes

latency := time.Since(start)

fmt.Printf("%s %s - %v\n", c.Method(), c.Path(), latency)

return err

}

}

Notice the use of c.Next() before measuring latency. If we measured before the call, we’d only capture the middleware’s own overhead—not the actual request handling.

Adding Conditional Logic

Suppose you only want to log requests to a certain prefix, like /api. You can insert a quick guard:

if !strings.HasPrefix(c.Path(), "/api") {

return c.Next()

}

This tiny check saves resources for static assets that don’t need logging.

Injecting Values Into Context

Middleware is also a handy place to stash data for downstream handlers. Fiber’s context carries a map that you can tap into with c.Locals(key, value) and retrieve later via c.Locals(key).

func RequestID() fiber.Handler {

return func(c *fiber.Ctx) error {

id := uuid.New().String()

c.Locals("reqID", id)

// Optionally set a response header

c.Set("X-Request-ID", id)

return c.Next()

}

}

Later in your handler you can do reqID := c.Locals("reqID").(string) without threading the ID through function arguments.

Composing Multiple Middleware

Fiber lets you stack middleware in the order you declare them. The order matters: a panic recovery middleware should sit near the top, while authentication checks often come just after logging.

app.Use(Logger())

app.Use(RequestID())

app.Use(Recover()) // built‑in recovery

app.Use(AuthRequired())

If you find yourself repeating the same sequence across several route groups, bundle them into a slice and apply with app.Group(...).Use(...).

Testing Custom Middleware

Testing is where many developers stumble. Because middleware works with fiber.Ctx, you can simulate a request using app.Test(). Here’s a quick example for the logger:

func TestLogger(t *testing.T) {

app := fiber.New()

app.Use(Logger())

app.Get("/ping", func(c *fiber.Ctx) error { return c.SendString("pong") })

req := httptest.NewRequest("GET", "/ping", nil)

resp, err := app.Test(req)

if err != nil { t.Fatalf("request failed: %v", err) }

if resp.StatusCode != http.StatusOK { t.Fail() }

// Inspect stdout or use a buffer to capture the log line

}

By feeding a fake http.Request, you can verify that the middleware behaves correctly without spinning up a real server.

Advanced Tip: Asynchronous Work

If you need to fire off a background job—say, push a metric to Prometheus—you shouldn’t block the request. Spin a goroutine after c.Next() and let it run independently.

go func() {

// long‑running task

metrics.Inc("request_total")

}()

Just remember to keep error handling inside the goroutine; there’s no caller to catch panics.

Common Pitfalls to Avoid

  • Swallowing errors. Returning nil after c.Next() when the downstream handler actually failed masks problems.
  • Modifying the response after it’s sent. Once you call c.Send() or similar, further writes are ignored.
  • Global state. Avoid using package‑level variables inside middleware; they become race conditions under load.

Putting It All Together

Below is a miniature “full‑stack” example that combines logging, request ID injection, and a simple authentication guard.

func AuthRequired() fiber.Handler {

return func(c *fiber.Ctx) error {

token := c.Get("Authorization")

if token != "Bearer secret-token" {

return c.Status(fiber.StatusUnauthorized).SendString("unauthorized")

}

return c.Next()

}

}

func main() {

app := fiber.New()

app.Use(Logger())

app.Use(RequestID())

app.Use(AuthRequired())

app.Get("/secure", func(c *fiber.Ctx) error {

id := c.Locals("reqID")

return c.JSON(fiber.Map{"msg": "welcome", "reqID": id})

})

log.Fatal(app.Listen(":3000"))

}

The pattern scales: replace AuthRequired with JWT validation, add rate‑limiting middleware, or sprinkle tracing spans. Each piece stays isolated, testable, and reusable.

Final Thoughts

Custom middleware in Go Fiber is less about magical tricks and more about disciplined composition. A well‑placed c.Next(), thoughtful error returns, and clean context usage give you a flexible pipeline that grows with your application. Experiment with small handlers, test them in isolation, and soon you’ll have a toolbox that feels as lean as Fiber itself.

Implementing a Web Service With Go and Fiber | HackerNoon
🐛 [Bug]: Custom Middleware creating routes · Issue #2113 · gofiber ...
GitHub - sacsand/gofiber-firebaseauth: Firebase Authentication ...
Go Fiber Vs Mux at Gabriella Raiwala blog

Written by Dominic Hawke

Dominic Hawke is a Chief Correspondent with over a decade of experience covering breaking trends, in-depth analysis, and exclusive insights.