Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addition of Locals Function with Go Generics as an Alternative to c.Locals #2813

Merged
merged 7 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,21 @@ func (c *DefaultCtx) Locals(key any, value ...any) any {
return value[0]
}

// Locals function utilizing Go's generics feature.
// This function allows for manipulating and retrieving local values within a request context with a more specific data type.
func Locals[V any](c Ctx, key any, value ...any) V {
ReneWerner87 marked this conversation as resolved.
Show resolved Hide resolved
ctx, ok := c.(*DefaultCtx)
ReneWerner87 marked this conversation as resolved.
Show resolved Hide resolved
if !ok {
panic(fmt.Errorf("failed to type-assert to *DefaultCtx"))
}
var v V
v, ok = ctx.Locals(key, value...).(V)
if !ok {
panic(fmt.Errorf("failed to type-assert to %T", v))
ReneWerner87 marked this conversation as resolved.
Show resolved Hide resolved
}
return v
}

// Location sets the response Location HTTP header to the specified path parameter.
func (c *DefaultCtx) Location(path string) {
c.setCanonical(HeaderLocation, path)
Expand Down
44 changes: 44 additions & 0 deletions ctx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,50 @@ func Test_Ctx_Locals(t *testing.T) {
require.Equal(t, StatusOK, resp.StatusCode, "Status code")
}

// go test -run Test_Ctx_Locals_Generic
func Test_Ctx_Locals_Generic(t *testing.T) {
t.Parallel()
app := New()
app.Use(func(c Ctx) error {
Locals[string](c, "john", "doe")
Locals[int](c, "age", 18)
Locals[bool](c, "isHuman", true)
return c.Next()
})
app.Get("/test", func(c Ctx) error {
require.Equal(t, "doe", Locals[string](c, "john"))
require.Equal(t, 18, Locals[int](c, "age"))
require.Equal(t, true, Locals[bool](c, "isHuman"))
return nil
})
resp, err := app.Test(httptest.NewRequest(MethodGet, "/test", nil))
require.NoError(t, err, "app.Test(req)")
require.Equal(t, StatusOK, resp.StatusCode, "Status code")
}

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

type User struct {
name string
age int
}

app := New()
app.Use(func(c Ctx) error {
Locals[User](c, "user", User{"john", 18})
return c.Next()
})
app.Use("/test", func(c Ctx) error {
require.Equal(t, User{"john", 18}, Locals[User](c, "user"))
return nil
})
resp, err := app.Test(httptest.NewRequest(MethodGet, "/test", nil))
require.NoError(t, err, "app.Test(req)")
require.Equal(t, StatusOK, resp.StatusCode, "Status code")
}

// go test -run Test_Ctx_Method
func Test_Ctx_Method(t *testing.T) {
t.Parallel()
Expand Down
28 changes: 28 additions & 0 deletions docs/api/ctx.md
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,34 @@ app.Get("/admin", func(c fiber.Ctx) error {
})
```

An alternative version of the Locals method that takes advantage of Go's generics feature is also available. This version
allows for the manipulation and retrieval of local values within a request's context with a more specific data type.

```go title="Signature"
func Locals[V any](c Ctx, key any, value ...any) V
```

```go title="Example"
app.Use(func(c Ctx) error {
fiber.Locals[string](c, "john", "doe")
fiber.Locals[int](c, "age", 18)
fiber.Locals[bool](c, "isHuman", true)
return c.Next()
})
app.Get("/test", func(c Ctx) error {
fiber.Locals[string](c, "john") // "doe"
fiber.Locals[int](c, "age") // 18
fiber.Locals[bool](c, "isHuman") // true
return nil
ReneWerner87 marked this conversation as resolved.
Show resolved Hide resolved
})
````

Keep in mind, you will need Go 1.18 or later to take advantage of generics. Also, be aware of the types you pass into
ryanbekhen marked this conversation as resolved.
Show resolved Hide resolved
the generic function. A runtime panic will occur if the type does not match the expected type.

Make sure to understand and correctly implement the Locals method in both its standard and generic form for better control
over route-specific data within your application.

## Location

Sets the response [Location](https://developer.mozilla.org/ru/docs/Web/HTTP/Headers/Location) HTTP header to the specified path parameter.
Expand Down
Loading