From 8588110d2e868e63e9dc340b3353d3cfa1d82529 Mon Sep 17 00:00:00 2001 From: Robert Roland Date: Tue, 10 Jul 2018 15:13:36 -0700 Subject: [PATCH] Allows a RootObject to be generated per request Right now, there is no way to generate a default RootObject without forking this repo entirely. This expands on graphql-go/handler#9 by using a generator function for the root object, and graphql-go/handler#30 by not changing any other contracts in the handler. --- handler.go | 33 +++++++++++++++++++++------------ handler_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/handler.go b/handler.go index eebd0a3..ce2d700 100644 --- a/handler.go +++ b/handler.go @@ -19,10 +19,11 @@ const ( ) type Handler struct { - Schema *graphql.Schema - pretty bool - graphiql bool - playground bool + Schema *graphql.Schema + pretty bool + graphiql bool + playground bool + rootObjectFn RootObjectFn } type RequestOptions struct { Query string `json:"query" url:"query" schema:"query"` @@ -128,6 +129,9 @@ func (h *Handler) ContextHandler(ctx context.Context, w http.ResponseWriter, r * OperationName: opts.OperationName, Context: ctx, } + if h.rootObjectFn != nil { + params.RootObject = h.rootObjectFn(ctx, r) + } result := graphql.Do(params) if h.graphiql { @@ -169,11 +173,15 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.ContextHandler(r.Context(), w, r) } +// RootObjectFn allows a user to generate a RootObject per request +type RootObjectFn func(ctx context.Context, r *http.Request) map[string]interface{} + type Config struct { - Schema *graphql.Schema - Pretty bool - GraphiQL bool - Playground bool + Schema *graphql.Schema + Pretty bool + GraphiQL bool + Playground bool + RootObjectFn RootObjectFn } func NewConfig() *Config { @@ -194,9 +202,10 @@ func New(p *Config) *Handler { } return &Handler{ - Schema: p.Schema, - pretty: p.Pretty, - graphiql: p.GraphiQL, - playground: p.Playground, + Schema: p.Schema, + pretty: p.Pretty, + graphiql: p.GraphiQL, + playground: p.Playground, + rootObjectFn: p.RootObjectFn, } } diff --git a/handler_test.go b/handler_test.go index ea73d2a..9a579fa 100644 --- a/handler_test.go +++ b/handler_test.go @@ -11,6 +11,7 @@ import ( "testing" "context" + "github.com/graphql-go/graphql" "github.com/graphql-go/graphql/testutil" "github.com/graphql-go/handler" @@ -150,3 +151,48 @@ func TestHandler_Params_NilParams(t *testing.T) { _ = handler.New(nil) } + +func TestHandler_BasicQuery_WithRootObjFn(t *testing.T) { + myNameQuery := graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "name": &graphql.Field{ + Name: "name", + Type: graphql.String, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + rv := p.Info.RootValue.(map[string]interface{}) + return rv["rootValue"], nil + }, + }, + }, + }) + myNameSchema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: myNameQuery, + }) + if err != nil { + t.Fatal(err) + } + + expected := &graphql.Result{ + Data: map[string]interface{}{ + "name": "foo", + }, + } + queryString := `query={name}` + req, _ := http.NewRequest("GET", fmt.Sprintf("/graphql?%v", queryString), nil) + + h := handler.New(&handler.Config{ + Schema: &myNameSchema, + Pretty: true, + RootObjectFn: func(ctx context.Context, r *http.Request) map[string]interface{} { + return map[string]interface{}{"rootValue": "foo"} + }, + }) + result, resp := executeTest(t, h, req) + if resp.Code != http.StatusOK { + t.Fatalf("unexpected server response %v", resp.Code) + } + if !reflect.DeepEqual(result, expected) { + t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result)) + } +}