Mutations which don't satisfy watched queries cause queries to return no data and no error
See original GitHub issueIntended outcome:
A mutation which adds data to the store which is insufficient to satisfy an existing query should either return partial data or produce an error. Currently, this snippet exists in readFromStore.js:readStoreResolver
:
if (typeof fieldValue === 'undefined') {
if (!context.returnPartialData) {
throw new Error("Can't find field " + storeKeyName + " on object (" + objId + ") " + JSON.stringify(obj, null, 2) + ".");
}
context.hasMissingField = true;
return fieldValue;
}
Actual outcome:
The above code throws, but is silently caught in QueryManager:getCurrentQueryResult
:
try {
var data = this.dataStore.getCache().read({
query: query,
variables: variables,
previousResult: lastResult ? lastResult.data : undefined,
optimistic: true,
});
return maybeDeepFreeze({ data: data, partial: false });
}
catch (e) {
return maybeDeepFreeze({ data: {}, partial: true });
}
This results in a render which has no usable query data, nor any error.
How to reproduce the issue:
Say you have a classic todo app. A query may contain an array node of actual todos, and renders correctly:
gql`
query Todos {
todos {
id
text
details
}
}
`;
You then have a mutation to create a todo which only returns the id
and text
, as we know the details
haven’t been filled in yet and we don’t wish to overfetch (or possibly, we just forgot to include the field):
gql`
mutation addTodo($text: String!) {
todo {
id
text
}
}
`;
The original query can no longer be satisfied with what is in the store after this mutation, because a new item has been added which does not include all queried fields. The result is that no query data is returned (ie data.todos
is undefined). Additionally, data.error
is undefined, and nothing has been reported to the console.
In the real world, we add new products for an order to an array, but the schema has a number of fields which we do not wish to pull back in the mutation result, because we know they will always be null
for newly added products. We would prefer to have the flexibility to have these default to null
or undefined
and let the components dictate behavior there (if we force renderPartialData
to true
inside the memory cache this works, but that option has been deprecated as a thing we can pass in from our app), but at a minimum, we should be provided with some sort of error so we know why it won’t work. The thrown error is actually rather helpful, but never makes it to the developer.
Version
- apollo-client@2.2.0
Issue Analytics
- State:
- Created 6 years ago
- Reactions:9
- Comments:5 (1 by maintainers)
Top GitHub Comments
This behaviour caused by https://github.com/apollographql/apollo-client/blob/31b0ee4a027c60394cf9297df8f9eeeda3918272/packages/apollo-client/src/core/QueryManager.ts#L994.
I believe error should not be caught. It should be either reported to console or returned to caller as
data: { error }
.I’m having hard time debugging it and finding out which field is missing every time
This has been addressed by https://github.com/apollographql/apollo-client/pull/4743, and will be coming in Apollo Client 2.6. You can set
returnPartialData
totrue
to have previous partial cache results used, instead of having the returned data set to an empty object.