Groups and Middleware
Zinc keeps middleware composition simple:
app.UseHTTP(...)wraps the application in standardnet/httpmiddlewareapp.Use(...)applies globallyapp.UsePrefix(...)applies to matching prefixesgroup.Use(...)applies inside a specific group tree- route registration accepts middleware before the final handler
Middleware uses the same handler signature as routes:
type Middleware = func(*zinc.Context) errorEvery item in the chain runs in order. Call c.Next() to continue.
At a glance
Section titled “At a glance”app.Use(middleware.RequestID())
api := app.Group("/api", requireAPIKey)api.Get("/users/{id}", loadUser, showUser)Middleware belongs at the narrowest level that still matches the behavior: app-wide for every request, group-level for route families, and route-level for endpoint-specific guards.
Use UseHTTP when middleware already follows the standard
func(http.Handler) http.Handler contract. It runs outside every Zinc
middleware layer. See net/http Interoperability.
Global middleware
Section titled “Global middleware”app.Use( requestLogger, recoverPanic,)Global middleware wraps every request before Zinc dispatches the matched route.
Prefix middleware
Section titled “Prefix middleware”Use UsePrefix when behavior should apply to one part of the app but you do not want to build a full group up front.
app.UsePrefix("/api", requireAPIKey)app.UsePrefix("/admin", requireSession)Group middleware
Section titled “Group middleware”Group middleware composes naturally with route prefixes.
admin := app.Group("/admin")admin.Use(requireSession, requireAdmin)
admin.Get("/dashboard", dashboard)admin.Get("/users", listAdminUsers)Nested groups inherit parent middleware.
api := app.Group("/api", requireAPIKey)v1 := api.Group("/v1", withVersionHeader)Route middleware
Section titled “Route middleware”Pass middleware directly into a route when the behavior belongs to one endpoint.
app.Post("/posts", authUser, requireRole("editor", "admin"), createPost)That reads as:
- authenticate the request
- check the allowed roles
- run the handler
The guard is just middleware.
func requireRole(allowed ...string) zinc.Middleware { return func(c *zinc.Context) error { user, ok := c.Get("user") if !ok || user == nil { return c.AbortWithStatus(zinc.StatusUnauthorized) } if !hasAnyRole(user, allowed...) { return c.AbortWithStatus(zinc.StatusForbidden) } return c.Next() }}The role lookup can live in your auth package. The middleware shape stays the same.
Use groups when many routes share a guard.
admin := app.Group("/admin", authUser, requireRole("admin"))admin.Get("/users", listUsers)admin.Delete("/users/{id}", deleteUser)Returning from middleware
Section titled “Returning from middleware”Middleware can:
- continue with
return c.Next() - short-circuit with a response
- short-circuit by returning an error
func requireAPIKey(c *zinc.Context) error { if c.GetHeader("X-API-Key") == "" { return c.AbortWithStatus(zinc.StatusUnauthorized) } return c.Next()}First-party middleware package
Section titled “First-party middleware package”Zinc ships common middleware in one package:
import "github.com/0mjs/zinc/middleware"Start with Request ID, Request Logger, Recover, CORS, and Secure for a typical API stack.
See also
Section titled “See also”- Middleware Overview for the full first-party middleware map.
- Routing for groups and route registration.
- Errors for returned middleware errors.
