Repository: jensneuse/graphql-go-tools (go)

Issue:
Is it not possible to query __typename field
We could not query `__typename` field in case it is not specified in schema for each type
query:
```graphql
query getApi($id: String!) {
  api(id: $id) {
      __typename
    ... on Api {
      __typename
      id
      name
    }

    ... on RequestResult {
      __typename
      status
      message
    }  
  }
}

```

graphql server returns an error:
```
[Jan 21 17:29:58] ERROR executionHandler.Handle error=external: field: __typename not defined on type: Query, locations: [], path: [query]
[Jan 21 17:30:12] ERROR executionHandler.Handle error=external: field: __typename not defined on type: Api, locations: [], path: [query,api]
[Jan 21 17:30:18] ERROR executionHandler.Handle error=external: field: __typename not defined on type: ApiResult, locations: [], path: [query,api]
```

Pull request:
Bugfix/validation fails for typename field
Added skipping __typename field validation as there are no definitions for this field.
Closes #173 

Patch:
diff --git a/pkg/asttransform/baseschema.go b/pkg/asttransform/baseschema.go
index f6ab27d2..d18a98f0 100644
--- a/pkg/asttransform/baseschema.go
+++ b/pkg/asttransform/baseschema.go
@@ -15,11 +15,7 @@ func MergeDefinitionWithBaseSchema(definition *ast.Document) error {
 	if report.HasErrors() {
 		return report
 	}
-	err := handleSchema(definition)
-	if err != nil {
-		return err
-	}
-	return nil
+	return handleSchema(definition)
 }
 
 func handleSchema(definition *ast.Document) error {
diff --git a/pkg/astvalidation/astvalidation.go b/pkg/astvalidation/astvalidation.go
index 187472ff..2ea4dd08 100644
--- a/pkg/astvalidation/astvalidation.go
+++ b/pkg/astvalidation/astvalidation.go
@@ -199,6 +199,9 @@ func (f *fieldDefined) ValidateUnionField(ref int, enclosingTypeDefinition ast.N
 
 func (f *fieldDefined) ValidateInterfaceObjectTypeField(ref int, enclosingTypeDefinition ast.Node) {
 	fieldName := f.operation.FieldNameBytes(ref)
+	if bytes.Equal(fieldName,literal.TYPENAME){
+		return
+	}
 	typeName := f.definition.NodeNameBytes(enclosingTypeDefinition)
 	hasSelections := f.operation.FieldHasSelections(ref)
 	definitions := f.definition.NodeFieldDefinitions(enclosingTypeDefinition)
@@ -322,8 +325,10 @@ func (f *fieldSelectionMergingVisitor) EnterOperationDefinition(ref int) {
 }
 
 func (f *fieldSelectionMergingVisitor) EnterField(ref int) {
-
 	fieldName := f.operation.FieldNameBytes(ref)
+	if bytes.Equal(fieldName,literal.TYPENAME){
+		return
+	}
 	objectName := f.operation.FieldObjectNameBytes(ref)
 	definition, ok := f.definition.NodeFieldDefinitionByName(f.EnclosingTypeDefinition, fieldName)
 	if !ok {


Test patch:
diff --git a/pkg/astvalidation/astvalidation_test.go b/pkg/astvalidation/astvalidation_test.go
index e3684bbc..46bc9c34 100644
--- a/pkg/astvalidation/astvalidation_test.go
+++ b/pkg/astvalidation/astvalidation_test.go
@@ -2,6 +2,7 @@ package astvalidation
 
 import (
 	"fmt"
+	"github.com/jensneuse/graphql-go-tools/internal/pkg/unsafeparser"
 	"github.com/jensneuse/graphql-go-tools/pkg/ast"
 	"github.com/jensneuse/graphql-go-tools/pkg/astnormalization"
 	"github.com/jensneuse/graphql-go-tools/pkg/astparser"
@@ -3523,6 +3524,51 @@ func TestExecutionValidation(t *testing.T) {
 	})
 }
 
+func TestValidationWithTypeName(t *testing.T){
+	operation := `
+		query getApi($id: String!) {
+		  api(id: $id) {
+			__typename
+			... on Api {
+			  __typename
+			  id
+			  name
+			}
+			... on RequestResult {
+			  __typename
+			  status
+			  message
+			}  
+		  }
+		}`
+	definition := `
+		schema {
+			query: Query
+		}
+		type Query {
+			api(id: String): ApiResult
+		}
+		union ApiResult = Api | RequestResult
+		type Api {
+			id: String
+			name: String
+		}
+		type RequestResult {
+			status: String
+			message: String
+		}
+		scalar String
+	`
+	op := unsafeparser.ParseGraphqlDocumentString(operation)
+	def := unsafeparser.ParseGraphqlDocumentString(definition)
+	validator := DefaultOperationValidator()
+	var report operationreport.Report
+	validator.Validate(&op,&def,&report)
+	if report.HasErrors() {
+		t.Fatal(report.Error())
+	}
+}
+
 func BenchmarkValidation(b *testing.B) {
 
 	must := func(err error) {
diff --git a/pkg/astvisitor/visitor_test.go b/pkg/astvisitor/visitor_test.go
index af49a60f..5043f763 100644
--- a/pkg/astvisitor/visitor_test.go
+++ b/pkg/astvisitor/visitor_test.go
@@ -52,6 +52,52 @@ func TestVisitOperation(t *testing.T) {
 	}
 }
 
+func TestVisitWithTypeName(t *testing.T){
+	operation := `
+		query getApi($id: String!) {
+		  api(id: $id) {
+			__typename
+			... on Api {
+			  __typename
+			  id
+			  name
+			}
+			... on RequestResult {
+			  __typename
+			  status
+			  message
+			}  
+		  }
+		}`
+	definition := `
+		schema {
+			query: Query
+		}
+		type Query {
+			api(id: String): ApiResult
+		}
+		union ApiResult = Api | RequestResult
+		type Api {
+			id: String
+			name: String
+		}
+		type RequestResult {
+			status: String
+			message: String
+		}
+		scalar String
+	`
+
+	walker := NewWalker(8)
+	op := unsafeparser.ParseGraphqlDocumentString(operation)
+	def := unsafeparser.ParseGraphqlDocumentString(definition)
+	var report operationreport.Report
+	walker.Walk(&op,&def,&report)
+	if report.HasErrors() {
+		t.Fatal(report.Error())
+	}
+}
+
 func TestVisitSchemaDefinition(t *testing.T) {
 
 	operation := unsafeparser.ParseGraphqlDocumentString(testDefinitions)