Skip to content

Commit

Permalink
🐛 fix: Improve naming convention for Context returning functions (#3193)
Browse files Browse the repository at this point in the history
* Rename UserContext() to Context(). Rename Context() to RequestCtx()

* Update Ctxt docs and What's new

* Remove extra blank lines

---------

Co-authored-by: M. Efe Çetin <[email protected]>
  • Loading branch information
gaby and efectn authored Nov 13, 2024
1 parent 7cddb84 commit 16f9056
Show file tree
Hide file tree
Showing 23 changed files with 122 additions and 120 deletions.
10 changes: 5 additions & 5 deletions bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (b *Bind) RespHeader(out any) error {
// Cookie binds the requesr cookie strings into the struct, map[string]string and map[string][]string.
// NOTE: If your cookie is like key=val1,val2; they'll be binded as an slice if your map is map[string][]string. Else, it'll use last element of cookie.
func (b *Bind) Cookie(out any) error {
if err := b.returnErr(binder.CookieBinder.Bind(b.ctx.Context(), out)); err != nil {
if err := b.returnErr(binder.CookieBinder.Bind(b.ctx.RequestCtx(), out)); err != nil {
return err
}

Expand All @@ -104,7 +104,7 @@ func (b *Bind) Cookie(out any) error {

// Query binds the query string into the struct, map[string]string and map[string][]string.
func (b *Bind) Query(out any) error {
if err := b.returnErr(binder.QueryBinder.Bind(b.ctx.Context(), out)); err != nil {
if err := b.returnErr(binder.QueryBinder.Bind(b.ctx.RequestCtx(), out)); err != nil {
return err
}

Expand All @@ -131,7 +131,7 @@ func (b *Bind) XML(out any) error {

// Form binds the form into the struct, map[string]string and map[string][]string.
func (b *Bind) Form(out any) error {
if err := b.returnErr(binder.FormBinder.Bind(b.ctx.Context(), out)); err != nil {
if err := b.returnErr(binder.FormBinder.Bind(b.ctx.RequestCtx(), out)); err != nil {
return err
}

Expand All @@ -149,7 +149,7 @@ func (b *Bind) URI(out any) error {

// MultipartForm binds the multipart form into the struct, map[string]string and map[string][]string.
func (b *Bind) MultipartForm(out any) error {
if err := b.returnErr(binder.FormBinder.BindMultipart(b.ctx.Context(), out)); err != nil {
if err := b.returnErr(binder.FormBinder.BindMultipart(b.ctx.RequestCtx(), out)); err != nil {
return err
}

Expand All @@ -163,7 +163,7 @@ func (b *Bind) MultipartForm(out any) error {
// If there're no custom binder for mime type of body, it will return a ErrUnprocessableEntity error.
func (b *Bind) Body(out any) error {
// Get content-type
ctype := utils.ToLower(utils.UnsafeString(b.ctx.Context().Request.Header.ContentType()))
ctype := utils.ToLower(utils.UnsafeString(b.ctx.RequestCtx().Request.Header.ContentType()))
ctype = binder.FilterFlags(utils.ParseVendorSpecificContentType(ctype))

// Check custom binders
Expand Down
2 changes: 1 addition & 1 deletion client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1572,7 +1572,7 @@ func Test_Client_SetProxyURL(t *testing.T) {
}

c.Status(resp.StatusCode())
c.Context().SetBody(resp.Body())
c.RequestCtx().SetBody(resp.Body())

return nil
})
Expand Down
22 changes: 11 additions & 11 deletions ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,26 +382,26 @@ func (c *DefaultCtx) ClearCookie(key ...string) {
})
}

// Context returns *fasthttp.RequestCtx that carries a deadline
// RequestCtx returns *fasthttp.RequestCtx that carries a deadline
// a cancellation signal, and other values across API boundaries.
func (c *DefaultCtx) Context() *fasthttp.RequestCtx {
func (c *DefaultCtx) RequestCtx() *fasthttp.RequestCtx {
return c.fasthttp
}

// UserContext returns a context implementation that was set by
// Context returns a context implementation that was set by
// user earlier or returns a non-nil, empty context,if it was not set earlier.
func (c *DefaultCtx) UserContext() context.Context {
func (c *DefaultCtx) Context() context.Context {
ctx, ok := c.fasthttp.UserValue(userContextKey).(context.Context)
if !ok {
ctx = context.Background()
c.SetUserContext(ctx)
c.SetContext(ctx)
}

return ctx
}

// SetUserContext sets a context implementation by user.
func (c *DefaultCtx) SetUserContext(ctx context.Context) {
// SetContext sets a context implementation by user.
func (c *DefaultCtx) SetContext(ctx context.Context) {
c.fasthttp.SetUserValue(userContextKey, ctx)
}

Expand Down Expand Up @@ -1189,8 +1189,8 @@ func (c *DefaultCtx) Query(key string, defaultValue ...string) string {
// Queries()["filters[customer][name]"] == "Alice"
// Queries()["filters[status]"] == "pending"
func (c *DefaultCtx) Queries() map[string]string {
m := make(map[string]string, c.Context().QueryArgs().Len())
c.Context().QueryArgs().VisitAll(func(key, value []byte) {
m := make(map[string]string, c.RequestCtx().QueryArgs().Len())
c.RequestCtx().QueryArgs().VisitAll(func(key, value []byte) {
m[c.app.getString(key)] = c.app.getString(value)
})
return m
Expand Down Expand Up @@ -1219,7 +1219,7 @@ func (c *DefaultCtx) Queries() map[string]string {
// unknown := Query[string](c, "unknown", "default") // Returns "default" since the query parameter "unknown" is not found
func Query[V GenericType](c Ctx, key string, defaultValue ...V) V {
var v V
q := c.App().getString(c.Context().QueryArgs().Peek(key))
q := c.App().getString(c.RequestCtx().QueryArgs().Peek(key))

return genericParseType[V](q, v, defaultValue...)
}
Expand Down Expand Up @@ -1630,7 +1630,7 @@ func (c *DefaultCtx) SendFile(file string, config ...SendFile) error {
// Apply cache control header
if status != StatusNotFound && status != StatusForbidden {
if len(cacheControlValue) > 0 {
c.Context().Response.Header.Set(HeaderCacheControl, cacheControlValue)
c.RequestCtx().Response.Header.Set(HeaderCacheControl, cacheControlValue)
}

return nil
Expand Down
12 changes: 6 additions & 6 deletions ctx_interface_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 16 additions & 16 deletions ctx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -843,24 +843,24 @@ func Benchmark_Ctx_Body_With_Compression_Immutable(b *testing.B) {
}
}

// go test -run Test_Ctx_Context
func Test_Ctx_Context(t *testing.T) {
// go test -run Test_Ctx_RequestCtx
func Test_Ctx_RequestCtx(t *testing.T) {
t.Parallel()
app := New()
c := app.AcquireCtx(&fasthttp.RequestCtx{})

require.Equal(t, "*fasthttp.RequestCtx", fmt.Sprintf("%T", c.Context()))
require.Equal(t, "*fasthttp.RequestCtx", fmt.Sprintf("%T", c.RequestCtx()))
}

// go test -run Test_Ctx_UserContext
func Test_Ctx_UserContext(t *testing.T) {
// go test -run Test_Ctx_Context
func Test_Ctx_Context(t *testing.T) {
t.Parallel()
app := New()
c := app.AcquireCtx(&fasthttp.RequestCtx{})

t.Run("Nil_Context", func(t *testing.T) {
t.Parallel()
ctx := c.UserContext()
ctx := c.Context()
require.Equal(t, ctx, context.Background())
})
t.Run("ValueContext", func(t *testing.T) {
Expand All @@ -872,36 +872,36 @@ func Test_Ctx_UserContext(t *testing.T) {
})
}

// go test -run Test_Ctx_SetUserContext
func Test_Ctx_SetUserContext(t *testing.T) {
// go test -run Test_Ctx_SetContext
func Test_Ctx_SetContext(t *testing.T) {
t.Parallel()
app := New()
c := app.AcquireCtx(&fasthttp.RequestCtx{})

testKey := struct{}{}
testValue := "Test Value"
ctx := context.WithValue(context.Background(), testKey, testValue) //nolint: staticcheck // not needed for tests
c.SetUserContext(ctx)
require.Equal(t, testValue, c.UserContext().Value(testKey))
c.SetContext(ctx)
require.Equal(t, testValue, c.Context().Value(testKey))
}

// go test -run Test_Ctx_UserContext_Multiple_Requests
func Test_Ctx_UserContext_Multiple_Requests(t *testing.T) {
// go test -run Test_Ctx_Context_Multiple_Requests
func Test_Ctx_Context_Multiple_Requests(t *testing.T) {
t.Parallel()
testKey := struct{}{}
testValue := "foobar-value"

app := New()
app.Get("/", func(c Ctx) error {
ctx := c.UserContext()
ctx := c.Context()

if ctx.Value(testKey) != nil {
return c.SendStatus(StatusInternalServerError)
}

input := utils.CopyString(Query(c, "input", "NO_VALUE"))
ctx = context.WithValue(ctx, testKey, fmt.Sprintf("%s_%s", testValue, input)) //nolint: staticcheck // not needed for tests
c.SetUserContext(ctx)
c.SetContext(ctx)

return c.Status(StatusOK).SendString(fmt.Sprintf("resp_%s_returned", input))
})
Expand All @@ -913,7 +913,7 @@ func Test_Ctx_UserContext_Multiple_Requests(t *testing.T) {
resp, err := app.Test(httptest.NewRequest(MethodGet, fmt.Sprintf("/?input=%d", i), nil))

require.NoError(t, err, "Unexpected error from response")
require.Equal(t, StatusOK, resp.StatusCode, "context.Context returned from c.UserContext() is reused")
require.Equal(t, StatusOK, resp.StatusCode, "context.Context returned from c.Context() is reused")

b, err := io.ReadAll(resp.Body)
require.NoError(t, err, "Unexpected error from reading response body")
Expand Down Expand Up @@ -3220,7 +3220,7 @@ func Test_Ctx_SendFile_MaxAge(t *testing.T) {
// check expectation
require.NoError(t, err)
require.Equal(t, expectFileContent, c.Response().Body())
require.Equal(t, "public, max-age=100", string(c.Context().Response.Header.Peek(HeaderCacheControl)), "CacheControl Control")
require.Equal(t, "public, max-age=100", string(c.RequestCtx().Response.Header.Peek(HeaderCacheControl)), "CacheControl Control")
require.Equal(t, StatusOK, c.Response().StatusCode())
app.ReleaseCtx(c)
}
Expand Down
53 changes: 26 additions & 27 deletions docs/api/ctx.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,15 +354,20 @@ app.Get("/hello", func(c fiber.Ctx) error {

## Context

Returns [\*fasthttp.RequestCtx](https://godoc.org/github.com/valyala/fasthttp#RequestCtx) that is compatible with the context.Context interface that requires a deadline, a cancellation signal, and other values across API boundaries.
Context returns a context implementation that was set by user earlier or returns a non-nil, empty context, if it was not set earlier.

```go title="Signature"
func (c Ctx) Context() *fasthttp.RequestCtx
func (c Ctx) Context() context.Context
```

:::info
Please read the [Fasthttp Documentation](https://pkg.go.dev/github.com/valyala/fasthttp?tab=doc) for more information.
:::
```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
ctx := c.Context()
// ctx is context implementation set by user

// ...
})
```

## Cookie

Expand Down Expand Up @@ -1489,6 +1494,18 @@ app.Get("/", func(c fiber.Ctx) error {
})
```
## RequestCtx
Returns [\*fasthttp.RequestCtx](https://godoc.org/github.com/valyala/fasthttp#RequestCtx) that is compatible with the context.Context interface that requires a deadline, a cancellation signal, and other values across API boundaries.
```go title="Signature"
func (c Ctx) RequestCtx() *fasthttp.RequestCtx
```
:::info
Please read the [Fasthttp Documentation](https://pkg.go.dev/github.com/valyala/fasthttp?tab=doc) for more information.
:::
## Response
Response return the [\*fasthttp.Response](https://godoc.org/github.com/valyala/fasthttp#Response) pointer
Expand Down Expand Up @@ -1891,18 +1908,18 @@ app.Get("/", func(c fiber.Ctx) error {
})
```

## SetUserContext
## SetContext

Sets the user specified implementation for context interface.
Sets the user specified implementation for context.Context interface.

```go title="Signature"
func (c Ctx) SetUserContext(ctx context.Context)
func (c Ctx) SetContext(ctx context.Context)
```

```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
ctx := context.Background()
c.SetUserContext(ctx)
c.SetContext(ctx)
// Here ctx could be any context implementation
// ...
Expand Down Expand Up @@ -2005,24 +2022,6 @@ app.Get("/", func(c fiber.Ctx) error {
})
```

## UserContext

UserContext returns a context implementation that was set by user earlier
or returns a non-nil, empty context, if it was not set earlier.

```go title="Signature"
func (c Ctx) UserContext() context.Context
```

```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
ctx := c.UserContext()
// ctx is context implementation set by user
// ...
})
```

## Vary

Adds the given header field to the [Vary](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary) response header. This will append the header, if not already listed, otherwise leaves it listed in the current location.
Expand Down
8 changes: 4 additions & 4 deletions docs/middleware/timeout.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ There exist two distinct implementations of timeout middleware [Fiber](https://g

## New

As a `fiber.Handler` wrapper, it creates a context with `context.WithTimeout` and pass it in `UserContext`.
As a `fiber.Handler` wrapper, it creates a context with `context.WithTimeout` which is then used with `c.Context()`.

If the context passed executions (eg. DB ops, Http calls) takes longer than the given duration to return, the timeout error is set and forwarded to the centralized `ErrorHandler`.

Expand Down Expand Up @@ -38,7 +38,7 @@ func main() {
app := fiber.New()
h := func(c fiber.Ctx) error {
sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
if err := sleepWithContext(c.UserContext(), sleepTime); err != nil {
if err := sleepWithContext(c.Context(), sleepTime); err != nil {
return fmt.Errorf("%w: execution error", err)
}
return nil
Expand Down Expand Up @@ -84,7 +84,7 @@ func main() {
app := fiber.New()
h := func(c fiber.Ctx) error {
sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
if err := sleepWithContextWithCustomError(c.UserContext(), sleepTime); err != nil {
if err := sleepWithContextWithCustomError(c.Context(), sleepTime); err != nil {
return fmt.Errorf("%w: execution error", err)
}
return nil
Expand Down Expand Up @@ -116,7 +116,7 @@ func main() {
db, _ := gorm.Open(postgres.Open("postgres://localhost/foodb"), &gorm.Config{})

handler := func(ctx fiber.Ctx) error {
tran := db.WithContext(ctx.UserContext()).Begin()
tran := db.WithContext(ctx.Context()).Begin()

if tran = tran.Exec("SELECT pg_sleep(50)"); tran.Error != nil {
return tran.Error
Expand Down
3 changes: 3 additions & 0 deletions docs/whats_new.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ DRAFT section
- Format -> Param: body interface{} -> handlers ...ResFmt
- Redirect -> c.Redirect().To()
- SendFile now supports different configurations using the config parameter.
- Context has been renamed to RequestCtx which corresponds to the FastHTTP Request Context.
- UserContext has been renamed to Context which returns a context.Context object.
- SetUserContext has been renamed to SetContext.

---

Expand Down
6 changes: 3 additions & 3 deletions middleware/adaptor/adaptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func HTTPHandlerFunc(h http.HandlerFunc) fiber.Handler {
func HTTPHandler(h http.Handler) fiber.Handler {
return func(c fiber.Ctx) error {
handler := fasthttpadaptor.NewFastHTTPHandler(h)
handler(c.Context())
handler(c.RequestCtx())
return nil
}
}
Expand All @@ -43,7 +43,7 @@ func HTTPHandler(h http.Handler) fiber.Handler {
// forServer should be set to true when the http.Request is going to be passed to a http.Handler.
func ConvertRequest(c fiber.Ctx, forServer bool) (*http.Request, error) {
var req http.Request
if err := fasthttpadaptor.ConvertRequest(c.Context(), &req, forServer); err != nil {
if err := fasthttpadaptor.ConvertRequest(c.RequestCtx(), &req, forServer); err != nil {
return nil, err //nolint:wrapcheck // This must not be wrapped
}
return &req, nil
Expand Down Expand Up @@ -108,7 +108,7 @@ func HTTPMiddleware(mw func(http.Handler) http.Handler) fiber.Handler {
c.Request().Header.Set(key, v)
}
}
CopyContextToFiberContext(r.Context(), c.Context())
CopyContextToFiberContext(r.Context(), c.RequestCtx())
})

if err := HTTPHandler(mw(nextHandler))(c); err != nil {
Expand Down
Loading

1 comment on commit 16f9056

@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: 16f9056 Previous: 8c84b0f Ratio
Benchmark_Utils_GetOffer/1_parameter 202.7 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 202.7 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 525 B/op 327 B/op 1.61
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.