If you have this schema:
type Query {
user: User!
}
type User {
house: House!
}
type House {
id: String!
}
and do this client call:
client.user() - what should happen?
Right now an error is thrown, that the query contains an empty selection set.
This is the case, because we only expand on scalar fields for now.
However, with types like the User type as in our example, that don't have scalar fields, this approach breaks.
An opinionated, non-trivial solution is needed here.
Here are possible solutions for the problem:
Let's discuss in this issue, which behavior makes more sense and potentially other solutions.
One thing is clear: We at least need better error handling for this case.
My suggestion: always query __typename automatically for every selection set. This way, there is no error thrown. Don't query any relations automatically.
If the user wants to query a relation, they should be able to easily do so however. I think this would be client.user().house().
Just a side not: Currently, this behaviour breaks xsConnection queries.
If you run
ctx.prisma.usersConnection()
this error is thrown
Field 'usersConnection' of type 'UserConnection' must have a sub selection.
I like @marktani's suggestion to query for __typename. I'm currently leaning towards only querying it if no other scalar fields are available. Are there any reasons why it should be queried in all cases?
Note that this is both important for Connection types and Subscription types.
My suggestion: always query
__typenameautomatically for every selection set. This way, there is no error thrown. Don't query any relations automatically.If the user wants to query a relation, they should be able to easily do so however. I think this would be
client.user().house().
Could you please provide an example?
Until this issue is resolved, you can try connection queries like :-
async productsConnection(parent, args, ctx: Context, info) {
//getUserId(ctx);
const query = `
query($orderBy: ProductOrderByInput, $where: ProductWhereInput) {
productsConnection(orderBy: $orderBy, where: $where) {
__typename
pageInfo {
hasNextPage
hasPreviousPage
}
edges {
node {
id
name
price
pictureUrl
seller {
id
}
}
cursor
}
}
}
`;
const variables = { ...args};
const { productsConnection } = await ctx.prisma.$graphql(query, variables);
return productsConnection;
},
In the above code I made a request to prisma's endpoint from my server.
We just discussed the concrete implementation and it should look like this:
Only for types that don't have scalar fields, we'll add the __typename in the query.
The actual return type won't change - it's an empty object.
This PR https://github.com/prisma/prisma/pull/3892 implements it for top level types. Resulting in the following behavior:
prisma.users() yields the following query now
query ($where: UserWhereInput) {
users(where: $where) {
__typename
}
}
However, as a result of this opinionated API https://github.com/prisma/prisma/issues/3629 the generated connection API for a type with no scalars breaks currently, generating the following query:-
{
usersConnection {
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
edges {
node
cursor
}
}
}
This fails at node selection with: UnhandledPromiseRejectionWarning: Error: Field 'node' of type 'User' must have a sub selection.
This needs further spec of the behavior when we encounter a connection operation from client for a type without scalars. Following solutions (not exhaustive) are possible:-
Cons:
Different types for relay connection API for types that have scalars vs types that have no scalars.
This will be a breaking change in terms of types.
Resulting query:
{
usersConnection {
__typename
}
}
__typenameCons:
__typename from the result. node (as done in the opinionated API ) or handle it via a generic solution i.e. expand every type without scalars ?Resulting query:
{
usersConnection {
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
edges {
node {
__typename
}
cursor
}
}
}
Most helpful comment
Could you please provide an example?