Skip to content
Merged
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
2 changes: 1 addition & 1 deletion router-tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ require (
github.com/wundergraph/cosmo/router v0.0.0-20260330183556-dc4388d100a4
github.com/wundergraph/cosmo/router-plugin v0.0.0-20250808194725-de123ba1c65e
github.com/wundergraph/cosmo/speedtrap v0.0.0-00010101000000-000000000000
github.com/wundergraph/graphql-go-tools/v2 v2.4.6
github.com/wundergraph/graphql-go-tools/v2 v2.5.0
go.opentelemetry.io/otel v1.44.0
go.opentelemetry.io/otel/sdk v1.44.0
go.opentelemetry.io/otel/sdk/metric v1.44.0
Expand Down
4 changes: 2 additions & 2 deletions router-tests/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,8 @@ github.com/wundergraph/astjson v1.1.0 h1:xORDosrZ87zQFJwNGe/HIHXqzpdHOFmqWgykCLV
github.com/wundergraph/astjson v1.1.0/go.mod h1:h12D/dxxnedtLzsKyBLK7/Oe4TAoGpRVC9nDpDrZSWw=
github.com/wundergraph/go-arena v1.3.0 h1:n0ng5a1vbd8YGq1u3rMr0vPU5f6AZ1BXIiUhL1UIok8=
github.com/wundergraph/go-arena v1.3.0/go.mod h1:ROOysEHWJjLQ8FSfNxZCziagb7Qw2nXY3/vgKRh7eWw=
github.com/wundergraph/graphql-go-tools/v2 v2.4.6 h1:MqUDusuiOGlO0Oa8etTdcVA2ySmY0XehTDq/dILelEw=
github.com/wundergraph/graphql-go-tools/v2 v2.4.6/go.mod h1:rGG9m74sUyucfvSZ83Mjuq/6qRJetl1CVP872f/dCok=
github.com/wundergraph/graphql-go-tools/v2 v2.5.0 h1:Id21OFacHv9gaictZR+dPDYWNFF0WQXbAIE4Y81Vujo=
github.com/wundergraph/graphql-go-tools/v2 v2.5.0/go.mod h1:rGG9m74sUyucfvSZ83Mjuq/6qRJetl1CVP872f/dCok=
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg=
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
Expand Down
39 changes: 35 additions & 4 deletions router-tests/security/costs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,10 @@ func TestOperationCost(t *testing.T) {
require.Contains(t, res.Body, `"data":`)
require.NotContains(t, res.Body, `"errors":`)

// 50 * (employees(1) + id(0) + 1 * (role(1) + 3 * departments(1) + 5 * title(1)))
require.Equal(t, "500", res.Response.Header.Get(core.CostEstimatedHeader))
// 10 * (employees(1) + id(0) + 1 * (role(1) + 1.2 * departments(1) + 1.4 * title(1)))
require.Equal(t, "46", res.Response.Header.Get(core.CostActualHeader))
// 50 * (employees(1) + id(0) + 1 * (role(1) + 3 * departments(1) + 5 * title(0)))
require.Equal(t, "250", res.Response.Header.Get(core.CostEstimatedHeader))
// 10 * (employees(1) + id(0) + 1 * (role(1) + 1.2 * departments(1) + 1.4 * title(0)))
require.Equal(t, "32", res.Response.Header.Get(core.CostActualHeader))
})
})

Expand Down Expand Up @@ -384,6 +384,37 @@ func TestOperationCost(t *testing.T) {
})
})

t.Run("ignore_implementing_type_weights excludes implementing-type weights on abstract fields", func(t *testing.T) {
t.Parallel()
// The RoleType interface field "employees" has no weight of its own.
// With the flag on, that implementing-type weight is skipped (Apollo behavior).
testenv.Run(t, &testenv.Config{
ModifySecurityConfiguration: func(securityConfiguration *config.SecurityConfiguration) {
securityConfiguration.CostControl = &config.CostControl{
Enabled: true,
Mode: config.CostControlModeMeasure,
MaxEstimatedLimit: 10000,
EstimatedListSize: 10,
ExposeHeaders: true,
IgnoreImplementingTypeWeights: true,
}
},
}, func(t *testing.T, xEnv *testenv.Environment) {
res := xEnv.MakeGraphQLRequestOK(testenv.GraphQLRequest{
Query: `{ employee(id:1) { role { employees { id } } } }`,
})
require.Contains(t, res.Body, `"data":`)
require.NotContains(t, res.Body, `"errors":`)

// "@expensiveOp(coefficient: Int = 2 @cost(weight: 22))" should not be used!

// employee.arg(2) + 1 * (employee(5) + 1 * (role(1) + 10 * employees(1)))
require.Equal(t, "18", res.Response.Header.Get(core.CostEstimatedHeader))
// employee.arg(2) + 1 * (employee(5) + 1 * (role(1) + 7 * employees(1)))
require.Equal(t, "15", res.Response.Header.Get(core.CostActualHeader))
})
})

t.Run("slicingArguments controls list size estimation", func(t *testing.T) {
t.Parallel()
testenv.Run(t, &testenv.Config{
Expand Down
1 change: 1 addition & 0 deletions router/core/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ func (b *ExecutorConfigurationBuilder) buildPlannerConfiguration(ctx context.Con
if routerEngineCfg.CostControl != nil && routerEngineCfg.CostControl.Enabled {
planConfig.ComputeCosts = true
planConfig.StaticCostDefaultListSize = routerEngineCfg.CostControl.EstimatedListSize
planConfig.IgnoreImplementingTypeWeights = routerEngineCfg.CostControl.IgnoreImplementingTypeWeights
}

return planConfig, providers, nil
Expand Down
2 changes: 1 addition & 1 deletion router/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ require (
github.com/tidwall/gjson v1.18.0
github.com/tidwall/sjson v1.2.5
github.com/twmb/franz-go v1.16.1
github.com/wundergraph/graphql-go-tools/v2 v2.4.6
github.com/wundergraph/graphql-go-tools/v2 v2.5.0
// Do not upgrade, it renames attributes we rely on
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0
go.opentelemetry.io/contrib/propagators/b3 v1.44.0
Expand Down
4 changes: 2 additions & 2 deletions router/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,8 @@ github.com/wundergraph/astjson v1.1.0 h1:xORDosrZ87zQFJwNGe/HIHXqzpdHOFmqWgykCLV
github.com/wundergraph/astjson v1.1.0/go.mod h1:h12D/dxxnedtLzsKyBLK7/Oe4TAoGpRVC9nDpDrZSWw=
github.com/wundergraph/go-arena v1.3.0 h1:n0ng5a1vbd8YGq1u3rMr0vPU5f6AZ1BXIiUhL1UIok8=
github.com/wundergraph/go-arena v1.3.0/go.mod h1:ROOysEHWJjLQ8FSfNxZCziagb7Qw2nXY3/vgKRh7eWw=
github.com/wundergraph/graphql-go-tools/v2 v2.4.6 h1:MqUDusuiOGlO0Oa8etTdcVA2ySmY0XehTDq/dILelEw=
github.com/wundergraph/graphql-go-tools/v2 v2.4.6/go.mod h1:rGG9m74sUyucfvSZ83Mjuq/6qRJetl1CVP872f/dCok=
github.com/wundergraph/graphql-go-tools/v2 v2.5.0 h1:Id21OFacHv9gaictZR+dPDYWNFF0WQXbAIE4Y81Vujo=
github.com/wundergraph/graphql-go-tools/v2 v2.5.0/go.mod h1:rGG9m74sUyucfvSZ83Mjuq/6qRJetl1CVP872f/dCok=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
Expand Down
5 changes: 5 additions & 0 deletions router/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,11 @@ type CostControl struct {

// ExposeHeaders adds X-WG-Cost-* response headers.
ExposeHeaders bool `yaml:"expose_headers,omitempty" envDefault:"false" env:"EXPOSE_HEADERS"`

// IgnoreImplementingTypeWeights, when true, ignores @cost weights contributed by
// implementing types on abstract (interface/union) fields that have no weight of
// their own. Emulates Apollo's cost behavior.
IgnoreImplementingTypeWeights bool `yaml:"ignore_implementing_type_weights,omitempty" envDefault:"false" env:"IGNORE_IMPLEMENTING_TYPE_WEIGHTS"`
}

type ComplexityLimit struct {
Expand Down
5 changes: 5 additions & 0 deletions router/pkg/config/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3531,6 +3531,11 @@
"expose_headers": {
"type": "boolean",
"description": "Enable costs response headers for estimated and actuals operation costs."
},
"ignore_implementing_type_weights": {
"type": "boolean",
"default": false,
"description": "When enabled, ignores @cost weights from implementing types on abstract (interface/union) fields that have no weight of their own. Emulates Apollo's cost behavior."
}
}
},
Expand Down
3 changes: 2 additions & 1 deletion router/pkg/config/testdata/config_full.json
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,8 @@
"Mode": "enforce",
"MaxEstimatedLimit": 1000,
"EstimatedListSize": 10,
"ExposeHeaders": false
"ExposeHeaders": false,
"IgnoreImplementingTypeWeights": false
},
"DepthLimit": null,
"ParserLimits": {
Expand Down
Loading