In my golang project I am using Fiber (https://gofiber.io/) as a router and somewhere in code I am setting some values in fibers context. Now I am adding graphql (https://github.com/99designs/gqlgen) endpoints and in resolvers context I need to access values set in fibers context. In router I added the following:
import (
"github.com/gofiber/adaptor/v2"
"github.com/gofiber/fiber/v2"
gql_handler "github.com/99designs/gqlgen/graphql/handler"
)
server := gql_handler.NewDefaultServer(generated.NewExecutableSchema(
generated.Config{
Resolvers: h.createResolvers(),
Directives: h.createDirectives(),
Complexity: h.createComplexity(),
},
))
route := r.Group("/graph")
route.Get("/playground", adaptor.HTTPHandlerFunc(playground.Handler("Graphql Playground", "/graph")))
route.All("", adaptor.HTTPHandler(server))
so somewhere in my code I do:
func (h *Handler) MyFunc(c *fiber.Ctx) error {
//setting value in fibers context
c.Locals("MyTestValue", "some_value")
return nil
}
and in my graphql resolver I want to access it:
func (r *queryResolver) MyQuery(ctx context.Context) (bool, error) {
fmt.Println(ctx.Value("MyTestValue"))//returns nil
return true, nil
}
I tried to create a middleware to pass fiber context into regular context (as it is made for gin router, for example) but it did not work:
func FiberContextToContext() fiber.Handler {
return func(c *fiber.Ctx) error {
ctx := context.WithValue(c.Context(), "FiberContextKey", c)
//c.Context() = c.WithContext(ctx)//errors here
return c.Next()
}
}
Any ideas how to fix it would be welcome. Thank you.
First note: if you want to change the value behind a pointer, you'ld need to apply a construction like:
Second note: this won't work because in you case
ctxis not of typefasthttp.RequestCtx(fasthttp.RequestCtximplementscontext.Context, not the other way around.)So, in general you're right, with
fiberyou setLocals, which basically just sets afasthttp.UserValue. And there's where the problems begin.UserValuesget "lost" after the conversion withadaptor. There's an open issue for that, but it's not an easy one to solve.Effectively, this is where your precious local variables end up:
So they are hidden in an object behind the key
"__local_user_context__".My workaround is this:
It's not great and might break when this key is rename - or even worse, becomes a private
typeinstead of astring. Maybe other users can come up with better ideas.In general, it's to just rely on
fiber/fasthttphandlers. But sadly forgqlgenthat's not possible - my screenshot stemps from exactly the same scenario. Still you should keep the following considerations in mind:fibermiddleware? Otherwise, you could just set regularhttpmiddleware and move it into theadaptor.fiberhere at all? With the usage of theadaptor, I expect that most of the gain in performance to be lost, b/cfiber(resp. openfaas) is based on reusing objects, and this gets dropped after the conversion.