Skip to content
Draft
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
62 changes: 62 additions & 0 deletions execution/engine/federation_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,68 @@ func TestFederationIntegrationTest(t *testing.T) {
expected := `{"data":{"cat":{"name":"Pepper"},"me":{"id":"1234","username":"Me","realName":"User Usington","reviews":[{"body":"A highly effective form of birth control."},{"body":"Fedoras are one of the most fashionable hats around and can look great with a variety of outfits."}],"history":[{},{"rating":5},{}]}}}`
assert.Equal(t, compact(expected), string(resp))
})

// Regression test for https://github.com/wundergraph/cosmo/issues/991
t.Run("introspection ofType returns fields", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
resp := gqlClient.Query(ctx, setup.GatewayServer.URL, testQueryPath("queries/introspection_oftype_fields.query"), nil, t)
expected := `{"data":{"__type":{"name":"User","kind":"OBJECT","fields":[{"name":"id","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","fields":null}}},{"name":"username","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","fields":null}}},{"name":"history","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"fields":null}}},{"name":"realName","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","fields":null}}},{"name":"reviews","type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Review","fields":[{"name":"body"},{"name":"author"},{"name":"product"},{"name":"attachments"},{"name":"comment"}]}}}]}}}`
assert.Equal(t, compact(expected), string(resp))
})

// Complex nested introspection proving enrichment works end-to-end:
// - Aliases (review:, attachment:)
// - Deep ofType nesting: ofType.fields.type.ofType with full type resolution
// - Union possibleTypes with fields (Attachment → Question, Rating, Video)
// - Cycle prevention: User.reviews and Product.reviews both reference Review,
// which is already being serialized → "fields": null proves truncation
t.Run("introspection nested enriched types", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
resp := gqlClient.Query(ctx, setup.GatewayServer.URL, testQueryPath("queries/introspection_nested_enriched.query"), nil, t)
expected := `{"data":{
"review":{
"kind":"OBJECT","name":"Review",
"fields":[
{"name":"body","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","fields":null,"possibleTypes":[]}}},
{"name":"author","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"User",
"fields":[
{"name":"id","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","fields":null}}},
{"name":"username","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","fields":null}}},
{"name":"history","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"fields":null}}},
{"name":"realName","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","fields":null}}},
{"name":"reviews","type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Review","fields":null}}}
],
"possibleTypes":[]
}}},
{"name":"product","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"Product",
"fields":[
{"name":"upc","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","fields":null}}},
{"name":"name","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","fields":null}}},
{"name":"price","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","fields":null}}},
{"name":"inStock","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","fields":null}}},
{"name":"reviews","type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Review","fields":null}}}
],
"possibleTypes":[]
}}},
{"name":"attachments","type":{"kind":"LIST","name":null,"ofType":{"kind":"UNION","name":"Attachment","fields":null,"possibleTypes":[{"kind":"OBJECT","name":"Question"},{"kind":"OBJECT","name":"Rating"},{"kind":"OBJECT","name":"Video"}]}}},
{"name":"comment","type":{"kind":"INTERFACE","name":"Comment","ofType":null}}
]
},
"attachment":{
"kind":"UNION","name":"Attachment",
"possibleTypes":[
{"kind":"OBJECT","name":"Question","fields":[{"name":"upc"},{"name":"body"},{"name":"subject"}]},
{"kind":"OBJECT","name":"Rating","fields":[{"name":"upc"},{"name":"body"},{"name":"score"}]},
{"kind":"OBJECT","name":"Video","fields":[{"name":"upc"},{"name":"size"},{"name":"subject"}]}
]
}
}}`
assert.Equal(t, compact(expected), string(resp))
})
}

func compact(input string) string {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
review: __type(name: "Review") {
kind
name
fields {
name
type {
kind
name
ofType {
kind
name
fields {
name
type {
kind
name
ofType {
kind
name
fields {
name
}
}
}
}
possibleTypes {
kind
name
}
}
}
}
}
attachment: __type(name: "Attachment") {
kind
name
possibleTypes {
kind
name
fields {
name
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
__type(name: "User") {
name
kind
fields {
name
type {
kind
name
ofType {
kind
name
fields {
name
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ func NewIntrospectionConfigFactory(schema *ast.Document) (*IntrospectionConfigFa
return nil, report
}

if err := data.Schema.BuildJSON(); err != nil {
return nil, err
}

return &IntrospectionConfigFactory{introspectionData: &data}, nil
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"kind": "INPUT_OBJECT",
"name": "ConfigInput",
"description": "",
"inputFields": [
{
"name": "key",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null,
"__typename": "__Type",
"description": "The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.",
"inputFields": [],
"interfaces": [],
"possibleTypes": []
},
"__typename": "__Type"
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null,
"__typename": "__InputValue"
},
{
"name": "nested",
"description": "",
"type": {
"kind": "INPUT_OBJECT",
"name": "NestedInput",
"ofType": null,
"__typename": "__Type",
"description": "",
"inputFields": [
{
"name": "value",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null,
"__typename": "__Type",
"description": "The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",
"inputFields": [],
"interfaces": [],
"possibleTypes": []
},
"__typename": "__Type"
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null,
"__typename": "__InputValue"
}
],
"interfaces": [],
"possibleTypes": []
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null,
"__typename": "__InputValue"
}
],
"interfaces": [],
"possibleTypes": [],
"__typename": "__Type"
}
Loading