A middleware is just a Handler (func(Ctx) error) — like gofiber v3, there is no separate middleware type. A middleware does its work, then calls c.Next() to continue the chain:
func logging(c httpsrv.Ctx) error {
start := time.Now()
if err := c.Next(); err != nil { // continue to the next middleware / route handler
return err
}
log.Printf("%s %s %v", c.Method(), c.Path(), time.Since(start))
return nil
}Use signature:
Use(args ...any) Router- If the first argument is a
string, it is a path prefix; the rest are middleware. - If the first argument is not a string, all arguments are global middleware.
app.Use(func(c httpsrv.Ctx) error {
c.SetHeader("X-Frame-Options", "DENY")
return c.Next()
})Applies to every request and every HTTP method (including unmatched 404s, matching gofiber v3's default behavior).
app.Use("/api", func(c httpsrv.Ctx) error {
// scoped to /api/*
return c.Next()
})The prefix matches on / segment boundaries, so /api matches /api/users but not /apifoo.
A single Use may take multiple middleware:
app.Use("/api", logging, recoverer, cors)Middleware run in registration order — the first registered runs first and is the outermost:
app.Use(mwA) // runs first
app.Use(mwB) // runs second
// order: mwA -> mwB -> route handlerA middleware that does not call c.Next() terminates the chain; the route handler will not run:
app.Use(func(c httpsrv.Ctx) error {
if !authorized(c) {
c.Status(http.StatusUnauthorized)
return c.SendString("forbidden") // no Next, ends here
}
return c.Next()
})Any non-nil error returned by a Handler (middleware or route handler) bubbles up along c.Next() to the top of the chain, where the ErrorHandler handles it (default 500; customize with WithErrorHandler). A middleware may also intercept downstream errors:
app.Use(func(c httpsrv.Ctx) error {
err := c.Next()
if err != nil {
log.Printf("handler error: %v", err) // log, transform, or swallow
}
return err
})Group.Use automatically joins the group prefix onto the middleware path:
api := app.Group("/api")
api.Use(rateLimit) // scoped to /api/*
api.Get("/users", listUsers)Use accepts both a named Handler type and an inline func(Ctx) error:
var myMw httpsrv.Handler = func(c httpsrv.Ctx) error { /* ... */ }
app.Use(myMw, func(c httpsrv.Ctx) error { /* ... */ })compress.New()(themiddleware/compresssubpackage): gzip/brotli compression byAccept-Encoding(brotli preferred), mirroring gofiber v3'scompress.New.httpsrv.AcceptLanguage(def, others...): detect the request language fromAccept-Language(BCP-47, viax/text).
import "github.com/hooto/httpsrv/v2/middleware/compress"
app.Use(compress.New()) // default level
app.Use(compress.New(compress.Config{ // optional config
Level: compress.LevelBestSpeed,
}))
app.Use(httpsrv.AcceptLanguage("en", "zh"))- Middleware path prefixes support static prefixes only — no
/users/{id}parameter prefixes. - Path parameters are not available before the middleware calls
c.Next()(routing happens in the terminaldispatch); they are readable viac.Params()afterc.Next()returns.