Go SDK · HTTP middleware

The middleware threads a per-request Event through your handler chain, auto-populates Origin from the request and Result from the response status, and lets handlers enrich the event with Action / Target without threading the recorder through each one.

Actor Resolver

The middleware needs an ActorResolver — a function that derives the Actor for a request from its context. Sessions live in cookies, JWTs, headers, OAuth tokens — whatever your auth stack uses. Pair the resolver with a session middleware that plants identity on the request context before the audit middleware runs.

import (
    "context"
    "net/http"

    "github.com/everscribe/sdk-go/pkg/event"
)

type actorIDKey struct{}

// withSession plants the actor's identity on the request context.
// Real apps read a session cookie or JWT here.
func withSession(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        id := r.Header.Get("X-User-ID")
        ctx := context.WithValue(r.Context(), actorIDKey{}, id)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

// actorResolver reads the identity withSession planted and turns it
// into an Actor for the audit middleware.
func actorResolver(users map[string]User) event.ActorResolver {
    return func(ctx context.Context) event.Actor {
        id, _ := ctx.Value(actorIDKey{}).(string)
        if u, ok := users[id]; ok {
            return event.Actor{
                Type:        "user",
                ID:          u.ID,
                DisplayName: u.Name,
                Email:       u.Email,
            }
        }
        return event.Actor{Type: "anonymous"}
    }
}

ActorResolver signature:

type ActorResolver func(ctx context.Context) event.Actor

Wiring it up

Session middleware first, audit middleware second, then your routes. The resolver runs inside the audit middleware and reads what withSession planted:

auditMW := event.NewMiddleware(actorResolver(users))
apiHandler := withSession(auditMW(apiMux))

Ordering matters. If the audit middleware runs first, the resolver sees an empty context and every event records as anonymous.