-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
[Proposal] Add typed getters for Context values #2770
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
Comments
without delving into if this can be added to Context interface. Why does it not handle missing values or invalid casts as error and missing values defaulting to "zero" is problematic in cases when you need to know if value existed at all or not. |
nb: you could create helper function for that func ContextGet[T any](c echo.Context, key string) T {
v, ok := c.Get(key).(T)
if !ok {
var t = new(T)
return *t
}
return v
} and use it in handler/middlewares e.GET("/", func(c echo.Context) error {
var userID = ContextGet[int](c, "userId")
return c.JSON(http.StatusOK, map[string]int{"value": userID})
}) but it would make more sense if it returned an error when there is no value or cast can not be done. |
or this var ErrKeyNotFound = errors.New("key not found")
var ErrCanNotCastToTarget = errors.New("can not cast to target")
func ContextGet[T any](c echo.Context, key string, target *T) error {
raw := c.Get(key)
if raw == nil {
return ErrKeyNotFound
}
v, ok := raw.(T)
if !ok {
return ErrCanNotCastToTarget
}
*target = v
return nil
} and used like that var userId int = 10
if err := ContextGet(c, "userId", &userId); err != nil {
return err
} or type Args struct {
UserID int `json:"user_id"`
}
args := Args{
UserID: -1, // default to -1
}
if err := ContextGet(c, "userId", &args.UserID); err != nil {
return err
} full example: package main
import (
"errors"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"log/slog"
"net/http"
)
var ErrKeyNotFound = errors.New("key not found")
var ErrCanNotCastToTarget = errors.New("can not cast to target")
func ContextGet[T any](c echo.Context, key string, target *T) error {
raw := c.Get(key)
if raw == nil {
return ErrKeyNotFound
}
v, ok := raw.(T)
if !ok {
return ErrCanNotCastToTarget
}
*target = v
return nil
}
func main() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
c.Set("userId", int(123456))
return next(c)
}
})
e.GET("/", func(c echo.Context) error {
type Args struct {
UserID int `json:"user_id"`
}
args := Args{
UserID: -1, // default to -1
}
if err := ContextGet(c, "userId", &args.UserID); err != nil {
return err
}
return c.JSON(http.StatusOK, args)
})
if err := e.Start(":8080"); err != nil && !errors.Is(err, http.ErrServerClosed) {
slog.Error("server start error", "error", err)
}
} |
@aldas Totally agree. Generics, defaults, parsing are all improvements that must be made first. This was just a quick way for us to migrate out of Just wondering if it's something worth working on as part of |
If I may ask off the topic question - why migrate away from Gin? it is a good library. |
Two reasons mainly:
The rest is just personal preference towards echo that I couldn't justify. |
@aldas talking about Bind, looking at one of your examples, another approach came into my mind: type Data struct {
Foo string `query:"foo"`
Bar int `param:"bar"`
Baz bool `form:"baz"`
Qux float64 `context:"qux"` // type
}
ctx.Set("qux", 1) // notice this is an int and implies type cohersion
var reqVars Data
if err := ctx.Bind(&reqVars); err != nil {
// ...
} |
If you are suggesting adding support for |
To easily access context typed values, would you consider adding typed getters?
This of course would be a breaking change since a bunch of new functions would be added to the Context interface.
We've created an extension to handle such typed getters:
https://github.com/BacoFoods/echoext/blob/master/context.go#L12
I'd be willing to port it to the main project, but I'd like to pick your brains as to the value of this in
echo
before commiting to a PR.*Example Use Case: * passing auth parameters from an auth middleware down to handlers.\
Cheers.
The text was updated successfully, but these errors were encountered: