Closed jarrettv closed 1 year ago
Interesting idea. Maybe even add a mechanism for registering custom unmarshalers on a specific tag.
I was thinking about this and providing the context values are basic types the decoder used for headers, path etc. could quite easily be re-used for context.
Making it work with arbitrary types including structs etc would be quite a bit more work though.
In hindsight, I understand that most context value keys aren't basic types and why this would be so difficult. However, I do like your idea of "registering custom unmarshalers on a specific tag".
Hi @jarrettv ,
Sorry for leaving this issue sitting here for a while. Although it's slightly hacky it's actually possible to achieve this by using the decoder that's used for headers etc. in the handler function.
See the following example. Will close this as the option with registering decoders on tags is so niche that I'd rather not add it at this point.
package main
import (
"context"
"fmt"
"log"
"github.com/abemedia/go-don"
"github.com/abemedia/go-don/decoder"
_ "github.com/abemedia/go-don/encoding/json"
"github.com/valyala/fasthttp"
)
type Context struct {
context.Context
}
func (ctx Context) Get(key string) string {
v := ctx.Context.Value(key)
if v == nil {
return ""
}
return fmt.Sprint(v)
}
func (ctx Context) Values(key string) []string {
return []string{ctx.Get(key)}
}
var decodeContext = decoder.New("context")
type MyRequest struct {
UserName string `context:"userName"`
}
func MyHandler(ctx context.Context, req MyRequest) (string, error) {
err := decodeContext.Decode(Context{ctx}, &req)
if err != nil {
return "", err
}
return req.UserName, nil
}
func main() {
r := don.New(&don.Config{DefaultEncoding: "application/json"})
r.Post("/", don.H(MyHandler))
// Mock middleware which adds the username.
r.Use(func(next fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
ctx.SetUserValue("userName", "Test User")
next(ctx)
}
})
log.Fatal(r.ListenAndServe(":8080"))
}
Idea to include context unmarshalling into the request struct or a simple way for custom model binding based on tags: