Skip to content

Commit

Permalink
🔥 feat: Add Context Support to RequestID Middleware (#3200)
Browse files Browse the repository at this point in the history
* Rename UserContext() to Context(). Rename Context() to RequestCtx()

* feat: add requestID in UserContext

* Update Ctxt docs and What's new

* Remove extra blank lines

* ♻️ Refactor: merge issue #3186

* 🔥 Feature: improve FromContext func and test

* 📚 Doc: improve requestid middleware

* ♻️ Refactor: Rename interface to any

* fix: Modify structure sorting to reduce memory usage

---------

Co-authored-by: Juan Calderon-Perez <jgcalderonperez@protonmail.com>
Co-authored-by: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
  • Loading branch information
3 people authored Nov 15, 2024
1 parent 2c242e7 commit f725ded
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 20 deletions.
10 changes: 10 additions & 0 deletions docs/middleware/requestid.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ func handler(c fiber.Ctx) error {
}
```

In version v3, Fiber will inject `requestID` into the built-in `Context` of Go.

```go
func handler(c fiber.Ctx) error {
id := requestid.FromContext(c.Context())
log.Printf("Request ID: %s", id)
return c.SendString("Hello, World!")
}
```

## Config

| Property | Type | Description | Default |
Expand Down
25 changes: 22 additions & 3 deletions middleware/requestid/requestid.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package requestid

import (
"context"

"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/log"
)

// The contextKey type is unexported to prevent collisions with context keys defined in
Expand Down Expand Up @@ -36,16 +39,32 @@ func New(config ...Config) fiber.Handler {
// Add the request ID to locals
c.Locals(requestIDKey, rid)

// Add the request ID to UserContext
ctx := context.WithValue(c.Context(), requestIDKey, rid)
c.SetContext(ctx)

// Continue stack
return c.Next()
}
}

// FromContext returns the request ID from context.
// If there is no request ID, an empty string is returned.
func FromContext(c fiber.Ctx) string {
if rid, ok := c.Locals(requestIDKey).(string); ok {
return rid
// Supported context types:
// - fiber.Ctx: Retrieves request ID from Locals
// - context.Context: Retrieves request ID from context values
func FromContext(c any) string {
switch ctx := c.(type) {
case fiber.Ctx:
if rid, ok := ctx.Locals(requestIDKey).(string); ok {
return rid
}
case context.Context:
if rid, ok := ctx.Value(requestIDKey).(string); ok {
return rid
}
default:
log.Errorf("Unsupported context type: %T. Expected fiber.Ctx or context.Context", c)
}
return ""
}
67 changes: 50 additions & 17 deletions middleware/requestid/requestid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,26 +51,59 @@ func Test_RequestID_Next(t *testing.T) {
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
}

// go test -run Test_RequestID_Locals
// go test -run Test_RequestID_FromContext
func Test_RequestID_FromContext(t *testing.T) {
t.Parallel()

reqID := "ThisIsARequestId"

app := fiber.New()
app.Use(New(Config{
Generator: func() string {
return reqID
type args struct {
inputFunc func(c fiber.Ctx) any
}

tests := []struct {
args args
name string
}{
{
name: "From fiber.Ctx",
args: args{
inputFunc: func(c fiber.Ctx) any {
return c
},
},
},
}))

var ctxVal string

app.Use(func(c fiber.Ctx) error {
ctxVal = FromContext(c)
return c.Next()
})

_, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
require.NoError(t, err)
require.Equal(t, reqID, ctxVal)
{
name: "From context.Context",
args: args{
inputFunc: func(c fiber.Ctx) any {
return c.Context()
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

app := fiber.New()
app.Use(New(Config{
Generator: func() string {
return reqID
},
}))

var ctxVal string

app.Use(func(c fiber.Ctx) error {
ctxVal = FromContext(tt.args.inputFunc(c))
return c.Next()
})

_, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
require.NoError(t, err)
require.Equal(t, reqID, ctxVal)
})
}
}

1 comment on commit f725ded

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: f725ded Previous: 8c84b0f Ratio
Benchmark_Ctx_Send 6.508 ns/op 0 B/op 0 allocs/op 4.335 ns/op 0 B/op 0 allocs/op 1.50
Benchmark_Ctx_Send - ns/op 6.508 ns/op 4.335 ns/op 1.50
Benchmark_Utils_GetOffer/1_parameter 203 ns/op 0 B/op 0 allocs/op 131 ns/op 0 B/op 0 allocs/op 1.55
Benchmark_Utils_GetOffer/1_parameter - ns/op 203 ns/op 131 ns/op 1.55
Benchmark_Middleware_BasicAuth - B/op 80 B/op 48 B/op 1.67
Benchmark_Middleware_BasicAuth - allocs/op 5 allocs/op 3 allocs/op 1.67
Benchmark_Middleware_BasicAuth_Upper - B/op 80 B/op 48 B/op 1.67
Benchmark_Middleware_BasicAuth_Upper - allocs/op 5 allocs/op 3 allocs/op 1.67
Benchmark_CORS_NewHandler - B/op 16 B/op 0 B/op +∞
Benchmark_CORS_NewHandler - allocs/op 1 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerSingleOrigin - B/op 16 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerSingleOrigin - allocs/op 1 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflight - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflight - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflightSingleOrigin - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflightSingleOrigin - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflightWildcard - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflightWildcard - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_Middleware_CSRF_GenerateToken - B/op 521 B/op 327 B/op 1.59
Benchmark_Middleware_CSRF_GenerateToken - allocs/op 10 allocs/op 6 allocs/op 1.67

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.