diff --git a/apps/api/src/controllers/posts.ts b/apps/api/src/controllers/posts.ts new file mode 100644 index 00000000..1c728490 --- /dev/null +++ b/apps/api/src/controllers/posts.ts @@ -0,0 +1,111 @@ +import Post from '../models/post'; +import Comment from '../models/comment'; + +// GET /posts Return an array of all the posts with status code 200 +const getPosts = async (req, res, next) => { + try { + const posts = await Post.find(); + res.status(200).json(posts); + } catch (error) { + //handling error middleware - errorHandler + next(error); + } +}; + +// POST /posts Create a new post and return the created post with status code 201 +const createPosts = async (req, res, next) => { + // Retrieve the values from the request body + try { + const post = await Post.create(req.body); + res.status(201).json(post); + } catch (error) { + next(error); + } +}; + +// GET /posts/:id Return a post by id with category object and each comment object in the array with status code 200 +const getPostById = async (req, res, next) => { + const { id } = req.params; + try { + const post = await Post.findById(id).populate('comments').populate('category'); + + return res.status(200).json(post); + } catch (error) { + //handling error middleware - errorHandler + next(error); + } +}; + +//GET /posts/category/:category Return an array of all the posts by category with status code 200 +const getPostsByCategory = async (req, res, next) => { + const { category } = req.params; + try { + const posts = (await Post.findOne({ category })) ?? []; + + res.status(200).json(posts); + } catch (error) { + //handling error middleware - errorHandler + next(error); + } +}; + +// POST /posts/:id/comments Create a comment inside the post and return the comment with status code 201 +const createPostComment = async (req, res, next) => { + const { id } = req.params; + try { + const comments = await Comment.create({ + author: req.body.author, + content: req.body.content + }); + + //populate function on getPostById need the reference id from the comments + const posts = await Post.findById(id); + await Post.findByIdAndUpdate(id, { comments: [...posts.comments, comments._id] }); + + // Return all the posts with that category with a 200 status code + res.status(201).json(comments); + } catch (error) { + //handling error middleware - errorHandler + next(error); + } +}; + +//PATCH /posts/:id Update post information and return the updated post with status code 200 +const updatePost = async (req, res, next) => { + // Retrieve the id from the route params + const { id } = req.params; + try { + const post = await Post.findByIdAndUpdate(id, req.body, { new: true }); + res.status(200).json(post); + } catch (error) { + //handling error middleware - errorHandler + next(error); + } +}; + +// DELETE /posts/:id Delete the post and return the deleted post with status code 200 or 204 +const deletePost = async (req, res, next) => { + // Retrieve the id from the route params + const { id } = req.params; + try { + //Remove post comments from database when you delete the post + const posts = await Post.findById(id); + await Comment.deleteMany({ _id: { $in: posts.comments } }); + //Remove post + const post = await Post.findByIdAndDelete(id); + res.status(204).json(post); + } catch (error) { + //handling error middleware - errorHandler + next(error); + } +}; + +export default { + getPosts, + createPosts, + getPostById, + getPostsByCategory, + createPostComment, + updatePost, + deletePost +}; diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index daf9dc2e..96888e1e 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -8,6 +8,7 @@ import { verifyToken } from './middleware/auth'; import { errorHandler } from './middleware/errorHandler'; import auth from './routes/auth'; import categories from './routes/categories'; +import posts from './routes/posts'; const host = process.env.HOST ?? 'localhost'; const port = process.env.PORT ? Number(process.env.PORT) : 3000; @@ -22,6 +23,7 @@ app.use('/api/auth', auth); app.use(verifyToken); app.use('/api/categories', categories); +app.use('/api/posts', posts); app.use(errorHandler); diff --git a/apps/api/src/models/comment.ts b/apps/api/src/models/comment.ts new file mode 100644 index 00000000..5bb38b13 --- /dev/null +++ b/apps/api/src/models/comment.ts @@ -0,0 +1,30 @@ +import mongoose, { Document, Schema } from 'mongoose'; + +interface IComment extends Document { + author: string; + content: string; + // postId: mongoose.Schema.Types.ObjectId; +} + +export const commentSchema = new Schema( + { + author: { + type: String, + required: [true, 'Property is required'] + }, + content: { + type: String, + required: [true, 'Property is required'] + } + // postId: { + // type: mongoose.Schema.Types.ObjectId, + // ref: 'Post' + // } + }, + { + timestamps: true + } +); + +const Comment = mongoose.model('Comment', commentSchema); +export default Comment; diff --git a/apps/api/src/models/post.ts b/apps/api/src/models/post.ts new file mode 100644 index 00000000..61bec323 --- /dev/null +++ b/apps/api/src/models/post.ts @@ -0,0 +1,39 @@ +import mongoose, { Document, Schema } from 'mongoose'; + +interface IPost extends Document { + title: string; + image: string; + description: string; + category: mongoose.Schema.Types.ObjectId; + comments: [{ type: Schema.Types.ObjectId }]; +} + +export const postSchema = new Schema( + { + title: { + type: String, + required: [true, 'Property is required'] + }, + image: { + type: String, + required: [true, 'Property is required'] + }, + description: { + type: String, + required: [true, 'Property is required'] + }, + category: { + type: mongoose.Schema.Types.ObjectId, + required: [true, 'Property is required'], + ref: 'Category' + }, + comments: [{ type: Schema.Types.ObjectId, ref: 'Comment' }] + }, + { + timestamps: true + } +); + +const Post = mongoose.model('Post', postSchema); + +export default Post; diff --git a/apps/api/src/routes/posts.ts b/apps/api/src/routes/posts.ts new file mode 100644 index 00000000..ecaf597b --- /dev/null +++ b/apps/api/src/routes/posts.ts @@ -0,0 +1,28 @@ +import express from 'express'; + +import postController from '../controllers/posts'; + +const router = express.Router(); + +// GET /posts Return an array of all the posts with status code 200 +router.get('/', postController.getPosts); + +// POST /posts Create a new post and return the created post with status code 201 +router.post('/', postController.createPosts); + +// GET /posts/:id Return a post by id with category object and each comment object in the array with status code 200 +router.get('/:id', postController.getPostById); + +//GET /posts/category/:category Return an array of all the posts by category with status code 200 +router.get('/category/:category', postController.getPostsByCategory); + +// POST /posts/:id/comments Create a comment inside the post and return the comment with status code 201 +router.post('/:id/:comments', postController.createPostComment); + +//PATCH /posts/:id Update post information and return the updated post with status code 200 +router.patch('/:id', postController.updatePost); + +// DELETE /posts/:id Delete the post and return the deleted post with status code 200 or 204 +router.delete('/:id', postController.deletePost); + +export default router;