Skip to content

Usage

Engine lifecycle

The Engine facade composes config, route registry, Redis, ban manager, rate limit manager, and the check pipeline.

cfg, err := guardcore.NewSecurityConfig(func(c *guardcore.SecurityConfig) {
    c.EnableRateLimiting = true
    c.RateLimit = 30
    c.RateLimitWindow = 60
})
if err != nil {
    log.Fatal(err) // config validation failure
}

engine, err := guardcore.NewEngine(cfg)
if err != nil {
    log.Fatal(err)
}

// Idempotent (sync.Once-guarded): connects Redis, primes cloud IP ranges,
// initializes ban/rate-limit state. Call once before the first Check.
if err := engine.Initialize(); err != nil {
    log.Fatal(err)
}
defer engine.Close()

Exposed fields: engine.Config, engine.Routes, engine.Redis, engine.Ban, engine.RateLimit, engine.Cloud.

The request contract

Adapters (or your own middleware) translate native requests into guardcore.Request via the RequestFactory:

type Request interface {
    URLPath() string
    URLScheme() string
    URLFull() string
    URLReplaceScheme(scheme string) string
    Method() string
    ClientHost() string
    Headers() Headers
    QueryParams() map[string]string
    Body() ([]byte, error)
    State() *RequestState
}

RequestState carries per-request resolution results (ClientIP, GuardRouteID, BypassChecks, AuthPrincipal, ...). Set RequestOptions.State if you need to seed a route ID or client IP directly.

Checking requests

resp := engine.Check(req)
if resp != nil {
    // Blocked. Write resp.StatusCode, resp.Headers, resp.Body.
}

Well-known block verdicts:

Situation Status Body
Banned IP 403 IP address banned
Suspicious content 403 Suspicious activity detected
Rate limit exceeded 429 Too many requests

All of these can be overridden through SecurityConfig.CustomErrorResponses.

Standalone content detection

You can use the detector directly without the pipeline:

result := guardcore.Detect(content, ip, context)
if result.IsThreat {
    log.Printf("threat score %.2f via %s", result.ThreatScore, result.DetectionMethod)
}

See Detection for the full API.

Managers

The managers are usable on their own for admin tooling:

// IP bans
banned, err := engine.Ban.Ban("192.0.2.10", 3600, "manual")
if engine.Ban.IsIPBanned("192.0.2.10") {
    _ = engine.Ban.Unban("192.0.2.10")
}

// Rate limits
allowed, err := engine.RateLimit.CheckRateLimitByIP("192.0.2.10", "/api")

Route-scoped configuration

Register route configs on the engine's registry and attach the route ID to requests (adapters expose a WithRouteID context helper):

engine.Routes.Register("strict", func(rc *guardcore.RouteConfig) {
    rc.RateLimit = 1
    rc.RateLimitWindow = 10
    rc.APIKeyRequired = true
})

Net/http wiring

The engine has no HTTP dependency. For net/http services either use the nethttp-guard adapter or build your own shim:

factory := guardcore.NewRequestFactory()

func guardMiddleware(engine *guardcore.Engine, next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        body, _ := io.ReadAll(io.LimitReader(r.Body, 1<<20))
        header := map[string]string{}
        for k, v := range r.Header {
            header[k] = strings.Join(v, ",")
        }
        req := factory.CreateRequest(guardcore.RequestOptions{
            Path:       r.URL.Path,
            Scheme:     "http",
            Host:       r.Host,
            RawQuery:   r.URL.RawQuery,
            Method:     r.Method,
            ClientHost: r.RemoteAddr,
            Header:     header,
            QueryParams: func() map[string]string {
                qp := map[string]string{}
                for k, v := range r.URL.Query() {
                    qp[k] = v[0]
                }
                return qp
            }(),
            Body: body,
        })
        if resp := engine.Check(req); resp != nil {
            for k, v := range resp.Headers {
                w.Header().Set(k, v)
            }
            w.WriteHeader(resp.StatusCode)
            _, _ = w.Write(resp.Body)
            return
        }
        next.ServeHTTP(w, r)
    })
}

Note

For production wiring prefer the nethttp-guard adapter: it handles trusted proxy resolution, replayable bodies, and fail-closed error handling. The examples/ directory shows both a minimal and a production-style layout.