Repository: graph-gophers/graphql-go (Go)

Issue:
Remove _service from the introspection and it should be opt-in
Currently the `_service` field is added as an introspection field for every user of the library. This works fine, however, it is used by a small subset of users of this library who use Apollo Federation.
The issue will be considered done, when the `_service` field is deleted.
An example of apollo-federation-compatible subgraph will be added which shows how to add this yourself if you need it.


Discussion:

Patch:
diff --git a/example/social/introspect.json b/example/social/introspect.json
index e474d7941..cfd9911f6 100644
--- a/example/social/introspect.json
+++ b/example/social/introspect.json
@@ -613,33 +613,6 @@
         "name": "User",
         "possibleTypes": null
       },
-      {
-        "description": null,
-        "enumValues": null,
-        "fields": [
-          {
-            "args": [],
-            "deprecationReason": null,
-            "description": null,
-            "isDeprecated": false,
-            "name": "sdl",
-            "type": {
-              "kind": "NON_NULL",
-              "name": null,
-              "ofType": {
-                "kind": "SCALAR",
-                "name": "String",
-                "ofType": null
-              }
-            }
-          }
-        ],
-        "inputFields": null,
-        "interfaces": [],
-        "kind": "OBJECT",
-        "name": "_Service",
-        "possibleTypes": null
-      },
       {
         "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior\nin ways field arguments will not suffice, such as conditionally including or\nskipping a field. Directives provide this by describing additional information\nto the executor.",
         "enumValues": null,
diff --git a/example/starwars/introspect.json b/example/starwars/introspect.json
index 009799ffe..6eb3b79c8 100644
--- a/example/starwars/introspect.json
+++ b/example/starwars/introspect.json
@@ -1255,33 +1255,6 @@
         "name": "String",
         "possibleTypes": null
       },
-      {
-        "description": null,
-        "enumValues": null,
-        "fields": [
-          {
-            "args": [],
-            "deprecationReason": null,
-            "description": null,
-            "isDeprecated": false,
-            "name": "sdl",
-            "type": {
-              "kind": "NON_NULL",
-              "name": null,
-              "ofType": {
-                "kind": "SCALAR",
-                "name": "String",
-                "ofType": null
-              }
-            }
-          }
-        ],
-        "inputFields": null,
-        "interfaces": [],
-        "kind": "OBJECT",
-        "name": "_Service",
-        "possibleTypes": null
-      },
       {
         "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior\nin ways field arguments will not suffice, such as conditionally including or\nskipping a field. Directives provide this by describing additional information\nto the executor.",
         "enumValues": null,
diff --git a/internal/exec/resolvable/meta.go b/internal/exec/resolvable/meta.go
index 972f322b0..31eb9f863 100644
--- a/internal/exec/resolvable/meta.go
+++ b/internal/exec/resolvable/meta.go
@@ -34,12 +34,6 @@ func newMeta(s *ast.Schema) *Meta {
 		panic(err)
 	}
 
-	metaService := s.Types["_Service"].(*ast.ObjectTypeDefinition)
-	sv, err := b.makeObjectExec(metaService.Name, metaService.Fields, nil, nil, false, reflect.TypeOf(&introspection.Service{}))
-	if err != nil {
-		panic(err)
-	}
-
 	if err := b.finish(); err != nil {
 		panic(err)
 	}
@@ -68,21 +62,11 @@ func newMeta(s *ast.Schema) *Meta {
 		TraceLabel: "GraphQL field: __type",
 	}
 
-	fieldService := Field{
-		FieldDefinition: ast.FieldDefinition{
-			Name: "_service",
-			Type: s.Types["_Service"],
-		},
-		TraceLabel: "GraphQL field: _service",
-	}
-
 	return &Meta{
 		FieldSchema:   fieldSchema,
 		FieldTypename: fieldTypename,
 		FieldType:     fieldType,
-		FieldService:  fieldService,
 		Schema:        so,
 		Type:          t,
-		Service:       sv,
 	}
 }
diff --git a/internal/exec/selected/selected.go b/internal/exec/selected/selected.go
index 22dc6f28d..5b64f0b11 100644
--- a/internal/exec/selected/selected.go
+++ b/internal/exec/selected/selected.go
@@ -133,17 +133,6 @@ func applySelectionSet(r *Request, s *resolvable.Schema, e *resolvable.Object, s
 					})
 				}
 
-			case "_service":
-				if r.AllowIntrospection {
-					flattenedSels = append(flattenedSels, &SchemaField{
-						Field:       s.Meta.FieldService,
-						Alias:       field.Alias.Name,
-						Sels:        applySelectionSet(r, s, s.Meta.Service, field.SelectionSet),
-						Async:       true,
-						FixedResult: reflect.ValueOf(introspection.WrapService(r.Schema)),
-					})
-				}
-
 			default:
 				fe := e.Fields[field.Name.Name]
 
diff --git a/internal/schema/meta.go b/internal/schema/meta.go
index cb27202e4..70cd7134b 100644
--- a/internal/schema/meta.go
+++ b/internal/schema/meta.go
@@ -206,8 +206,4 @@ var metaSrc = `
 		# Indicates this type is a non-null. ` + "`" + `ofType` + "`" + ` is a valid field.
 		NON_NULL
 	}
-
-	type _Service {
-		sdl: String!
-	}
 `
diff --git a/internal/validation/validation.go b/internal/validation/validation.go
index 083499ae0..4cdf274e5 100644
--- a/internal/validation/validation.go
+++ b/internal/validation/validation.go
@@ -327,11 +327,6 @@ func validateSelection(c *opContext, sel ast.Selection, t ast.NamedType) {
 				},
 				Type: c.schema.Types["__Type"],
 			}
-		case "_service":
-			f = &ast.FieldDefinition{
-				Name: "_service",
-				Type: c.schema.Types["_Service"],
-			}
 		default:
 			f = fields(t).Get(fieldName)
 			if f == nil && t != nil {
diff --git a/introspection/introspection.go b/introspection/introspection.go
index 89e14f9ed..de01a7aff 100644
--- a/introspection/introspection.go
+++ b/introspection/introspection.go
@@ -324,16 +324,3 @@ func (r *Directive) Args() []*InputValue {
 	}
 	return l
 }
-
-type Service struct {
-	schema *ast.Schema
-}
-
-// WrapService is only used internally.
-func WrapService(schema *ast.Schema) *Service {
-	return &Service{schema}
-}
-
-func (r *Service) SDL() string {
-	return r.schema.SchemaString
-}


Test patch:
diff --git a/graphql_test.go b/graphql_test.go
index 0ffbeef8a..5be998193 100644
--- a/graphql_test.go
+++ b/graphql_test.go
@@ -2918,7 +2918,6 @@ func TestIntrospection(t *testing.T) {
 							{ "name": "SearchResult" },
 							{ "name": "Starship" },
 							{ "name": "String" },
-							{ "name": "_Service" },
 							{ "name": "__Directive" },
 							{ "name": "__DirectiveLocation" },
 							{ "name": "__EnumValue" },
@@ -5254,39 +5253,6 @@ func TestMaxQueryLength(t *testing.T) {
 	})
 }
 
-func TestQueryService(t *testing.T) {
-	t.Parallel()
-
-	schemaString := `
-	schema {
-		query: Query
-	}
-
-	type Query {
-		hello: String!
-	}`
-
-	gqltesting.RunTests(t, []*gqltesting.Test{
-		{
-			Schema: graphql.MustParseSchema(schemaString, &helloWorldResolver1{}),
-			Query: `
-				{
-					_service{
-						sdl
-					}
-				}
-			`,
-			ExpectedResult: `
-				{
-					"_service": {
-						"sdl": "\n\tschema {\n\t\tquery: Query\n\t}\n\n\ttype Query {\n\t\thello: String!\n\t}"
-					}
-				}
-			`,
-		},
-	})
-}
-
 type RootResolver struct{}
 type QueryResolver struct{}
 type MutationResolver struct{}