Skip to content

Add Execution middleware #4

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ type (
ResolveFieldFinishFunc func(interface{}, error)
// resolveFieldFinishFuncHandler calls the resolveFieldFinishFns for all the extensions
resolveFieldFinishFuncHandler func(interface{}, error) []gqlerrors.FormattedError

// ExecuteFunc computes a GraphQL response.
ExecuteFunc func(p ExecuteParams) (result *Result)
)

// Extension is an interface for extensions in graphql
Expand All @@ -49,6 +52,11 @@ type Extension interface {
// ResolveFieldDidStart notifies about the start of the resolving of a field
ResolveFieldDidStart(context.Context, *ResolveInfo) (context.Context, ResolveFieldFinishFunc)

// ExecuteMiddleware allows the extension to wrap the execution using a chain-of-responsibility pattern,
// modeled after http.Handler. next must be called somewhere within the implementation to preserve the chain. The
// final call and only the final call should trigger ExecutionDidStart and ExecutionFinish hooks.
ExecuteMiddleware(next ExecuteFunc) ExecuteFunc

// HasResult returns if the extension wants to add data to the result
HasResult() bool

Expand Down
44 changes: 44 additions & 0 deletions extensions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,40 @@ func TestExtensionExecutionFinishFuncPanic(t *testing.T) {
}
}

func TestExecutionMiddlewareWasCalled(t *testing.T) {
ext := newtestExt("testExt")
var called bool
ext.executionFunc = func(next graphql.ExecuteFunc) graphql.ExecuteFunc {
return func(p graphql.ExecuteParams) *graphql.Result {
called = true
return next(p)
}
}

schema := tinit(t)
query := `query Example { a }`
schema.AddExtensions(ext)

result := graphql.Do(graphql.Params{
Schema: schema,
RequestString: query,
})

expected := &graphql.Result{
Data: map[string]interface{}{
"a": "foo",
},
}

if !reflect.DeepEqual(expected, result) {
t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result))
}

if !reflect.DeepEqual(called, true) {
t.Fatalf("Middleware was not called")
}
}

func TestExtensionResolveFieldDidStartPanic(t *testing.T) {
ext := newtestExt("testExt")
ext.resolveFieldDidStartFn = func(ctx context.Context, i *graphql.ResolveInfo) (context.Context, graphql.ResolveFieldFinishFunc) {
Expand Down Expand Up @@ -424,6 +458,11 @@ func newtestExt(name string) *testExt {
return nil
}
}
if ext.executionFunc == nil {
ext.executionFunc = func(next graphql.ExecuteFunc) graphql.ExecuteFunc {
return next
}
}
return ext
}

Expand All @@ -436,6 +475,7 @@ type testExt struct {
validationDidStartFn func(ctx context.Context) (context.Context, graphql.ValidationFinishFunc)
executionDidStartFn func(ctx context.Context) (context.Context, graphql.ExecutionFinishFunc)
resolveFieldDidStartFn func(ctx context.Context, i *graphql.ResolveInfo) (context.Context, graphql.ResolveFieldFinishFunc)
executionFunc func(next graphql.ExecuteFunc) graphql.ExecuteFunc
}

func (t *testExt) Init(ctx context.Context, p *graphql.Params) context.Context {
Expand Down Expand Up @@ -469,3 +509,7 @@ func (t *testExt) ExecutionDidStart(ctx context.Context) (context.Context, graph
func (t *testExt) ResolveFieldDidStart(ctx context.Context, i *graphql.ResolveInfo) (context.Context, graphql.ResolveFieldFinishFunc) {
return t.resolveFieldDidStartFn(ctx, i)
}

func (t *testExt) ExecuteMiddleware(next graphql.ExecuteFunc) graphql.ExecuteFunc {
return t.executionFunc(next)
}
8 changes: 7 additions & 1 deletion graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,13 @@ func Do(p Params) *Result {
}
}

return Execute(ExecuteParams{
var exe ExecuteFunc
exe = Execute
for _, e := range p.Schema.extensions {
exe = e.ExecuteMiddleware(exe)
}

return exe(ExecuteParams{
Schema: p.Schema,
Root: p.RootObject,
AST: AST,
Expand Down