In the GraphQL specification 2.8.1 is stated that fragments can be specified on objects, interface and unions.
Unfortunately, Dgraph do not resolve fragments for interfaces, leading to errors in the query result
interface Meta {
id: String! @id @search(by: [hash])
}
interface Generic {
names: [String!]!
}
type Movie implements Meta & Generic {
description: String!
}
query {
getMeta(id:"1") {
id
... on Generic {
__typename
names {
text
}
}
}
}
Turned out that the query do not return an error on standalone/latest, where the fragment simply do not resolve anything.
In dgraph:v20.07.2 it returns the above error.
"message": "Cannot return null for non-nullable field Movie.names."
After further tests I figured out the actual behavior:
The fragment on interface do not resolve in dgraph, returning a null field. Putting an apollo server in front of dgraph and mirroring the schema, it expect the names to not be null (type definition) but because behind dgraph do not resolve the fragment and returns null, the apollo server triggers the error above described.
Hi @Luscha, I am not getting the above error while applying fragment on interface. I have used same schema, queries and mutations which you mentioned and tried on both v20.07.2 and master branch.
Response of query which uses fragment on interface:
@JatinDevDG
The error is triggered when putting an apollo server in front of dgraph because the schema tells apollo that querying on the fragment should return names and description.
The query with the fragment on interface should resolve in the same way of the type which implements the interface (according to the GraphQL specification).
I guess interfaces are useful because you want to query things without listing all the implementing types
EG:
I have an ecommerce with a lot of “products” interface with name, image and description implemented by cloth (with size), ebook (format available), PC (with specifications) and printed book (ISBN13-10 …).
Right now to get a search result you have to query
query {
getProduct(first:10) {
... on Cloth {
name
image
description
}
... on Ebook {
name
image
description
}
.....
}
}
which simply nullyfy the benefit of having an interface
Based on your last response it’s still not clear what the problem is @Luscha. What is the GraphQL query that is failing for you? What’s the expected response for it and what are you actually getting?
You don’t have to list all the types that implement the interface. You only have to list them if you want to get a field that is not part of the interface. So the query below should also work for you, as long as the name, description, and image are fields in the interface definition.
query {
getProduct(first:10) {
name
image
description
}
}
Hi @Luscha, we find out the query below should work when getMeta returns an object of a type that implements both Meta and Generic. Otherwise, it should return an error.We are not getting this behaviour right now. So, we are accepting this bug and will have a fix soon. Thanks.
query {
getMeta(id:"1") {
id
... on Generic {
__typename
names {
text
}
}
}
}
@pawan
Sorry, I got confused as well trying to explain the problem:
Conditions:
Type A implements interface B and C
Action:
query {
getB {
... on C {
some C Fields
}
}
}
Expected behavior:
The fragment on C should resolve for A because it implements the 2 interfaces
Actual Behaviour:
The fragment do not resolve and some C Fields is not returned for object A.
This behavior is worsened if an apollo server is used as gateway, because it expects the fields to be returned (schema definition) and triggers an error to the client, failing the query