Changelog
RSSRelease notes and version history for GoFr. Pick a version from the right rail or deep-link to a specific tag (e.g. /changelog#v1.61.0).
v1.611 release
Features
HTTP `QUERY` Method (RFC 10008)
QUERY is a safe, idempotent method that puts the query in the request body. It avoids GET's URL-length limit and query strings leaking into logs, without losing safety the way POST does. GoFr now supports it for incoming routes and on the service client:
// inbound
app.QUERY("/search", func(ctx *gofr.Context) (any, error) {
var q SearchRequest
if err := ctx.Bind(&q); err != nil {
return nil, err
}
return search(ctx, q)
})
// outbound
resp, err := ctx.GetHTTPService("catalog").Query(ctx, "search", nil, body)
As RFC 10008 requires, a QUERY request with no Content-Type gets 400, and one GoFr cannot decode gets 415, before your handler runs. The 415 is the new typed ErrorUnsupportedMediaType. Unknown paths still return 404. On the client, QUERY gets circuit-breaker and retry handling like GET. The circuit breaker now returns an error for an unrecognised method; before, it quietly returned a nil response.
Readiness Checks for `/.well-known/health`
/.well-known/health always answered 200, so a Kubernetes readiness probe on it sent traffic to a pod whose dependencies weren't reachable yet. AddReadinessCheck makes the endpoint answer 503 until your check passes:
// GoFr's own datasource checks must pass, and so must this one
app.AddReadinessCheck(func(ctx *gofr.Context) error {
return licenseDB.PingContext(ctx)
})
// your check decides alone; GoFr's checks are not run
app.AddReadinessCheck(func(ctx *gofr.Context) error {
if redisUp(ctx) || sqlUp(ctx) {
return nil
}
return errNoBackingStore
}, gofr.ReplaceFrameworkChecks())
You can register several checks. They run in the order you added them, and the first failure decides. FrameworkReadiness(ctx) returns GoFr's own result, so a replace-mode check can still use it. The error is logged, never written to the response, whose body is just DOWN. With no check registered, the endpoint behaves exactly as before.
Configurable Metric Cardinality Limit
METRICS_CARDINALITY_LIMIT sets how many attribute sets each OpenTelemetry instrument keeps. Once an instrument passes the limit, extra series are merged into one otel.metric.overflow series, so a label explosion can't overwhelm your backend.
| value | behavior |
|---|---|
| unset | SDK default (2000, or OTEL_GO_X_CARDINALITY_LIMIT) — unchanged |
| > 0 | that limit; takes precedence over OTEL_GO_X_CARDINALITY_LIMIT |
| 0 or negative | unlimited |
Circuit Breaker Open Counter
app_circuit_open_count{service} goes up once each time a circuit actually goes from closed to open. It does not count every failing request that sees the trip, so a burst of concurrent failures still adds exactly one.
Azure Event Hub Health Check
Health() for Event Hub was a stub that returned an empty status. Container.Health didn't count an empty status as DOWN, so an app that couldn't reach its Event Hub reported UP. It now makes a real connectivity check, limited to 2s, and reports UP/DOWN with backend, eventHub and partitionCount. The 2s limit is enforced by GoFr itself, because azeventhubs ignores the caller's deadline on this call.
Enhancements
Concurrent Health Checks
Container.Health used to check each dependency one after another, so the endpoint took as long as all the checks added together. The checks now run in parallel, and callers that arrive at the same time share one set of results:
| | before | after |
|---|---|---|
| one /health probe | 1605 ms | 401 ms |
| 20 concurrent probes | 1623 ms, 80 backend calls | 402 ms, 4 backend calls |
(MySQL, Redis and four HTTP dependencies, each taking 400 ms to answer.)
A panicking check reports its dependency as DOWN instead of crashing the process. Two new settings are both off by default:
| config | description |
|---|---|
| HEALTH_CACHE_TTL | Reuse a result for this long (5s, 1m) before checking again. |
| HEALTH_CHECK_TIMEOUT | Limit a round of checks (2s). Dependencies that haven't answered are left out, the status is DEGRADED, and the partial result is never cached. |
MQTT Tracing Semantics
MQTT publish and subscribe spans now set SpanKind and the messaging.* attributes, as Kafka, NATS, SQS and Google Pub/Sub already do. The consume span used to start on context.Background() and ended up in a separate trace. It now sits inside the trace of the request that consumed the message. MQTT 3.1.1 has nowhere to carry traceparent, so there is still no link across the broker. With tracing off, publish allocates exactly what it did before.
To match the other providers, MQTT's app_pubsub_subscribe_total_count now counts Subscribe calls, so it lines up with the success counter. It used to count messages arriving.
performance
Fewer allocations on every request. Output is byte-identical in each case.
| path | before | after |
|---|---:|---:|
| CORS headers (wildcard config) | 5 allocs, 160 B | 0 allocs, 0 B |
| CORS headers (named origins) | 6 allocs, 176 B | 2 allocs, 32 B |
| HTTP metrics histogram observation | 4 allocs, 424 B | 0 allocs, 0 B |
| JSON response | 9 allocs, 288 B | 7 allocs, 224 B |
| RBAC rule resolution (51 rules) | 9,684 allocs, 373,669 ns | 6 allocs, 1,717 ns |
(route, method, status) and reused. The cache is keyed on the route template and only admits templated routes, so unique unmatched paths can't fill it up.Content-Type value is built once.Fixes
"methods": ["*"], or with no methods, never matched, so the routes they protected let every request through. They are now enforced./.well-known, such as /.well-knownprivate, skipped auth and rate limiting. The exemption now requires /.well-known/.TRACER_URL were printed in startup logs. They are now logged as REDACTED.http:// and https:// endpoints were not valid gRPC targets. They now work, and TRACER_INSECURE controls host:port endpoints.__unmatched__, so real routes keep their series.SIGKILL. The server now stops.uint, bool and time.Time fields panicked, and digits were corrupted in table and column names. Both are fixed.SUCCESS, and some operations used the wrong names. Status and labels are now correct.Full Changelog: https://github.com/gofr-dev/gofr/compare/v1.60.1...v1.61.0
v1.602 releases
v1.591 release
v1.581 release
v1.571 release
v1.568 releases
v1.551 release
v1.545 releases
Showing 20 of 117 releases
View all releases on GitHub →