Tier: Foundational · Status: Full · Java original:
firefly-web+firefly-spring-utils· .NET project:FireflyFramework.Web
web is the framework's HTTP-layer middleware tier — it converts
errors into RFC 7807 application/problem+json responses, propagates
correlation IDs, replays idempotent requests, and scrubs PII out of
log lines. Composed at the outermost edge of every Firefly service via
startercore.Core.Middleware().
Every middleware is a func(http.Handler) http.Handler so it
composes with stdlib net/http and any third-party router.
Spring's @ControllerAdvice and ASP.NET's exception handlers cover
problem-detail rendering only. The framework needs four orthogonal
middlewares to behave identically across runtimes, with the same
header names, response shapes, and conflict semantics — web
provides them as one composable bundle.
incoming request
│
▼
┌─────────────────────────────────────────┐
│ ProblemMiddleware (panic → 500 RFC7807)│
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ CorrelationMiddleware (X-Correlation-Id) │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ IdempotencyMiddleware (replay if Key) │
└─────────────────────────────────────────┘
│
▼
your mux
This is the chain returned by startercore.Core.Middleware().
| Symbol | Behaviour |
|---|---|
WriteProblem(w, *kernel.ProblemDetail) |
Sets application/problem+json, writes status, encodes |
WriteError(w, error) |
Converts via kernel.AsProblem then writes |
ProblemMiddleware(next) |
Catches panics, renders 500 with kernel.TypeInternal |
ErrorHandler(fn).AsHandler() |
Adapter for handlers returning error |
| Symbol | Behaviour |
|---|---|
CorrelationMiddleware(next) |
Reads / generates X-Correlation-Id, stores on ctx, echoes back |
| Symbol | Behaviour |
|---|---|
IdempotencyConfig{Store, TTL, Methods} |
Tunes the middleware |
DefaultIdempotencyConfig() |
24 h TTL, memory store, POST/PUT/PATCH |
IdempotencyMiddleware(cfg)(next) |
Replays cached 2xx responses; returns 409 on key reuse w/ different body |
MemoryIdempotencyStore |
Default in-process store |
IdempotencyStore interface |
Plug your own (Redis / Postgres / etc.) |
| Symbol | Behaviour |
|---|---|
MaskPII(s) string |
Redacts emails, IBANs, cards, E.164 phones |
MaskMap(m) map |
Recursive redaction; sensitive keys (password, token, secret, authorization, cookie, api_key, apikey, private_key) replaced wholesale |
import (
"net/http"
"github.com/fireflyframework/fireflyframework-go/kernel"
"github.com/fireflyframework/fireflyframework-go/web"
)
mux := http.NewServeMux()
mux.Handle("POST /orders", web.ErrorHandler(func(w http.ResponseWriter, r *http.Request) error {
if r.URL.Query().Get("customer") == "" {
return kernel.NewBadRequest("customer is required")
}
// … your domain logic …
w.WriteHeader(http.StatusCreated)
return nil
}).AsHandler())
cfg := web.DefaultIdempotencyConfig()
chain := web.ProblemMiddleware(
web.CorrelationMiddleware(
web.IdempotencyMiddleware(cfg)(mux),
),
)
http.ListenAndServe(":8080", chain)cd web
go test ./...Suite covers panic→500, the typed ErrorHandler, correlation id
generation + echo-back, idempotency replay (replay header, body), and
PII redaction across emails / IBANs / cards / phones plus map-key
sensitive-name scrubbing.