diff --git a/client.go b/client.go index 984e52e2..aa249217 100644 --- a/client.go +++ b/client.go @@ -27,6 +27,10 @@ type ClientOpt func(*GraphQLClient) // NewClient creates a new GraphQLClient from the given options. func NewClient(opts ...ClientOpt) *GraphQLClient { + return NewClientWithPlugins(nil, opts...) +} + +func NewClientWithPlugins(plugins []Plugin, opts ...ClientOpt) *GraphQLClient { c := &GraphQLClient{ HTTPClient: &http.Client{ Timeout: 5 * time.Second, @@ -38,6 +42,9 @@ func NewClient(opts ...ClientOpt) *GraphQLClient { opt(c) } + for _, plugin := range plugins { + c.HTTPClient.Transport = plugin.WrapGraphQLClientTransport(c.HTTPClient.Transport) + } return c } diff --git a/config.go b/config.go index f3861880..25e3df0f 100644 --- a/config.go +++ b/config.go @@ -271,7 +271,7 @@ func (c *Config) Init() error { if c.QueryHTTPClient != nil { queryClientOptions = append(queryClientOptions, WithHTTPClient(c.QueryHTTPClient)) } - queryClient := NewClient(queryClientOptions...) + queryClient := NewClientWithPlugins(c.plugins, queryClientOptions...) es := NewExecutableSchema(c.plugins, c.MaxRequestsPerQuery, queryClient, services...) err = es.UpdateSchema(true) if err != nil { diff --git a/execution.go b/execution.go index ae9163cc..58a0988d 100644 --- a/execution.go +++ b/execution.go @@ -21,7 +21,7 @@ func NewExecutableSchema(plugins []Plugin, maxRequestsPerQuery int64, client *Gr } if client == nil { - client = NewClient() + client = NewClientWithPlugins(plugins) } return &ExecutableSchema{ @@ -138,6 +138,10 @@ func (s *ExecutableSchema) ExecuteQuery(ctx context.Context) *graphql.Response { operation := operationCtx.Operation variables := operationCtx.Variables + for _, plugin := range s.plugins { + plugin.InterceptRequest(ctx, operation.Name, operationCtx.RawQuery, variables) + } + AddField(ctx, "operation.name", operation.Name) AddField(ctx, "operation.type", operation.Operation) diff --git a/plugin.go b/plugin.go index d86c4e85..5f3242f8 100644 --- a/plugin.go +++ b/plugin.go @@ -1,6 +1,7 @@ package bramble import ( + "context" "encoding/json" "net/http" @@ -24,6 +25,9 @@ type Plugin interface { GraphqlQueryPath() (bool, string) ApplyMiddlewarePublicMux(http.Handler) http.Handler ApplyMiddlewarePrivateMux(http.Handler) http.Handler + WrapGraphQLClientTransport(http.RoundTripper) http.RoundTripper + + InterceptRequest(ctx context.Context, operationName, rawQuery string, variables map[string]interface{}) } // BasePlugin is an empty plugin. It can be embedded by any plugin as a way to avoid @@ -49,6 +53,11 @@ func (p *BasePlugin) GraphqlQueryPath() (bool, string) { return false, "" } +// InterceptRequest is called before bramble starts executing a request. +// It can be used to inspect the unmarshalled GraphQL request bramble receives. +func (p *BasePlugin) InterceptRequest(ctx context.Context, operationName, rawQuery string, variables map[string]interface{}) { +} + // ApplyMiddlewarePublicMux ... func (p *BasePlugin) ApplyMiddlewarePublicMux(h http.Handler) http.Handler { return h @@ -59,6 +68,11 @@ func (p *BasePlugin) ApplyMiddlewarePrivateMux(h http.Handler) http.Handler { return h } +// WrapGraphQLClientTransport wraps the http.RoundTripper used for GraphQL requests. +func (p *BasePlugin) WrapGraphQLClientTransport(transport http.RoundTripper) http.RoundTripper { + return transport +} + var registeredPlugins = map[string]Plugin{} // RegisterPlugin register a plugin so that it can be enabled via the configuration.