Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error: "cannot query field "id" on type "UnionType" #128

Open
prokaktus opened this issue Mar 7, 2021 · 3 comments
Open

Error: "cannot query field "id" on type "UnionType" #128

prokaktus opened this issue Mar 7, 2021 · 3 comments
Labels
bug Something isn't working

Comments

@prokaktus
Copy link
Contributor

prokaktus commented Mar 7, 2021

Hello!

I've met the error when using inline fragments.

Description

Schema:

type Cat {
	id: ID!
	name: String!
}

type Dog {
	id: ID!
	name: String!
}

union Animal = Cat | Dog

type Query {
	animals: [Animal!]!
}

Query:

query MyQuery {
	animals {
		... on Cat {
			id
			name
		}
		... on Dog {
			id
			name
		}
	}
}

If Dog and Cat are defined in the same location, it works well.

But if you define Dog and Cat in different locations, then first query in plans generate:

(query generated by Gateway)

{
  animals {
    ... on Cat {
      id
      name
    }
    id
  }
}

Which is invalid, because we cannot query fields on Union, except __typename. Graphql spec told so:

the following query is invalid, because the union itself defines no fields:

{
  firstSearchResult {
    name
    height
  }
}

https://spec.graphql.org/June2018/#sec-Unions

Possible workaround

Use defined fragments.

Query like this will work:

query MyQuery {
	animals {
		... on Cat {
			...CatFragment
		}
		... on Dog {
			...DogFragment
		}
	}
}

fragment CatFragment on Cat {
	id,
	name
}
fragment DogFragment on Dog {
	id,
	name
}

I'll try to provide testcase and fix for this issue.

@prokaktus
Copy link
Contributor Author

The same problem happens with query, if Dog and Cat from different locations:

query {
	animals {
		...CatFragment
		...DogFragment
	}
}

fragment CatFragment on Cat {
	id
	name
}
fragment DogFragment on Dog {
	id
	name
}

@prokaktus
Copy link
Contributor Author

Turned out this is a lot trickier to fix than I expected.

Problem is somewhere there:

gateway/plan.go

Lines 389 to 392 in 1078926

if checkForID {
// add the id field since duplicates are ignored
locationFields[config.parentLocation] = append(locationFields[config.parentLocation], &ast.Field{Name: "id"})
}

When gateway handling unions fragments, there added id field to unions SelectionSet, and this is invalid syntax for graphql.

@AlecAivazis
Copy link
Member

Oh, damn yea this is going to bring you very deep into the weeds of the query planning process. It sounds like you are on the right track tho! Since its safe to assume that every boundary type has ID, you should be able to just ensure that ID shows up the different conditions for the union and instead of adding it straight to the selection set.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants