From 06751a60cce13951ac84421661f019f7975211a7 Mon Sep 17 00:00:00 2001 From: Jennifer Nevarez Date: Tue, 21 May 2024 12:25:13 -0700 Subject: [PATCH 1/7] feat(api): Add security middlewares --- apps/api/.env | 3 ++- apps/api/src/config/corsConfig.ts | 10 ++++++++++ apps/api/src/main.ts | 8 ++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 apps/api/src/config/corsConfig.ts diff --git a/apps/api/.env b/apps/api/.env index ecaf5a7c..af8edb18 100644 --- a/apps/api/.env +++ b/apps/api/.env @@ -1,3 +1,4 @@ +TRUSTED_ORIGINS=[] ACCESS_TOKEN_SECRET=[YOUR_ACCESS_TOKEN_SECRET_HERE] REFRESH_TOKEN_SECRET=[YOUR_REFRESH_TOKEN_SECRET_HERE] -MONGO_URL=[YOUR_MONGO_CONNECTION_STRING_HERE] \ No newline at end of file +MONGO_URL=[YOUR_MONGO_CONNECTION_STRING_HERE] diff --git a/apps/api/src/config/corsConfig.ts b/apps/api/src/config/corsConfig.ts new file mode 100644 index 00000000..bd927b58 --- /dev/null +++ b/apps/api/src/config/corsConfig.ts @@ -0,0 +1,10 @@ +export const corsOptions = { + origin: (origin, callback) => { + if (!process.env.TRUSTED_ORIGINS.includes(origin) || origin.includes("localhost")) { + callback(new Error("Not Allowed By Cors")) + } + + callback(null, true) + }, + OptionsSuccessStatus: 200 +} diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index e5fad103..086ee7a1 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -1,10 +1,18 @@ import express from 'express'; +import helmet from 'helmet'; +import cors from 'cors'; + +import { corsOptions } from './config/corsConfig'; const host = process.env.HOST ?? 'localhost'; const port = process.env.PORT ? Number(process.env.PORT) : 3000; const app = express(); +app.use(express.json()) +app.use(helmet()) +app.use(cors(corsOptions)) + app.get('/', (req, res) => { res.send({ message: 'Hello MFEE!' }); }); From 910941de7824ca64c9d0108f086f020743d8f1fd Mon Sep 17 00:00:00 2001 From: Jennifer Nevarez Date: Tue, 21 May 2024 13:48:21 -0700 Subject: [PATCH 2/7] fix(api): Invalidate Cors on Dev --- apps/api/.env | 1 + apps/api/src/config/corsConfig.ts | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/api/.env b/apps/api/.env index af8edb18..0f84af61 100644 --- a/apps/api/.env +++ b/apps/api/.env @@ -1,3 +1,4 @@ +ENV=dev TRUSTED_ORIGINS=[] ACCESS_TOKEN_SECRET=[YOUR_ACCESS_TOKEN_SECRET_HERE] REFRESH_TOKEN_SECRET=[YOUR_REFRESH_TOKEN_SECRET_HERE] diff --git a/apps/api/src/config/corsConfig.ts b/apps/api/src/config/corsConfig.ts index bd927b58..b1398ed9 100644 --- a/apps/api/src/config/corsConfig.ts +++ b/apps/api/src/config/corsConfig.ts @@ -1,10 +1,10 @@ export const corsOptions = { origin: (origin, callback) => { - if (!process.env.TRUSTED_ORIGINS.includes(origin) || origin.includes("localhost")) { - callback(new Error("Not Allowed By Cors")) + if (process.env.ENV === "dev" || process.env.TRUSTED_ORIGINS.includes(origin)) { + callback(null, true) } - callback(null, true) + callback(new Error("Not Allowed By Cors")) }, OptionsSuccessStatus: 200 } From ada843defbe7f527b32fffa04c919db1cb37fb8f Mon Sep 17 00:00:00 2001 From: Jennifer Nevarez Date: Tue, 18 Jun 2024 12:31:21 -0700 Subject: [PATCH 3/7] fix(api): Remove Double Callback Execution --- apps/api/src/config/corsConfig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/src/config/corsConfig.ts b/apps/api/src/config/corsConfig.ts index b1398ed9..dd2e6594 100644 --- a/apps/api/src/config/corsConfig.ts +++ b/apps/api/src/config/corsConfig.ts @@ -1,7 +1,7 @@ export const corsOptions = { origin: (origin, callback) => { if (process.env.ENV === "dev" || process.env.TRUSTED_ORIGINS.includes(origin)) { - callback(null, true) + return callback(null, true) } callback(new Error("Not Allowed By Cors")) From 85dd943609b00e0599eecd5d153f06f568504fc2 Mon Sep 17 00:00:00 2001 From: Jennifer Nevarez Date: Wed, 19 Jun 2024 13:20:52 -0700 Subject: [PATCH 4/7] Revert "Merge remote-tracking branch 'origin/node/session-02' into node/jennifer.nevarez" This reverts commit 16b085aabf6687c3969aa23ad464479028548a8b, reversing changes made to ada843defbe7f527b32fffa04c919db1cb37fb8f. --- apps/api/README.md | 29 +------ apps/api/src/config/.gitkeep | 0 apps/api/src/config/corsConfig.ts | 20 ++--- apps/api/src/controllers/.gitkeep | 0 apps/api/src/controllers/category.ts | 110 --------------------------- apps/api/src/main.ts | 4 +- apps/api/src/routes/.gitkeep | 0 apps/api/src/routes/categories.ts | 22 ------ 8 files changed, 12 insertions(+), 173 deletions(-) create mode 100644 apps/api/src/config/.gitkeep create mode 100644 apps/api/src/controllers/.gitkeep delete mode 100644 apps/api/src/controllers/category.ts create mode 100644 apps/api/src/routes/.gitkeep delete mode 100644 apps/api/src/routes/categories.ts diff --git a/apps/api/README.md b/apps/api/README.md index f172a610..6066cc0e 100644 --- a/apps/api/README.md +++ b/apps/api/README.md @@ -21,34 +21,7 @@ ## Challenges -### Session 01 - -- Create `route` for `posts` endpoint with the following methods: - - `GET /posts` Return an array of all the posts with status code 200 - - `GET /posts/category/:category` Return an array of all the posts by category with status code 200 - - `GET /posts/:id` Return a post by id with category object and each comment object in the array with status code 200 - - `POST /posts` Create a new post and return the created post with status code 201 - - `POST /posts/:id/comments` Create a comment inside the post and return the comment with status code 201 - - `PATCH /posts/:id` Update post information and return the updated post with status code 200 - - `DELETE /posts/:id` Delete the post and return the deleted post with status code 200 or 204 if you decide to not return anything - * *Add 404 validation where needed* - -- Post model - - id: string - - title: string - - image: string - - description: string - - category: string *Id of the category* - - comments: array *Array of comment ids* - -- Comment model - - id: string - - author: string - - content: string - -### Session 02 - -- Refactor the code from last session to add a post controller +### Session * ## How to diff --git a/apps/api/src/config/.gitkeep b/apps/api/src/config/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apps/api/src/config/corsConfig.ts b/apps/api/src/config/corsConfig.ts index d8f9f72a..dd2e6594 100644 --- a/apps/api/src/config/corsConfig.ts +++ b/apps/api/src/config/corsConfig.ts @@ -1,10 +1,10 @@ -export const corsOptions = { - origin: (origin, callback) => { - if (process.env.ENV === "dev" || process.env.TRUSTED_ORIGINS.includes(origin)) { - return callback(null, true) - } - - callback(new Error("Not Allowed By Cors")) - }, - OptionsSuccessStatus: 200 -} +export const corsOptions = { + origin: (origin, callback) => { + if (process.env.ENV === "dev" || process.env.TRUSTED_ORIGINS.includes(origin)) { + return callback(null, true) + } + + callback(new Error("Not Allowed By Cors")) + }, + OptionsSuccessStatus: 200 +} diff --git a/apps/api/src/controllers/.gitkeep b/apps/api/src/controllers/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apps/api/src/controllers/category.ts b/apps/api/src/controllers/category.ts deleted file mode 100644 index 59294b96..00000000 --- a/apps/api/src/controllers/category.ts +++ /dev/null @@ -1,110 +0,0 @@ -// Initialize categories array to save data in memory -const categories = []; - -export const getCategory = (id: string) => { - return categories.find((p) => p.id === id); -}; - -// Get all categories -const getCategories = (req, res) => { - // Return all the categories with a 200 status code - res.status(200).json(categories); -}; - -// Get category by id -const getCategoryById = (req, res) => { - // Retrieve the id from the route params - const { id } = req.params; - // Check if we have a category with that id - const category = getCategory(id); - - if (!category) { - // If we don't find the category return a 404 status code with a message - return res.status(404).json({ message: 'Category not found' }); - // Note: Remember that json method doesn't interrupt the workflow - // therefore is important to add a "return" to break the process - } - - // Return the category with a 200 status code - res.status(200).json(category); -}; - -// Create category -const createCategory = (req, res) => { - // Retrieve the name from the request body - const { name } = req.body; - - if (!name) { - // If name is empty or undefined return a 400 status code with a message - return res.status(400).json({ message: 'The name is required.' }); - } - - // Generate a new category - const newCategory = { - id: Date.now().toString(), // Convert id to string to match the value in get by id endpoint - name - }; - // Add the new category to our array - categories.push(newCategory); - - // Return the created category with a 201 status code - res.status(201).json(newCategory); -}; - -// Update category -const updateCategory = (req, res) => { - // Retrieve the id from the route params - const { id } = req.params; - // Retrieve the index of the category in the array - const categoryIndex = categories.findIndex((p) => p.id === id); - - // "findIndex" will return -1 if there is no match - if (categoryIndex === -1) { - // If we don't find the category return a 404 status code with a message - return res.status(404).json({ message: 'Category not found' }); - } - - // Generate a copy of our cateogory - const updatedCategory = { ...categories[categoryIndex] }; - // Retrieve the name from the request body - const { name } = req.body; - - // Check if we have a name, if so update the property - if (name) { - updatedCategory.name = name; - } - - // Update the category in our array - categories[categoryIndex] = updatedCategory; - - // Return the updated category with a 200 status code - res.status(200).json(updatedCategory); -}; - -// Delete category -const deleteCategory = (req, res) => { - // Retrieve the id from the route params - const { id } = req.params; - // Retrieve the index of the category in the array - const categoryIndex = categories.findIndex((p) => p.id === id); - - // "findIndex" will return -1 if there is no match - if (categoryIndex === -1) { - // If we don't find the category return a 404 status code with a message - return res.status(404).json({ message: 'Category not found' }); - } - - // Remove the category from the array - categories.splice(categoryIndex, 1); - - // Return a 204 status code - res.status(204).send(); -}; - -export default { - getCategories, - getCategoryById, - createCategory, - updateCategory, - deleteCategory -}; diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 181c340b..086ee7a1 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -1,11 +1,9 @@ -import cors from 'cors'; import express from 'express'; import helmet from 'helmet'; +import cors from 'cors'; import { corsOptions } from './config/corsConfig'; -// import categories from './routes/categories'; - const host = process.env.HOST ?? 'localhost'; const port = process.env.PORT ? Number(process.env.PORT) : 3000; diff --git a/apps/api/src/routes/.gitkeep b/apps/api/src/routes/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/apps/api/src/routes/categories.ts b/apps/api/src/routes/categories.ts deleted file mode 100644 index 78e120a1..00000000 --- a/apps/api/src/routes/categories.ts +++ /dev/null @@ -1,22 +0,0 @@ -import express from 'express'; - -import categoryController from '../controllers/category'; - -const router = express.Router(); - -// Get all categories -router.get('/', categoryController.getCategories); - -// Get category by id -router.get('/:id', categoryController.getCategoryById); - -// Create category -router.post('/', categoryController.createCategory); - -// Update category -router.patch('/:id', categoryController.updateCategory); - -// Delete category -router.delete('/:id', categoryController.deleteCategory); - -export default router; From 85c4ab4d0c46785d21b5a3446cd0e725d6697a88 Mon Sep 17 00:00:00 2001 From: Jennifer Nevarez Date: Thu, 20 Jun 2024 09:47:56 -0700 Subject: [PATCH 5/7] feat(api): Add Catalog Route --- apps/api/src/main.ts | 3 ++ apps/api/src/routes/categories.ts | 59 +++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 apps/api/src/routes/categories.ts diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 086ee7a1..b9b006fb 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -3,6 +3,7 @@ import helmet from 'helmet'; import cors from 'cors'; import { corsOptions } from './config/corsConfig'; +import categories from './routes/categories'; const host = process.env.HOST ?? 'localhost'; const port = process.env.PORT ? Number(process.env.PORT) : 3000; @@ -13,6 +14,8 @@ app.use(express.json()) app.use(helmet()) app.use(cors(corsOptions)) +app.use('/api/categories', categories) + app.get('/', (req, res) => { res.send({ message: 'Hello MFEE!' }); }); diff --git a/apps/api/src/routes/categories.ts b/apps/api/src/routes/categories.ts new file mode 100644 index 00000000..e3d31c1d --- /dev/null +++ b/apps/api/src/routes/categories.ts @@ -0,0 +1,59 @@ +import express from 'express'; + +const router = express.Router(); +const categories = [] + +router.route('/:id') + .get((req, res) => { + const { id } = req.params; + const currentCategory = categories.find(el => el.id === id) + + if (!currentCategory) return res.status(404).json({message: "Category not found"}) + + res.status(200).json(currentCategory); + }) + .patch((req, res) => { + const { id } = req.params; + const categoryIndex = categories.findIndex(el => el.id === id) + if (categoryIndex < 0) return res.status(404).json({message: "Category not found"}) + + const { name } = req.body; + if (!name) return res.status(401).json({ message: "Name is required!" }) + + categories[categoryIndex].name = name; + + res.status(203).json(categories[categoryIndex]); + }) + .delete((req, res) => { + const { id } = req.params; + const categoryIndex = categories.findIndex(el => el.id === id) + if (categoryIndex < 0) return res.status(404).json({message: "Category not found"}) + + const currentCategory = categories[categoryIndex] + + categories.splice(categoryIndex, 1) + + res.status(200).json({status: "Item Deleted", item: currentCategory}); + }) + + +router.route('/') + .get((req, res) => { + res.status(200).json(categories); + }) + .post((req, res) => { + const { name } = req.body; + + if (!name) return res.status(401).json({ message: "Name is required!" }) + + const newCategory = { + id: Date.now().toString(), + name + } + + categories.push(newCategory) + + res.status(201).json(newCategory) + }) + +export default router From 67493680c2204728f73d528ca661ce1952f99a3a Mon Sep 17 00:00:00 2001 From: Jennifer Nevarez Date: Thu, 20 Jun 2024 13:09:01 -0700 Subject: [PATCH 6/7] refactor(api): Convert to MVC Structure --- apps/api/src/controllers/category.ts | 69 ++++++++++++++++++++++++++++ apps/api/src/models/category.ts | 4 ++ apps/api/src/routes/categories.ts | 55 +++------------------- 3 files changed, 79 insertions(+), 49 deletions(-) create mode 100644 apps/api/src/controllers/category.ts create mode 100644 apps/api/src/models/category.ts diff --git a/apps/api/src/controllers/category.ts b/apps/api/src/controllers/category.ts new file mode 100644 index 00000000..bf1ea5a7 --- /dev/null +++ b/apps/api/src/controllers/category.ts @@ -0,0 +1,69 @@ +import type { Category } from "../models/category" + +const categories: Category[] = [] + +const findCategory = (categories: Category[], id: string): Category | void => { + return categories.find(el => el.id === id) +} + +const getCategory = (req, res): void => { + const { id } = req.params; + const currentCategory = findCategory(categories, id) + + if (!currentCategory) return res.status(404).json({message: "Category not found"}) + + res.status(200).json(currentCategory); +} + +const updateCategory = (req, res) => { + const { id } = req.params; + const categoryIndex = categories.findIndex(el => el.id === id) + if (categoryIndex < 0) return res.status(404).json({message: "Category not found"}) + + const { name } = req.body; + if (!name) return res.status(401).json({ message: "Name is required!" }) + + categories[categoryIndex].name = name; + + res.status(203).json(categories[categoryIndex]); +} + +const deleteCategory = (req, res) => { + const { id } = req.params; + const categoryIndex = categories.findIndex(el => el.id === id) + if (categoryIndex < 0) return res.status(404).json({message: "Category not found"}) + + const currentCategory = categories[categoryIndex] + + categories.splice(categoryIndex, 1) + + res.status(200).json({status: "Item Deleted", item: currentCategory}); +} + + +const getAllCategories = (req, res) => { + res.status(200).json(categories); +} + +const createCategory = (req, res) => { + const { name } = req.body; + + if (!name) return res.status(401).json({ message: "Name is required!" }) + + const newCategory: Category = { + id: Date.now().toString(), + name + } + + categories.push(newCategory) + + res.status(201).json(newCategory) +} + +export default { + getCategory, + updateCategory, + deleteCategory, + getAllCategories, + createCategory, +} diff --git a/apps/api/src/models/category.ts b/apps/api/src/models/category.ts new file mode 100644 index 00000000..8c2f7393 --- /dev/null +++ b/apps/api/src/models/category.ts @@ -0,0 +1,4 @@ +export type Category = { + id: string, + name: string; +} diff --git a/apps/api/src/routes/categories.ts b/apps/api/src/routes/categories.ts index e3d31c1d..1573de98 100644 --- a/apps/api/src/routes/categories.ts +++ b/apps/api/src/routes/categories.ts @@ -1,59 +1,16 @@ import express from 'express'; +import categoryController from '../controllers/category'; const router = express.Router(); -const categories = [] router.route('/:id') - .get((req, res) => { - const { id } = req.params; - const currentCategory = categories.find(el => el.id === id) - - if (!currentCategory) return res.status(404).json({message: "Category not found"}) - - res.status(200).json(currentCategory); - }) - .patch((req, res) => { - const { id } = req.params; - const categoryIndex = categories.findIndex(el => el.id === id) - if (categoryIndex < 0) return res.status(404).json({message: "Category not found"}) - - const { name } = req.body; - if (!name) return res.status(401).json({ message: "Name is required!" }) - - categories[categoryIndex].name = name; - - res.status(203).json(categories[categoryIndex]); - }) - .delete((req, res) => { - const { id } = req.params; - const categoryIndex = categories.findIndex(el => el.id === id) - if (categoryIndex < 0) return res.status(404).json({message: "Category not found"}) - - const currentCategory = categories[categoryIndex] - - categories.splice(categoryIndex, 1) - - res.status(200).json({status: "Item Deleted", item: currentCategory}); - }) + .get(categoryController.getCategory) + .patch(categoryController.updateCategory) + .delete(categoryController.deleteCategory) router.route('/') - .get((req, res) => { - res.status(200).json(categories); - }) - .post((req, res) => { - const { name } = req.body; - - if (!name) return res.status(401).json({ message: "Name is required!" }) - - const newCategory = { - id: Date.now().toString(), - name - } - - categories.push(newCategory) - - res.status(201).json(newCategory) - }) + .get(categoryController.getAllCategories) + .post(categoryController.createCategory) export default router From 0579464f9cf7285450290cddc18ceb28055d5f18 Mon Sep 17 00:00:00 2001 From: Jennifer Nevarez Date: Fri, 21 Jun 2024 09:05:39 -0700 Subject: [PATCH 7/7] feeat(api): Create Posts Route in MVC Structure --- apps/api/src/controllers/category.ts | 8 +- apps/api/src/controllers/post.ts | 143 +++++++++++++++++++++++++++ apps/api/src/main.ts | 2 + apps/api/src/models/category.ts | 4 - apps/api/src/models/types.ts | 24 +++++ apps/api/src/routes/posts.ts | 21 ++++ 6 files changed, 194 insertions(+), 8 deletions(-) create mode 100644 apps/api/src/controllers/post.ts delete mode 100644 apps/api/src/models/category.ts create mode 100644 apps/api/src/models/types.ts create mode 100644 apps/api/src/routes/posts.ts diff --git a/apps/api/src/controllers/category.ts b/apps/api/src/controllers/category.ts index bf1ea5a7..999663f1 100644 --- a/apps/api/src/controllers/category.ts +++ b/apps/api/src/controllers/category.ts @@ -1,14 +1,14 @@ -import type { Category } from "../models/category" +import type { Category } from "../models/types" -const categories: Category[] = [] +export const categories: Category[] = [] -const findCategory = (categories: Category[], id: string): Category | void => { +const findCategory = (id: string): Category | void => { return categories.find(el => el.id === id) } const getCategory = (req, res): void => { const { id } = req.params; - const currentCategory = findCategory(categories, id) + const currentCategory = findCategory(id) if (!currentCategory) return res.status(404).json({message: "Category not found"}) diff --git a/apps/api/src/controllers/post.ts b/apps/api/src/controllers/post.ts new file mode 100644 index 00000000..c883316a --- /dev/null +++ b/apps/api/src/controllers/post.ts @@ -0,0 +1,143 @@ +import type { Post, Comment, PostResponse } from "../models/types" +import { categories } from "../controllers/category" + +const posts: Post[] = [] +const comments: Comment[] = [] + +const buildResponsePost = (post: Post): PostResponse => { + return { + ...post, + category: categories.filter(cat => post.category.includes(cat.id)), + comments: comments.filter(com => post.category.includes(com.id)) + } as PostResponse +} + +const findPost = (id: string): Post | void => { + return posts.find(el => el.id === id) +} + +const getPost = (req, res): void => { + const { id } = req.params; + const currentPost = findPost(id) + + if (!currentPost) return res.status(404).json({message: "Post not found"}) + + res.status(200).json(buildResponsePost(currentPost)); +} + +const updatePost = (req, res) => { + const { id } = req.params; + const postIndex = posts.findIndex(el => el.id === id) + if (postIndex < 0) return res.status(404).json({message: "Post not found"}) + + const post = req.body; + if (!post) return res.status(401).json({ message: "Name is required!" }) + + Object.keys(post).forEach(key => { + if (!posts[postIndex][key]) return + posts[postIndex][key] = post[key] + }) + + res.status(203).json(buildResponsePost(posts[postIndex])); +} + +const deletePost = (req, res) => { + const { id } = req.params; + const postIndex = categories.findIndex(el => el.id === id) + if (postIndex < 0) return res.status(404).json({message: "Post not found"}) + + const currentPost = buildResponsePost(posts[postIndex]) + + posts.splice(postIndex, 1) + + res.status(200).json({status: "Item Deleted", item: currentPost}); +} + +const createComment = (req, res) => { + const { id } = req.params; + const currentPost = findPost(id) + if (!currentPost) return res.status(404).json({message: "Post not found"}) + + const {comment} = req.body; + if (!comment.author || !comment.content) return res.status(401).json({ message: "Invalid Comment!" }) + + const commentId = Date.now().toString() + comments.push({ + id, + author: comment.author, + content: comment.content, + }) + + currentPost.comments.push(commentId) + + res.status(203).json(buildResponsePost(currentPost)); +} + + +const getAllPosts = (req, res) => { + res.status(200).json(posts.map(post => buildResponsePost(post))); +} + +const createPost = (req, res) => { + const { + title, + image, + description, + category, + comments, + } = req.body; + + if ( + !title + || !image + || !description + || !category + ) return res.status(401).json({ message: "Invalid Post!" }) + + const newComments: string[] = [] + + comments.forEach(({author, content}) => { + if (!author || !content) res.status(401).json({ message: "Invalid Comment!" }) + + const id = Date.now().toString() + + newComments.push(id) + + comments.push({ + id, + author, + content, + }) + }); + + const newPost: Post = { + ...req.body, + id: Date.now().toString(), + comments: newComments, + } + + posts.push(newPost) + + res.status(201).json(buildResponsePost(newPost)) +} + +const getAllPostsByCategory = (req, res): void => { + const { category } = req.params; + let categoryPosts = posts.filter(post => post.category.includes(category)) + + if (!categoryPosts.length) return res.status(404).json({message: "Category has no posts"}) + + categoryPosts = categoryPosts.map(post => buildResponsePost(post)) + + res.status(200).json(categoryPosts); +} + +export default { + getPost, + updatePost, + deletePost, + createComment, + getAllPosts, + createPost, + getAllPostsByCategory +} diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index b9b006fb..3eec0782 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -4,6 +4,7 @@ import cors from 'cors'; import { corsOptions } from './config/corsConfig'; 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; @@ -14,6 +15,7 @@ app.use(express.json()) app.use(helmet()) app.use(cors(corsOptions)) +app.use('/api/post', posts) app.use('/api/categories', categories) app.get('/', (req, res) => { diff --git a/apps/api/src/models/category.ts b/apps/api/src/models/category.ts deleted file mode 100644 index 8c2f7393..00000000 --- a/apps/api/src/models/category.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type Category = { - id: string, - name: string; -} diff --git a/apps/api/src/models/types.ts b/apps/api/src/models/types.ts new file mode 100644 index 00000000..09904544 --- /dev/null +++ b/apps/api/src/models/types.ts @@ -0,0 +1,24 @@ +export type Category = { + id: string, + name: string; +} + +export type Comment = { + id: string + author: string + content: string +} + +export type Post = { + id: string + title: string + image: string + description: string + category: Category['id'][] + comments: Comment['id'][] +} + +export type PostResponse = Post & { + category: Category[] + comments: Comment[] +} diff --git a/apps/api/src/routes/posts.ts b/apps/api/src/routes/posts.ts new file mode 100644 index 00000000..313bd76f --- /dev/null +++ b/apps/api/src/routes/posts.ts @@ -0,0 +1,21 @@ +import express from 'express'; +import postController from '../controllers/post'; + +const router = express.Router(); + +router.route('/:id') + .get(postController.getPost) + .patch(postController.updatePost) + .delete(postController.deletePost) + +router.route("/:id/comments") + .post(postController.createComment) + +router.route('/') + .get(postController.getAllPosts) + .post(postController.createPost) + +router.route("/category/:category") + .get(postController.getAllPostsByCategory) + +export default router