mirror of https://github.com/gofiber/fiber.git
Addition of Locals Function with Go Generics as an Alternative to c.Locals (#2813)
* Add type-specific local value handling with generics in Ctx Introduced a new function, Locals, that utilizes Go's generics to handle and retrieve type-specific local values within a request context. This enhancement provides more accurate data type control within the context. Included are tests for generic and custom struct use-cases to ensure the function performs as expected. * Update documentation for Go generics in Locals method Added documentation to explain the new version of the Locals method that uses Go's generics feature. This version allows for better control of data types when manipulating and retrieving local values within a request's context. Examples are provided, along with a caution on using correct data types to prevent a runtime panic. * update ctx.md * Correct indentation in API documentation * Refactor Locals function and add new test case * Refactor Locals function and add new test case --------- Co-authored-by: Deza Farras Tsany <deza.ftsany@gmail.com>pull/2820/head
parent
31246ffe24
commit
738e062d5b
16
ctx.go
16
ctx.go
|
@ -817,6 +817,22 @@ 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 ...V) V {
|
||||
var v V
|
||||
var ok bool
|
||||
if len(value) == 0 {
|
||||
v, ok = c.Locals(key).(V)
|
||||
} else {
|
||||
v, ok = c.Locals(key, value[0]).(V)
|
||||
}
|
||||
if !ok {
|
||||
return v // return zero of type V
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Location sets the response Location HTTP header to the specified path parameter.
|
||||
func (c *DefaultCtx) Location(path string) {
|
||||
c.setCanonical(HeaderLocation, path)
|
||||
|
|
45
ctx_test.go
45
ctx_test.go
|
@ -1757,6 +1757,51 @@ 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"))
|
||||
require.Equal(t, 0, Locals[int](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()
|
||||
|
|
|
@ -1000,6 +1000,31 @@ 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
|
||||
})
|
||||
````
|
||||
|
||||
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.
|
||||
|
|
Loading…
Reference in New Issue