-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
<!-- Provide a general summary of your changes in the Title above --> [TT-10962](https://tyktech.atlassian.net/browse/TT-10962) <!-- Describe your changes in detail --> <!-- This project only accepts pull requests related to open issues. --> <!-- If suggesting a new feature or change, please discuss it in an issue first. --> <!-- If fixing a bug, there should be an issue describing it with steps to reproduce. --> <!-- OSS: Please link to the issue here. Tyk: please create/link the JIRA ticket. --> <!-- Why is this change required? What problem does it solve? --> <!-- Please describe in detail how you tested your changes --> <!-- Include details of your testing environment, and the tests --> <!-- you ran to see how your change affects other areas of the code, etc. --> <!-- This information is helpful for reviewers and QA. --> <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Refactoring or add test (improvements in base code or adds test coverage to functionality) <!-- Go over all the following points, and put an `x` in all the boxes that apply --> <!-- If there are no documentation updates required, mark the item as checked. --> <!-- Raise up any additional concerns not covered by the checklist. --> - [ ] I ensured that the documentation is up to date - [ ] I explained why this PR updates go.mod in detail with reasoning why it's required - [ ] I would like a code coverage CI quality gate exception and have explained why [TT-10962]: https://tyktech.atlassian.net/browse/TT-10962?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ ___ bug_fix ___ - Disabled the `EnableSingleFlight` feature in both `ProxyOnly` and `UniversalDataGraph` adapters to address existing issues. ___ <table><thead><tr><th></th><th align="left">Relevant files</th></tr></thead><tbody><tr><td><strong>Bug fix</strong></td><td><table> <tr> <td> <details> <summary><strong>adapter_proxy_only.go</strong><dd><code>Disable SingleFlight in ProxyOnly Adapter</code> </dd></summary> <hr> apidef/adapter/gqlengineadapter/adapter_proxy_only.go <li>Disabled <code>EnableSingleFlight</code> feature by setting its value to <code>false</code>.<br> </details> </td> <td><a href="https://pull/6072/files#diff-c3d2491b83997adf408861dc51e396c95e2baabba8286309f5c344cfcee7d78b">+1/-1</a> </td> </tr> <tr> <td> <details> <summary><strong>adapter_udg.go</strong><dd><code>Disable SingleFlight in UniversalDataGraph Adapter</code> </dd></summary> <hr> apidef/adapter/gqlengineadapter/adapter_udg.go <li>Disabled <code>EnableSingleFlight</code> feature by setting its value to <code>false</code>.<br> </details> </td> <td><a href="https://pull/6072/files#diff-f01b6f97ed0e7bbe78b66c8d0c5e34fbabf49683a4a0784f7b25ebaabe97c03b">+1/-1</a> </td> </tr> </table></td></tr></tr></tbody></table> ___ > ✨ **PR-Agent usage**: >Comment `/help` on the PR to get a list of all available PR-Agent tools and their descriptions Co-authored-by: Shakira Salazar <69164527+rhianeKobar@users.noreply.github.com> (cherry picked from commit 9ed401d)
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package gqlengineadapter | ||
|
||
import ( | ||
"net/http" | ||
"strings" | ||
|
||
graphqlDataSource "github.com/TykTechnologies/graphql-go-tools/pkg/engine/datasource/graphql_datasource" | ||
"github.com/TykTechnologies/graphql-go-tools/pkg/graphql" | ||
|
||
"github.com/TykTechnologies/tyk/apidef" | ||
) | ||
|
||
type ProxyOnly struct { | ||
ApiDefinition *apidef.APIDefinition | ||
HttpClient *http.Client | ||
StreamingClient *http.Client | ||
Schema *graphql.Schema | ||
|
||
subscriptionClientFactory graphqlDataSource.GraphQLSubscriptionClientFactory | ||
} | ||
|
||
func (p *ProxyOnly) EngineConfig() (*graphql.EngineV2Configuration, error) { | ||
var err error | ||
if p.Schema == nil { | ||
p.Schema, err = parseSchema(p.ApiDefinition.GraphQL.Schema) | ||
Check failure on line 25 in apidef/adapter/gqlengineadapter/adapter_proxy_only.go GitHub Actions / Go 1.16 Redis 5
|
||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
staticHeaders := make(http.Header) | ||
for key, value := range p.ApiDefinition.GraphQL.Proxy.RequestHeaders { | ||
staticHeaders.Set(key, value) | ||
} | ||
|
||
url := p.ApiDefinition.Proxy.TargetURL | ||
if strings.HasPrefix(url, "tyk://") { | ||
url = strings.ReplaceAll(url, "tyk://", "http://") | ||
staticHeaders.Set(apidef.TykInternalApiHeader, "true") | ||
} | ||
|
||
upstreamConfig := graphql.ProxyUpstreamConfig{ | ||
URL: url, | ||
StaticHeaders: staticHeaders, | ||
SubscriptionType: graphqlSubscriptionType(p.ApiDefinition.GraphQL.Proxy.SubscriptionType), | ||
Check failure on line 45 in apidef/adapter/gqlengineadapter/adapter_proxy_only.go GitHub Actions / Go 1.16 Redis 5
|
||
} | ||
|
||
v2Config, err := graphql.NewProxyEngineConfigFactory( | ||
p.Schema, | ||
upstreamConfig, | ||
graphqlDataSource.NewBatchFactory(), | ||
graphql.WithProxyHttpClient(p.HttpClient), | ||
graphql.WithProxyStreamingClient(p.StreamingClient), | ||
graphql.WithProxySubscriptionClientFactory(subscriptionClientFactoryOrDefault(p.subscriptionClientFactory)), | ||
Check failure on line 54 in apidef/adapter/gqlengineadapter/adapter_proxy_only.go GitHub Actions / Go 1.16 Redis 5
|
||
).EngineV2Configuration() | ||
|
||
v2Config.EnableSingleFlight(false) | ||
return &v2Config, err | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
package gqlengineadapter | ||
|
||
import ( | ||
"encoding/json" | ||
"net/http" | ||
|
||
graphqlDataSource "github.com/TykTechnologies/graphql-go-tools/pkg/engine/datasource/graphql_datasource" | ||
kafkaDataSource "github.com/TykTechnologies/graphql-go-tools/pkg/engine/datasource/kafka_datasource" | ||
restDataSource "github.com/TykTechnologies/graphql-go-tools/pkg/engine/datasource/rest_datasource" | ||
"github.com/TykTechnologies/graphql-go-tools/pkg/engine/plan" | ||
"github.com/TykTechnologies/graphql-go-tools/pkg/graphql" | ||
|
||
"github.com/TykTechnologies/tyk/apidef" | ||
) | ||
|
||
type UniversalDataGraph struct { | ||
ApiDefinition *apidef.APIDefinition | ||
HttpClient *http.Client | ||
StreamingClient *http.Client | ||
Schema *graphql.Schema | ||
|
||
subscriptionClientFactory graphqlDataSource.GraphQLSubscriptionClientFactory | ||
} | ||
|
||
func (u *UniversalDataGraph) EngineConfig() (*graphql.EngineV2Configuration, error) { | ||
var err error | ||
if u.Schema == nil { | ||
u.Schema, err = parseSchema(u.ApiDefinition.GraphQL.Schema) | ||
Check failure on line 28 in apidef/adapter/gqlengineadapter/adapter_udg.go GitHub Actions / Go 1.16 Redis 5
|
||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
conf := graphql.NewEngineV2Configuration(u.Schema) | ||
conf.EnableSingleFlight(false) | ||
|
||
fieldConfigs := u.engineConfigV2FieldConfigs() | ||
datsSources, err := u.engineConfigV2DataSources() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
conf.SetFieldConfigurations(fieldConfigs) | ||
conf.SetDataSources(datsSources) | ||
|
||
return &conf, nil | ||
} | ||
|
||
func (u *UniversalDataGraph) engineConfigV2FieldConfigs() (planFieldConfigs plan.FieldConfigurations) { | ||
for _, fc := range u.ApiDefinition.GraphQL.Engine.FieldConfigs { | ||
planFieldConfig := plan.FieldConfiguration{ | ||
TypeName: fc.TypeName, | ||
FieldName: fc.FieldName, | ||
DisableDefaultMapping: fc.DisableDefaultMapping, | ||
Path: fc.Path, | ||
} | ||
|
||
planFieldConfigs = append(planFieldConfigs, planFieldConfig) | ||
} | ||
|
||
generatedArgs := u.Schema.GetAllFieldArguments(graphql.NewSkipReservedNamesFunc()) | ||
generatedArgsAsLookupMap := graphql.CreateTypeFieldArgumentsLookupMap(generatedArgs) | ||
u.engineConfigV2Arguments(&planFieldConfigs, generatedArgsAsLookupMap) | ||
|
||
return planFieldConfigs | ||
} | ||
|
||
func (u *UniversalDataGraph) engineConfigV2DataSources() (planDataSources []plan.DataSourceConfiguration, err error) { | ||
for _, ds := range u.ApiDefinition.GraphQL.Engine.DataSources { | ||
planDataSource := plan.DataSourceConfiguration{ | ||
RootNodes: []plan.TypeField{}, | ||
} | ||
|
||
for _, typeField := range ds.RootFields { | ||
planTypeField := plan.TypeField{ | ||
TypeName: typeField.Type, | ||
FieldNames: typeField.Fields, | ||
} | ||
|
||
planDataSource.RootNodes = append(planDataSource.RootNodes, planTypeField) | ||
} | ||
|
||
switch ds.Kind { | ||
case apidef.GraphQLEngineDataSourceKindREST: | ||
var restConfig apidef.GraphQLEngineDataSourceConfigREST | ||
err = json.Unmarshal(ds.Config, &restConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
planDataSource.Factory = &restDataSource.Factory{ | ||
Client: u.HttpClient, | ||
} | ||
|
||
urlWithoutQueryParams, queryConfigs, err := extractURLQueryParamsForEngineV2(restConfig.URL, restConfig.Query) | ||
Check failure on line 95 in apidef/adapter/gqlengineadapter/adapter_udg.go GitHub Actions / Go 1.16 Redis 5
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
planDataSource.Custom = restDataSource.ConfigJSON(restDataSource.Configuration{ | ||
Fetch: restDataSource.FetchConfiguration{ | ||
URL: urlWithoutQueryParams, | ||
Method: restConfig.Method, | ||
Body: restConfig.Body, | ||
Query: queryConfigs, | ||
Header: convertApiDefinitionHeadersToHttpHeaders(restConfig.Headers), | ||
Check failure on line 106 in apidef/adapter/gqlengineadapter/adapter_udg.go GitHub Actions / Go 1.16 Redis 5
|
||
}, | ||
}) | ||
|
||
case apidef.GraphQLEngineDataSourceKindGraphQL: | ||
var graphqlConfig apidef.GraphQLEngineDataSourceConfigGraphQL | ||
err = json.Unmarshal(ds.Config, &graphqlConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if graphqlConfig.HasOperation { | ||
Check failure on line 117 in apidef/adapter/gqlengineadapter/adapter_udg.go GitHub Actions / Go 1.16 Redis 5
|
||
planDataSource.Factory = &restDataSource.Factory{ | ||
Client: u.HttpClient, | ||
} | ||
planDataSource.Custom, err = generateRestDataSourceFromGraphql(graphqlConfig) | ||
Check failure on line 121 in apidef/adapter/gqlengineadapter/adapter_udg.go GitHub Actions / Go 1.16 Redis 5
|
||
if err != nil { | ||
return nil, err | ||
} | ||
break | ||
} | ||
|
||
planDataSource.Factory, err = createGraphQLDataSourceFactory(createGraphQLDataSourceFactoryParams{ | ||
Check failure on line 128 in apidef/adapter/gqlengineadapter/adapter_udg.go GitHub Actions / Go 1.16 Redis 5
Check failure on line 128 in apidef/adapter/gqlengineadapter/adapter_udg.go GitHub Actions / Go 1.16 Redis 5
Check failure on line 128 in apidef/adapter/gqlengineadapter/adapter_udg.go GitHub Actions / Go 1.16 Redis 5
|
||
graphqlConfig: graphqlConfig, | ||
subscriptionClientFactory: subscriptionClientFactoryOrDefault(u.subscriptionClientFactory), | ||
httpClient: u.HttpClient, | ||
streamingClient: u.StreamingClient, | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
planDataSource.Custom = graphqlDataSource.ConfigJson(graphqlDataSourceConfiguration( | ||
graphqlConfig.URL, | ||
graphqlConfig.Method, | ||
graphqlConfig.Headers, | ||
graphqlConfig.SubscriptionType, | ||
)) | ||
|
||
case apidef.GraphQLEngineDataSourceKindKafka: | ||
var kafkaConfig apidef.GraphQLEngineDataSourceConfigKafka | ||
err = json.Unmarshal(ds.Config, &kafkaConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
planDataSource.Factory = &kafkaDataSource.Factory{} | ||
planDataSource.Custom = kafkaDataSource.ConfigJSON(kafkaDataSource.Configuration{ | ||
Subscription: kafkaDataSource.SubscriptionConfiguration{ | ||
BrokerAddresses: kafkaConfig.BrokerAddresses, | ||
Topics: kafkaConfig.Topics, | ||
GroupID: kafkaConfig.GroupID, | ||
ClientID: kafkaConfig.ClientID, | ||
KafkaVersion: kafkaConfig.KafkaVersion, | ||
StartConsumingLatest: kafkaConfig.StartConsumingLatest, | ||
BalanceStrategy: kafkaConfig.BalanceStrategy, | ||
IsolationLevel: kafkaConfig.IsolationLevel, | ||
SASL: kafkaConfig.SASL, | ||
}, | ||
}) | ||
} | ||
|
||
planDataSources = append(planDataSources, planDataSource) | ||
} | ||
|
||
err = u.determineChildNodes(planDataSources) | ||
return planDataSources, err | ||
} | ||
|
||
func (u *UniversalDataGraph) engineConfigV2Arguments(fieldConfs *plan.FieldConfigurations, generatedArgs map[graphql.TypeFieldLookupKey]graphql.TypeFieldArguments) { | ||
for i := range *fieldConfs { | ||
if len(generatedArgs) == 0 { | ||
return | ||
} | ||
|
||
lookupKey := graphql.CreateTypeFieldLookupKey((*fieldConfs)[i].TypeName, (*fieldConfs)[i].FieldName) | ||
currentArgs, ok := generatedArgs[lookupKey] | ||
if !ok { | ||
continue | ||
} | ||
|
||
(*fieldConfs)[i].Arguments = createArgumentConfigurationsForArgumentNames(currentArgs.ArgumentNames...) | ||
delete(generatedArgs, lookupKey) | ||
} | ||
|
||
for _, genArgs := range generatedArgs { | ||
*fieldConfs = append(*fieldConfs, plan.FieldConfiguration{ | ||
TypeName: genArgs.TypeName, | ||
FieldName: genArgs.FieldName, | ||
Arguments: createArgumentConfigurationsForArgumentNames(genArgs.ArgumentNames...), | ||
}) | ||
} | ||
} | ||
|
||
func (u *UniversalDataGraph) determineChildNodes(planDataSources []plan.DataSourceConfiguration) error { | ||
for i := range planDataSources { | ||
if _, ok := planDataSources[i].Factory.(*restDataSource.Factory); ok { | ||
continue | ||
} | ||
for j := range planDataSources[i].RootNodes { | ||
typeName := planDataSources[i].RootNodes[j].TypeName | ||
for k := range planDataSources[i].RootNodes[j].FieldNames { | ||
fieldName := planDataSources[i].RootNodes[j].FieldNames[k] | ||
typeFields := u.Schema.GetAllNestedFieldChildrenFromTypeField(typeName, fieldName, graphql.NewIsDataSourceConfigV2RootFieldSkipFunc(planDataSources)) | ||
|
||
children := make([]plan.TypeField, 0) | ||
for _, tf := range typeFields { | ||
childNode := plan.TypeField{ | ||
TypeName: tf.TypeName, | ||
FieldNames: tf.FieldNames, | ||
} | ||
children = append(children, childNode) | ||
} | ||
planDataSources[i].ChildNodes = append(planDataSources[i].ChildNodes, children...) | ||
} | ||
} | ||
} | ||
return nil | ||
} |