Apollo Client updateQuery Missing field [fieldName] in {} - reactjs

On a specific Query subscribeToMore function I can't seem to get the Query to take the new data.
updateQuery: async (prev, { subscriptionData } ) => {
const posts = [
...prev.getPosts,
subscriptionData.data.postCreated
];
const result = {
...prev,
count: posts.length,
getPosts: posts
}
return result;
}
This results in the following error:
Missing field getPosts in {}
If I log the result I get:
Object { getPosts: (3) […], count: 3 }
I'm not sure what is causing this as it seems fine on several other updateQuery calls. This one in particular seems to break.
The queries in question:
export const POST_CREATED = gql`
subscription postCreated($authorId: ID!){
postCreated(authorId: $authorId){
id, title, createdAt, published
}
} `;
export const GET_POSTS = gql`
query getPosts($authorId: ID!){
getPosts(authorId: $authorId){
id, title, createdAt, published
}
} `;

Got the same kind of Problem.
I fixed it because the return Object was wrong.
Since you´re only adding the post to the end this should work:
updateQuery: async (prev, { subscriptionData } ) => {
prev.getPosts.push(subscriptionData.data.postCreated)
return prev;
}

Related

Using apollo subscribeToMore with different results for subscription

GET_USERS returns users: []string
export const GET_USERS= gql`
query AllUsers{
users
}
`;
GET_USERS_SUBSCRIPTION returns user: string
export const GET_USERS_SUBSCRIPTION= gql`
subscription AllUsersUpdater{
user
}
`;
It seems like apollo expects the subscribeToMore to be of the exact same result type. I know I can update the result to also be []string, but that seems so unnecessary for what I want to do.
const { subscribeToMore } = useAllUsersQuery({});
useEffect(() => {
subscribeToMore({
document: GET_USERS_SUBSCRIPTION,
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) {
return prev;
}
const user= subscriptionData.data.user;
if (prev.users.find((u) => u === user)) {
return prev;
}
return Object.assign({}, prev, {
users: [user, ...prev.users],
});
},
});
}, []);
Is there any way to use subscribeToMore with a different subscription type?
Also, is subscribeToMore the best way to handle this? Could I just bundle the two and just have the subscription return past results prior to returning new ones?
The subscribeToMore as defined here https://github.com/apollographql/apollo-client/blob/a3aefcb310ea1451ee494077cbde98171169d8d0/src/core/ObservableQuery.ts#L502-L505 used the TSubscriptionData = TData type parameter to set the expected type which defaults to TData.
You need to specify the parameter to override the default.
In your specific example this would look something like this
const { subscribeToMore } = useAllUsersQuery({});
useEffect(() => {
subscribeToMore<{user: string}>({
document: GET_USERS_SUBSCRIPTION,
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) {
return prev;
}
const user= subscriptionData.data.user;
if (prev.users.find((u) => u === user)) {
return prev;
}
return Object.assign({}, prev, {
users: [user, ...prev.users],
});
},
});
}, []);

How to pass Unique Id in Graphql query

I'm trying to pass a unique id to a GraphQL query to get all data against the id. But when I print the console it shows undefined. Note that if I want to see all posts the then it becomes successful by another query.
in my query.js file I have written the below query:
export const Unique_Post_Query= gql`
query SampleQueries($id: ID!) {
post(_id: $id) {
id
data {
title
body {
text
}
}
}
}`;
and the below code from another file where I'm trying to see the result of the query:
const id='e42fd2b5-b84a-4417-afd2-36cdbaa204dd';
const { data , error,loading} = useQuery(Unique_Post_Query, { variables: {id ,}, });
//const { error, loading, data } = useQuery(PROFILE_QUERY);
console.log('yourrrrr f data',data);
Please check below reference
const id='e42fd2b5-b84a-4417-afd2-36cdbaa204dd';
const { loading, data } = useQuery(Unique_Post_Query, {
variables: { id: id},
});
useEffect(() => {
if (data && data?.post) {
console.log("data: ", data?.post);
}
}, [data]);

Query data doesn't update after successful apollo cache write

I have a query on my App.js:
import { gql } from 'apollo-boost';
const ALL_ITEMS_QUERY = gql`
query ALL_ITEMS_QUERY {
challenges {
id
title
}
goals {
id
title
completed
createdAt
updatedAt
steps {
id
completed
title
}
}
}
`;
And i am looking to write a simple deleteGoal mutation:
const DeleteWrapper = (props) => {
const [deleteGoal, { data }] = useMutation(DELETE_ITEM_MUTATION, {
update(cache, payload) {
const data = cache.readQuery({ query: ALL_ITEMS_QUERY });
data.goals = data.goals.filter(
(goal) => goal.id !== payload.data.deleteGoal.id
);
cache.writeQuery({ query: ALL_ITEMS_QUERY, data });
},
});
}
The function returns the modified array correctly, but the item never disappears from the frontend list. I have a hunch that this is related to querying multiple categories at once (goals and challenges, rather than goals only).
Even though the cache seems to be modified correclty, why does the item never disappear, why does the re-render never happen?
After some trial and error I found out that I have to lay out the exact data object to the writeQuery function. I don't really understand why, since the challenges object was left untouched after the query. I have not been able to make this work otherwise.
const DeleteWrapper = (props) => {
const [deleteGoal] = useMutation(DELETE_ITEM_MUTATION, {
update(cache, { data: { deleteGoal} }) {
const { goals, challenges } = cache.readQuery({ query: ALL_ITEMS_QUERY });
const newArr = goals.filter((goal) => goal.id !== deleteGoal.id);
cache.writeQuery({
query: ALL_ITEMS_QUERY,
data: { challenges, goals: newArr },
});
},
});
}

Apollo GraphQL - Associated types not included on Subscription response

Let's say I have a Post and Comment model. A Post hasMany Comments. In React Apollo I'm using subscribeToMore on a Query for a particular post.
The query appears as follows:
query getPost(id: ID!){
id, title, comments { id }
}
And the subscription which returns the post with any new comments:
subscription commentAdded(postId: ID!){
id, title, comments { id }
}
The query works. It returns all of the associated Comments, which I can then render as in list on the page.
Yet when using the subscribeToMore helper for the query, I get the follow error whenever the event subscription is dispatched.
Cannot read property 'Comment' of undefined.
The strange thing is that if I remove the Comment, such that the subscription looks like...
subscription commentAdded(postId: ID!){
id, title
}
...it works perfectly. I'm confused why it seems to treat the Comments as associating with an undefined model.
This isn't just a Comments -> Posts issue, this happens on any model that tries to return a subscription with an association.
post query:
post: async (parent, {id}, {models}) => {
return await models.Post.findByPk(id);
}
saveComment resolver:
saveComment: async (parent, {postId, comment}, {models, me}) => {
let post = await models.Post.findByPk(postId);
let comment = await models.Comment.create({comment, postId});
await pubsub.publish("COMMENT_CREATED", {
commentCreated: post,
postId
})
}
commentCreated subscription:
commentCreated: {
subscribe: withFilter(
() => pubsub.asyncIterator(["COMMENT_CREATED"]),
(payload, variables) => {
return payload.postId == variables.postId
}
)
}
Post type resolver
Post: {
comments: async (post, args, {models}) => {
return await models.Comment.findAll({where:{postId: post.id}});
}
}
Server initialization:
const server = new ApolloServer({
typeDefs: schema,
resolvers,
subscriptions: {
onConnect: (connectionParams, webSocket) => {
return true
},
},
context: async ({ req, connection }) => {
if(connection){
return connection.context;
}else{
const me = await getMe(req);
return {
models,
me,
secret: process.env.SECRET,
};
}
}
});
Your context function only returns connection.context, which will not include any of the custom properties you want to include (me, models, etc.). Doing something like this should fix the problem:
context: async ({ req, connection }) => {
const context = {
models,
secret: process.env.SECRET,
};
if(connection){
return { ...connection.context, ...context };
} else {
const me = await getMe(req);
return { ...context, me };
}
}

Why are Results logging as undefined after a GraphQL Mutation?

In one of my components within a redux-form onSubmit, I have the following:
const result = await helloSignup(values);
console.log(result);
helloSignup is mutating the database as expected but the const result is currently be logged as undefined
Why?
My HOC/mutation helloSignup:
export const HELLO_SIGNUP_MUTATION = gql`
mutation (
$email: String!
$code: String!
) {
signup(authProvider: {
emailAndCode: {
email: $email
code: $code
}
}) {
token
user {
id
}
}
}
`;
export default graphql(
HELLO_SIGNUP_MUTATION,
{
props: ({ mutate }) => ({
emailAndCodeSignup: async (variables) => {
const { data } = await mutate({ variables });
const { token } = data.signup;
},
}),
}
);
Using GraphiQL, I can see that my graphql mutation, returns the desired results:
{
"data": {
"signup": {
"token": "xxx",
"user": {
"id": "16"
}
}
}
}
If GraphiQL is getting the desired results after mutating, why isn't the result being console logged above?
React-Apollo provides a HOC for client side queries and mutations called withApollo.
This signature is something like this:
withApollo(MyForm)
https://www.apollographql.com/docs/react/basics/setup.html#withApollo
which adds a prop of 'client' to the MyForm component. On form submission, you'd want to access this prop, and call the mutation from there. So in your form submit handler youd end up with something like this:
https://www.apollographql.com/docs/react/basics/mutations.html#basics
onSubmit() {
const { client } = this.props
const options = {} // your mutation options
// mutations ands queries return promises,
// so you must wait for their completion before accessing data
client.mutate(
HELLO_SIGNUP_MUTATION,
options
).then(({ data }) => (
console.log('got data', data);
)
}
}
Where data should be whats coming back from the API

Resources