func New(engine *guardcore.Engine, opts ...Option) (echo.MiddlewareFunc, error)New returns an echo.MiddlewareFunc, so the guard composes with e.Use
(or group.Use) anywhere in a middleware chain. It rejects a nil engine
with an error; invalid option values are silently ignored so a bad flag can
never weaken security.
| Option | Default | Purpose |
|---|---|---|
WithMaxBodyBytes(int64) |
DefaultMaxBodyBytes (262144) |
Body prefix handed to the engine for inspection |
WithLogger(*log.Logger) |
log.Default() |
Receive fail-closed diagnostics (prefix guardcore echo: ...) |
guard, err := guardecho.New(engine,
guardecho.WithMaxBodyBytes(64*1024),
guardecho.WithLogger(log.New(os.Stderr, "guardecho ", log.LstdFlags)),
)Per-route configuration lives in the engine's RouteRegistry. Attach a route
ID to the request context in a middleware registered before the guard: Echo
runs middleware in registration order, so a group-level middleware would run
after the guard and the engine would never see the ID.
engine.Routes.Register("admin", func(rc *guardcore.RouteConfig) {
rc.RequiredHeaders = guardcore.RequiredHeaders{
{Name: "X-Admin-Token", Value: "secret"},
}
})
routeIDs := map[string]string{
"/admin/banned": "admin",
"/admin/ban": "admin",
"/admin/unban": "admin",
}
// Keys are echo route patterns (c.Path()), so parameterized routes map
// cleanly.
router.Use(func(next echolib.HandlerFunc) echolib.HandlerFunc {
return func(c *echolib.Context) error {
if routeID, ok := routeIDs[c.Path()]; ok {
c.SetRequest(c.Request().WithContext(guardecho.WithRouteID(c.Request().Context(), routeID)))
}
return next(c)
}
})
router.Use(guard) // the mapper must run before the guardWhen the engine returns a block verdict, the middleware writes the verdict
status code, headers, and body to c.Response() and returns nil without
calling next(c), so no later handler runs:
| Situation | Status | Body |
|---|---|---|
| Banned IP | 403 | IP address banned |
| Suspicious content | 400 | Suspicious activity detected |
| Rate limit exceeded | 429 | Too many requests |
Bodies can be overridden globally through SecurityConfig.CustomErrorResponses.
If the engine check panics, the middleware recovers, logs through the
WithLogger sink, and responds 500 Security check failed rather than
letting the request through.