I am trying to make a Social app using MongoDB, Express, React, Node, Graphql with Apollo , I am following a video from freecodecamp : Link to the video
I am using pubsub to achieve a realtime functionality, like when ever a new post has been added it should show up in the home page.
I might have missed the code of some file that's why I am dropping a link to my github repo containing the whole project : Link to the github repo
Home.js:
import React, { useContext } from 'react';
import { useQuery } from '@apollo/react-hooks';
import { Grid, Transition } from 'semantic-ui-react';
import { AuthContext } from '../context/auth';
import PostCard from '../components/PostCard';
import PostForm from '../components/PostForm';
import { FETCH_POSTS_QUERY } from '../util/graphql';
function Home() {
const { user } = useContext(AuthContext);
const { data, loading, error } = useQuery(FETCH_POSTS_QUERY);
if(data) {
const { posts } = data || [];
return (
<Grid columns={3}>
<Grid.Row className="page-title">
<h1>Recent Posts</h1>
</Grid.Row>
<Grid.Row>
{user && (
<Grid.Column>
<PostForm />
</Grid.Column>
)}
{loading && <h1>Loading posts..</h1>}
{data && (
<Transition.Group>
{posts &&
posts.map((post) => (
<Grid.Column key={post.id} style={{ marginBottom: 20 }}>
<PostCard post={post} />
</Grid.Column>
))}
</Transition.Group>
)}
</Grid.Row>
</Grid>
);
}
if(error) {
return error.message;
}
}
export default Home;
I render all the posts in Home.js
Resolvers => posts.js :
const { AuthenticationError, UserInputError } = require('apollo-server');
const Post = require('../../models/Post');
const checkAuth = require('../../util/check-auth');
module.exports = {
Query: {
async getPosts() {
try {
const posts = await Post.find().sort({ createdAt: -1 });
return posts;
} catch (err) {
throw new Error(err);
}
},
async getPost(_, { postId }) {
try {
const post = await Post.findById(postId);
if (post) {
return post;
} else {
throw new Error('Post not found');
}
} catch (err) {
throw new Error(err);
}
}
},
Mutation: {
async createPost(_, { body }, context) {
const user = checkAuth(context);
if (body.trim() === '') {
throw new Error('Post body must not be empty');
}
const newPost = new Post({
body,
user: user.id,
username: user.username,
createdAt: new Date().toISOString()
});
const post = await newPost.save();
context.pubsub.publish('NEW_POST', {
newPost: post,
}).then(()=>{
console.log("working")
});
return post;
},
async deletePost(_, { postId }, context) {
const user = checkAuth(context);
try {
const post = await Post.findById(postId);
if (user.username === post.username) {
await post.delete();
return 'Post deleted successfully';
} else {
throw new AuthenticationError('Action not allowed');
}
} catch (err) {
throw new Error(err);
}
},
async likePost(_, { postId }, context) {
const { username } = checkAuth(context);
const post = await Post.findById(postId);
if (post) {
if (post.likes.find((like) => like.username === username)) {
// Post already likes, unlike it
post.likes = post.likes.filter((like) => like.username !== username);
} else {
// Not liked, like post
post.likes.push({
username,
createdAt: new Date().toISOString()
});
}
await post.save();
return post;
} else throw new UserInputError('Post not found');
}
},
Subscription: {
newPost: {
subscribe: (_, __, { pubsub }) => pubsub.asyncIterator('NEW_POST')
}
}
};
Resolvers => index.js :
const postsResolvers = require('./posts');
const usersResolvers = require('./users');
const commentsResolvers = require('./comments');
module.exports = {
Post: {
likeCount: (parent) => parent.likes.length,
commentCount: (parent) => parent.comments.length
},
Query: {
...postsResolvers.Query
},
Mutation: {
...usersResolvers.Mutation,
...postsResolvers.Mutation,
...commentsResolvers.Mutation
},
Subscription: {
...postsResolvers.Subscription
}
};
tyDefs.js :
const { gql } = require('apollo-server');
module.exports = gql`
type Post {
id: ID!
body: String!
createdAt: String!
username: String!
comments: [Comment]!
likes: [Like]!
likeCount: Int!
commentCount: Int!
}
type Comment {
id: ID!
createdAt: String!
username: String!
body: String!
}
type Like {
id: ID!
createdAt: String!
username: String!
}
type User {
id: ID!
email: String!
token: String!
username: String!
createdAt: String!
}
input RegisterInput {
username: String!
password: String!
confirmPassword: String!
email: String!
}
type Query {
getPosts: [Post]
getPost(postId: ID!): Post
}
type Mutation {
register(registerInput: RegisterInput): User!
login(username: String!, password: String!): User!
createPost(body: String!): Post!
deletePost(postId: ID!): String!
createComment(postId: String!, body: String!): Post!
deleteComment(postId: ID!, commentId: ID!): Post!
likePost(postId: ID!): Post!
}
type Subscription {
newPost(
id: ID!,
body: String!,
createdAt: String!,
username: String!,
likeCount: Int!,
commentCount: Int!): Post!
}
`;
This is the index.js file of my server (backend) :
const { ApolloServer, PubSub } = require('apollo-server');
const mongoose = require('mongoose');
const typeDefs = require('./graphql/typeDefs');
const resolvers = require('./graphql/resolvers');
const { MONGODB } = require('./config.js');
const pubsub = new PubSub();
const PORT = process.env.port || 5000;
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => ({ req, pubsub })
});
mongoose
.connect(MONGODB, { useUnifiedTopology: true , useNewUrlParser: true })
.then(() => {
console.log('MongoDB Connected');
return server.listen({ port: PORT });
})
.then((res) => {
console.log(`Server running at ${res.url}`);
})
.catch(err => {
console.error(err)
})
I am intialising the pubsub in the index.js file only, This is the error I am getting :
TypeError: data.getPosts is not iterable 0.chunk.js:124321
This error is one problem the other is that whenever I click submit the same error occurs, but the post appears when I run the subscription in Graphql Playground not in the client page but when I refresh the page the post appears there.
