readQuery from cache results in Can't find field <field> on object undefined - react-apollo

I'm getting started with graphQL and apollo. I'm doing some simple queries and mutations fine but when I try to access data from apollo cache I keep getting "Can't find field me on object undefined" but when using apollo chrome plugin it returns data correct.
When logged into my app I run a simple query that fetches the user object from the server. It logs correct, I can see in chome dev apollo under queries and cache that my user data is there.
const ME_QUERY = gql`
query {
me {
_id
username
password
exchanges {
name
active
}
}
}
`;
<Query query={ME_QUERY}>
{({loading, error, data}) => {
if (error) {
return <Error error={error.message} />;
}
if (data) {
console.log(data, 'data');
}
return <div>asdf</div>
}}
</Query>
I have wrapped withApollo and I can log the client object fine in the component where I'm trying to query. I run the following code:
componentDidMount() {
console.log(this.props.client.readQuery, 'propps');
const user = this.props.client.readQuery({
query: gql`
{
me {
_id
username
password
exchanges {
name
active
}
}
}
`
});
console.log(user, 'user');
And that results in Uncaught Error: Can't find field me on object undefined Ive also tried with adding variables but it doesn't help.
Which object is undefined? Any idea why my query fails?

You are probably using Apollo Client > 2.5 which handles state locally.
Read the migration guide for more information.
Use the default client resolver to resolve your local state
Use cache.write to write default data into your cache. This is the part of the migration that causes your crash.

Related

Apollo GraphQL: Delay Query Refetch

Senario:
Table of users populated from graphQL query that runs an AWS OpenSearch (e.g. ElasticSearch) on the server.
After successfully adding a user using (using a graphQL mutation), want to refetch the user table.
The issue is OpenSearch queries are batched by the server. This means there is a delay between when the database is updated and when the update results are available to openSearch.
Question: Is there a way to delay the refetch on a query (not the mutation).
Hacky fix (it works, but hate it) in calling component:
const { users, usersLoading, refetch } = useGetUsers() // graphQL query
const onAddUserSuccess = () => {
// executed after the user successfully added
timeOut(() => { refetch() }, [1000])
}
Also, tried in the api queries and mutations (didn't work because of the server batching delay):
// fetch Query (would like to dealy the refetch or check if data has updated before refetching)
const { refetch, loading, error, data } useQuery(
query,
{ variables: ... },
fetchPolcy:
'network-only',
options: { awaitRefetchQueries: true }
)`
// Add User mutation
const refetchUsers = gql`...query`
const [addUser, { loading, error, data }] = useMutation(
mutation,
{
refetchQueries: () => {
return [
{
query: refetchUsers,
variables: {
...
}
}
];
}
}
);

Cannot query field \"xxx\" on type \"Query\".",

I have a GraphQL server built with apollo-server and i am getting this error. The query works correctly on apollo graphql studio, but I get the error when I try fetching the data in my React application.
const GET_VEHICLE_MAKES = gql`
query {
vehicleMakes {
id
make
}
}
`;
const { loading, error, data } = useQuery(GET_VEHICLE_MAKES);

How to find out which mutation is being requested when configuring “Context”(Node.js, Apollo Server)

I would like to add conditional function on context depending on which mutation is being called in Node.js, Apollo Server.
How would I do that efficiently?
When configuring context, I have access to the request body and all the graphql request information is stored at “req.body.query”, which also contains what I need.
To make use of this, I would have to parse with the “parse” function from “graphql” module. But I dont think this is efficient, cuz now the same request is basically getting parsed twice(once by me and once by Apollo Server). Also the parsed result is not very user friendly with all the nested values.
Is there a clean way to know what mutation is being requested?
One common solution to this is the use of operation names. The client can provide an operation name to the server in the request to identify what it is doing.
{
"query": "{ mutation AddToBasket($myVariable: AddToBasketInput!) { addToBasket(input: $myVariable) { id } } }",
"operationName": "AddToBasket",
"variables": { "myVariable": "someValue" }
}
I think you can access the operation name from the body like this:
const server = new ApolloServer({
context: ({ req }) => {
if (req.body.operationName === 'AddToBasket') {
console.log("Found it!")
}
}
})
You can also create a plugin for Apollo Server that uses the didResolveOperation event to get the operation name value.
export class MyPlugin implements ApolloServerPlugin {
async requestDidStart() {
return {
async didResolveOperation(
requestContext
) {
console.log(requestContext.operationName);
},
}
}
}
Using operation name avoids a need to parse the GraphQL operation to determine which mutation is included in the request, but also requires the client to provide a known operation name value, which may or may not work for your use case.

With GraphQL Apollo Client, How To set #client fields to store in Cache object?

I have an Apollo Query set as I have below.
query {
speakers {
id
name
checkBoxField #client
}
}
I have a field policy set as follows:
export const genericBoolean = cache.makeVar(false);
typePolicies: {
Speaker: {
fields: {
checkBoxField: {
read(checkBoxField = false) {
return genericBoolean === true ? "true" : "false";
...
I have a button on my page where I use useQuery defined and that button executes the code:
onClick : genericBoolean(true)
When I dump (JSON.stringify) the data returned from useQuery, the checkBoxField does change to true for all rows as expected, but in my Apollo Cache (as seen from chrome extension), there is no field stored for checkBoxField. I want that there so I can iterate through my cache and get the set valued for each row.
According to the Apollo docs, you can use reactive variables OR the Apollo client cache to store local state: https://www.apollographql.com/docs/react/local-state/managing-state-with-field-policies/#storing
Your example above is using reactive variables. To store your data in the cache you would need to use writeQuery or writeFragment: https://www.apollographql.com/docs/react/local-state/managing-state-with-field-policies/#storing-local-state-in-the-cache

How to update apollo cache after mutation (query with filter)

I am pretty new to GraphQL. I am using graph.cool in a Vue.js project with apollo.
I am using right now the in-memory cache.
I had previously a simple 'allPosts' query.
And after creating a new one, I used the update() hook and readQuery() + writeQuery()
However I want that logged in users can only see their posts. So I modified the query with a filter.
query userStreams ($ownerId: ID!) {
allStreams(filter: {
owner: {
id: $ownerId
}
}) {
id
name
url
progress
duration
watched
owner {
id
}
}
}
My thought was, that I only need to pass in the userid variable. However this is not working. I am always getting
Error: Can't find field allStreams({"filter":{"owner":{}}}) on object (ROOT_QUERY) undefined.
this.$apollo.mutate({
mutation: CREATE_STREAM,
variables: {
name,
url,
ownerId
},
update: (store, { data: { createStream } }) => {
const data = store.readQuery({
query: USERSTREAMS,
variables: {
id: ownerId
}
})
data.allStreams.push(createStream)
store.writeQuery({
query: USER_STREAMS,
variables: {
id: ownerId
},
data
})
}
})
When you use readQuery or writeQuery, you should use the same variable name. So replace
variables: { id: ownerId }
With
variables: { ownerId }
Also, the reason you are getting an exception is that readQuery throws an exception if the data is not in the store. That happens before the first time you use writeQuery (or get the data with some other query).
You could write some default values to the store before calling this mutation.
You could also use readFragment that returns null instead of throwing an exception. But that would require more changes to your code.

Resources