diff --git a/executable_schema.go b/executable_schema.go index 399a39b7..9fa3a9f8 100644 --- a/executable_schema.go +++ b/executable_schema.go @@ -167,7 +167,7 @@ func (s *ExecutableSchema) ExecuteQuery(ctx context.Context) *graphql.Response { }) if err != nil { - return graphql.ErrorResponse(ctx, err.Error()) + return s.interceptResponse(ctx, operation.Name, operationCtx.RawQuery, variables, graphql.ErrorResponse(ctx, err.Error())) } extensions := make(map[string]interface{}) @@ -196,9 +196,9 @@ func (s *ExecutableSchema) ExecuteQuery(ctx context.Context) *graphql.Response { qe := newQueryExecution(ctx, operationCtx.OperationName, s.GraphqlClient, filteredSchema, s.BoundaryQueries, int32(s.MaxRequestsPerQuery)) results, executeErrs := qe.Execute(plan) if len(executeErrs) > 0 { - return &graphql.Response{ + return s.interceptResponse(ctx, operation.Name, operationCtx.RawQuery, variables, &graphql.Response{ Errors: executeErrs, - } + }) } for _, result := range results { @@ -224,9 +224,9 @@ func (s *ExecutableSchema) ExecuteQuery(ctx context.Context) *graphql.Response { if err != nil { errs = append(errs, &gqlerror.Error{Message: err.Error()}) AddField(ctx, "errors", errs) - return &graphql.Response{ + return s.interceptResponse(ctx, operation.Name, operationCtx.RawQuery, variables, &graphql.Response{ Errors: errs, - } + }) } bubbleErrs, err := bubbleUpNullValuesInPlace(filteredSchema, operation.SelectionSet, mergedResult) @@ -235,9 +235,9 @@ func (s *ExecutableSchema) ExecuteQuery(ctx context.Context) *graphql.Response { } else if err != nil { errs = append(errs, &gqlerror.Error{Message: err.Error()}) AddField(ctx, "errors", errs) - return &graphql.Response{ + return s.interceptResponse(ctx, operation.Name, operationCtx.RawQuery, variables, &graphql.Response{ Errors: errs, - } + }) } errs = append(errs, bubbleErrs...) @@ -251,10 +251,17 @@ func (s *ExecutableSchema) ExecuteQuery(ctx context.Context) *graphql.Response { AddField(ctx, "errors", errs) } - return &graphql.Response{ + return s.interceptResponse(ctx, operation.Name, operationCtx.RawQuery, variables, &graphql.Response{ Data: formattedResponse, Errors: errs, + }) +} + +func (s *ExecutableSchema) interceptResponse(ctx context.Context, operationName, rawQuery string, variables map[string]interface{}, response *graphql.Response) *graphql.Response { + for _, plugin := range s.plugins { + response = plugin.InterceptResponse(ctx, operationName, rawQuery, variables, response) } + return response } // Schema returns the merged schema diff --git a/plugin.go b/plugin.go index 5f3242f8..f2ec6dd5 100644 --- a/plugin.go +++ b/plugin.go @@ -5,6 +5,7 @@ import ( "encoding/json" "net/http" + "github.com/99designs/gqlgen/graphql" log "github.com/sirupsen/logrus" ) @@ -28,6 +29,7 @@ type Plugin interface { WrapGraphQLClientTransport(http.RoundTripper) http.RoundTripper InterceptRequest(ctx context.Context, operationName, rawQuery string, variables map[string]interface{}) + InterceptResponse(ctx context.Context, operationName, rawQuery string, variables map[string]interface{}, response *graphql.Response) *graphql.Response } // BasePlugin is an empty plugin. It can be embedded by any plugin as a way to avoid @@ -58,6 +60,12 @@ func (p *BasePlugin) GraphqlQueryPath() (bool, string) { func (p *BasePlugin) InterceptRequest(ctx context.Context, operationName, rawQuery string, variables map[string]interface{}) { } +// InterceptResponse is called after bramble has finished executing a request. +// It can be used to inspect and/or modify the response bramble will return. +func (p *BasePlugin) InterceptResponse(ctx context.Context, operationName, rawQuery string, variables map[string]interface{}, response *graphql.Response) *graphql.Response { + return response +} + // ApplyMiddlewarePublicMux ... func (p *BasePlugin) ApplyMiddlewarePublicMux(h http.Handler) http.Handler { return h