From e368c1fb8b1a017d5b624640a43407a55639cbe8 Mon Sep 17 00:00:00 2001 From: Ali Date: Wed, 26 Nov 2025 22:07:35 +0300 Subject: [PATCH] complete --- data/tasks.json | 58 ++++-- package.json | 4 +- routes/taskRoute.js | 474 ++++++++++++++++++++++++++++++++++++++++++++ routes/tasks.js | 233 ---------------------- server.js | 10 +- 5 files changed, 522 insertions(+), 257 deletions(-) create mode 100644 routes/taskRoute.js delete mode 100644 routes/tasks.js diff --git a/data/tasks.json b/data/tasks.json index 3747a16..e81bc0e 100644 --- a/data/tasks.json +++ b/data/tasks.json @@ -1,6 +1,6 @@ [ { - "id": "1", + "id": 1, "title": "Learn Node.js Fundamentals", "description": "Complete the Node.js basics course and build a simple server", "status": "in-progress", @@ -9,25 +9,25 @@ "assignedTo": "John Doe", "subtasks": [ { - "id": "1.1", + "id": 1.1, "title": "Install Node.js", "completed": true, "description": "Download and install Node.js on your machine" }, { - "id": "1.2", + "id": 1.2, "title": "Create First Server", "completed": false, "description": "Build a simple HTTP server using Express.js" }, { - "id": "1.3", + "id": 1.3, "title": "Handle Routes", "completed": false, "description": "Learn how to create and handle different routes" }, { - "id": "1.4", + "id": 1.4, "title": "Test Subtask", "description": "This is a test subtask", "completed": false @@ -37,7 +37,7 @@ "updatedAt": "2025-07-23T01:29:37.667Z" }, { - "id": "2", + "id": 2, "title": "Build REST API", "description": "Create a complete REST API with CRUD operations", "status": "pending", @@ -46,25 +46,25 @@ "assignedTo": "Jane Smith", "subtasks": [ { - "id": "2.1", + "id": 2.1, "title": "Design API Structure", "completed": false, "description": "Plan the API endpoints and data structure" }, { - "id": "2.2", + "id": 2.2, "title": "Implement GET Routes", "completed": false, "description": "Create routes to retrieve data" }, { - "id": "2.3", + "id": 2.3, "title": "Implement POST Routes", "completed": false, "description": "Create routes to add new data" }, { - "id": "2.4", + "id": 2.4, "title": "Add Validation", "completed": false, "description": "Implement input validation and error handling" @@ -74,7 +74,7 @@ "updatedAt": "2024-01-02T11:00:00.000Z" }, { - "id": "3", + "id": 3, "title": "Database Integration", "description": "Connect the API to a database system", "status": "completed", @@ -83,25 +83,25 @@ "assignedTo": "Mike Johnson", "subtasks": [ { - "id": "3.1", + "id": 3.1, "title": "Choose Database", "completed": true, "description": "Select appropriate database (MongoDB/PostgreSQL)" }, { - "id": "3.2", + "id": 3.2, "title": "Setup Connection", "completed": true, "description": "Configure database connection" }, { - "id": "3.3", + "id": 3.3, "title": "Create Models", "completed": true, "description": "Define data models and schemas" }, { - "id": "3.4", + "id": 3.4, "title": "Update API", "completed": true, "description": "Modify API to use database instead of JSON files" @@ -111,7 +111,7 @@ "updatedAt": "2024-01-08T16:45:00.000Z" }, { - "id": "4", + "id": 4, "title": "Frontend Development", "description": "Build a React frontend to consume the API", "status": "pending", @@ -120,19 +120,19 @@ "assignedTo": "Alice Johnson", "subtasks": [ { - "id": "4.1", + "id": 4.1, "title": "Setup React Project", "completed": false, "description": "Create new React application" }, { - "id": "4.2", + "id": 4.2, "title": "Create Components", "completed": false, "description": "Build reusable UI components" }, { - "id": "4.3", + "id": 4.3, "title": "Connect to API", "completed": false, "description": "Integrate frontend with backend API" @@ -142,7 +142,7 @@ "updatedAt": "2024-01-04T13:20:00.000Z" }, { - "id": "5", + "id": 5, "title": "Test", "description": "Test", "status": "pending", @@ -152,5 +152,23 @@ "subtasks": [], "createdAt": "2025-07-23T04:22:47.898Z", "updatedAt": "2025-07-23T04:22:47.899Z" + }, + { + "id": 6, + "title": "Read Node.js Fundamentals", + "description": "Complete the Node.js basics course and build a simple server", + "status": "in-progress", + "priority": "high", + "createdAt": "2025-11-26T16:51:48.131Z", + "updatedAt": "2025-11-26T16:51:48.132Z" + }, + { + "id": 7, + "title": "Update Node.js Fundamentals", + "description": "Complete the Node.js basics course and build a simple server", + "status": "in-progress", + "priority": "high", + "createdAt": "2025-11-26T17:08:22.800Z", + "updatedAt": "2025-11-26T17:08:22.801Z" } ] \ No newline at end of file diff --git a/package.json b/package.json index 2327747..0caecd8 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,9 @@ "author": "Duraan", "license": "MIT", "dependencies": { - "express": "^4.18.2", + "body-parser": "^1.20.3", "cors": "^2.8.5", - "body-parser": "^1.20.2", + "express": "^4.21.2", "node-fetch": "^3.3.2" }, "devDependencies": { diff --git a/routes/taskRoute.js b/routes/taskRoute.js new file mode 100644 index 0000000..cf55e58 --- /dev/null +++ b/routes/taskRoute.js @@ -0,0 +1,474 @@ +import { error } from "console"; +import express from "express"; +import fs from "fs/promises"; +import path from "path"; +import { title } from "process"; +import { fileURLToPath } from "url"; + + + +// Initialize Express +const router = express.Router(); + +// ES module __dirname equivalent +// In CommonJS, __dirname is automatically available, but in ES modules we need to create it manually +// import.meta.url gives us the URL of the current module file +// fileURLToPath converts the URL to a file path string +// path.dirname gets the directory name from the file path +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Path to the data file +// path.join combines the current directory with the relative path to our data file +// "../data/tasks.json" means: go up one directory, then into 'data' folder, then 'tasks.json' +//const dataFilePath = path.join(__dirname, "../data/tasks.json"); ??? + +// Get the file path +const dataFilePath = path.resolve("data/tasks.json") + +// Helper function to read tasks from JSON file +// fs.readFile reads the file asynchronously and returns a promise +// JSON.parse converts the string data back to a JavaScript array +// If file doesn't exist or has errors, return empty array + +// function to get all the task data. + + async function getAllTasks() { + try { + //read tasks.json file using fs + const tasks = await fs.readFile(dataFilePath, "utf8"); + return JSON.parse(tasks); + } catch (error) { + return error + } + } + +// ENDPOINTS +// 1- get all tasks + +router.get("/", async (req, res) => { + try { + + const tasks = await getAllTasks(); + + res.status(200).json(allTasks) + } catch(error) { + res.status(400).json(error) + } +}) + +// 2- get one task + +router.get("/:id", async (req, res) => { + const { id } = req.params + const tasks = await getAllTasks() + const currentTask = tasks.find((task) => task.id === Number(id)) + + // if we can't find the task + if(!currentTask) { + return res.status(404).json({ error: "Task not found"}) + } + + res.json(currentTask) +}) + +// Helper function to write tasks to JSON file +// JSON.stringify converts the array back to a string with nice formatting (null, 2) +// fs.writeFile writes the data to the file asynchronously + +// 3- add new task function +async function writeTasks(tasks) { + await fs.writeFile(dataFilePath, JSON.stringify(tasks, null, 2)); + } + + // Add new task + router.post("/", async (req, res) => { + try { + //1. Get all the information of the task using req.body + const { title, description, status, priority } = req.body + + //2. verify if the information is there + if (!title || !description) { + return res.status(400).json({error: "Missing required fields"}); + } + + //3. get all the tasks, get task's ID, then increment + const tasks = await getAllTasks(); + // if there are tasks, get the one with the highest ID number then add one, if there are no tasks, make newID = 1. + const newID = tasks.length > 0 ? Math.max(...tasks.map((s) => parseInt(s.id))) + 1 : 1; + + //4. Build the new task information in one variable + const newTask = { + id: newID, + title, + description, + status: status || null, + priority: priority || null, + createdAt: new Date().toISOString(), // Current timestamp + updatedAt: new Date().toISOString(), + }; + + //5. add the new task to the list of all tasks using writetasks function + tasks.push(newTask) + await writeTasks(tasks) + + //6. return all tasks with the new task added + res.status(201).json(newTask) + + } catch(error) { + res.status(500).json(error) + } + }) + + + // 4- update a task (PUT) +router.put("/:id", async (req, res) => { + try { + const { id } = req.params; + const { title, description, status, priority } = req.body; + + // 1. Validate incoming data (ensure title and description are present) + if (!title || !description) { + return res.status(400).json({ error: "Missing required fields (title and description) for update." }); + } + + // 2. Get all existing tasks + const tasks = await getAllTasks(); + const taskIndex = tasks.findIndex((task) => task.id === Number(id)); + + // 3. Check if the task exists + if (taskIndex === -1) { + return res.status(404).json({ error: "Task not found." }); + } + + // 4. Create the updated task object, maintaining the original ID and creation date + const updatedTask = { + id: Number(id), // Ensure the ID remains the correct number + title, + description, + status: status || tasks[taskIndex].status, // Use new status or keep existing one + priority: priority || tasks[taskIndex].priority, // Use new priority or keep existing one + createdAt: tasks[taskIndex].createdAt, // Preserve original creation timestamp + updatedAt: new Date().toISOString(), // Set new update timestamp + }; + + // 5. Replace the old task object in the array with the new one + tasks[taskIndex] = updatedTask; + + // 6. Write the updated array back to the JSON file + await writeTasks(tasks); + + // 7. Return the newly updated task + res.status(200).json(updatedTask); + } catch (error) { + console.error("Error updating task:", error.message); + res.status(500).json({ error: "Internal server error updating task" }); + } +}); + + +// Helper function to validate task data +// This function checks if the required fields are present and valid +// function validateTaskData(taskData) { +// const requiredFields = ["title", "description", "status", "priority"]; +// const validStatuses = ["pending", "in-progress", "completed", "cancelled"]; +// const validPriorities = ["low", "medium", "high", "urgent"]; + +// // Check if all required fields are present +// for (const field of requiredFields) { +// if (!taskData[field]) { +// return { isValid: false, error: `Missing required field: ${field}` }; +// } +// } + +// // Validate status +// if (!validStatuses.includes(taskData.status)) { +// return { +// isValid: false, +// error: `Invalid status. Must be one of: ${validStatuses.join(", ")}`, +// }; +// } + +// // Validate priority +// if (!validPriorities.includes(taskData.priority)) { +// return { +// isValid: false, +// error: `Invalid priority. Must be one of: ${validPriorities.join(", ")}`, +// }; +// } + +// return { isValid: true }; +// } + +// // GET /api/tasks - Get all tasks +// // This route handles GET requests to /api/tasks +// // req = request object (contains data sent by client) +// // res = response object (used to send data back to client) +// router.get("/tasks", async (req, res) => { +// try { +// const tasks = await getAllTasks(); + +// // Add query parameter support for filtering +// let filteredTasks = tasks; + +// // Filter by status if provided +// if (req.query.status) { +// filteredTasks = filteredTasks.filter( +// (task) => task.status === req.query.status +// ); +// } + +// // Filter by priority if provided +// if (req.query.priority) { +// filteredTasks = filteredTasks.filter( +// (task) => task.priority === req.query.priority +// ); +// } + +// // Filter by assignedTo if provided +// if (req.query.assignedTo) { +// filteredTasks = filteredTasks.filter((task) => +// task.assignedTo +// .toLowerCase() +// .includes(req.query.assignedTo.toLowerCase()) +// ); +// } + +// res.json({ +// success: true, +// count: filteredTasks.length, +// data: filteredTasks, +// }); +// } catch (error) { +// res.status(500).json({ +// success: false, +// error: "Error retrieving tasks", +// }); +// } +// }); + +// // GET /api/tasks/:id - Get task by ID +// // :id is a route parameter - it captures the value from the URL +// // Example: /api/tasks/1 will set req.params.id = "1" +// router.get("/tasks/:id", async (req, res) => { +// try { +// const { id } = req.params; // Extract the ID from the URL +// const tasks = await getAllTasks(); +// const task = tasks.find((task) => task.id === id); // Find task with matching ID + +// if (!task) { +// return res.status(404).json({ +// success: false, +// error: "Task not found", +// }); // 404 = Not Found +// } + +// res.json({ +// success: true, +// data: task, +// }); +// } catch (error) { +// res.status(500).json({ +// success: false, +// error: "Error retrieving task", +// }); // 500 = Server Error +// } +// }); + +// // POST /api/tasks - Create new task +// // POST requests are used to create new resources +// // req.body contains the data sent in the request body +// router.post("/api/tasks", async (req, res) => { +// try { +// // TODO: Implement task creation +// // 1. Extract data from req.body (title, description, status, priority, etc.) + +// const {title, description, status, priority,} = req.body + +// // 2. Validate the data using validateTaskData function + +// if (!title || !description || !status || !priority) { +// return res.status(400).json({ error: "Missing required fields" }); +// } +// // 3. Get all existing tasks using getAllTasks() + +// let tasks = getAllTasks + +// const students = await getAllTasks(); + +// // 4. Generate a new ID for the task + +// const newID = +// tasks.length > 0 +// ? Math.max(...tasks.map((s) => parseInt(s.id))) + 1 +// : 1; + +// // 5. Create a new task object with all required fields + +// const newTask = { +// id: newID, +// title, +// description, +// status, +// priority: priority || null, +// createdAt: new Date().toISOString(), // Current timestamp +// updatedAt: new Date().toISOString(), +// }; + +// // 6. Add the task to the tasks array + +// tasks.push(newTask); + +// // 7. Save to file using writeTasks() +// await writeTasks(tasks); +// // 8. Send success response with status 201 + +// res.status(201).json(newTask); +// } catch (error) { +// res.status(500).json({ error, message: "Error creating task" }); +// } +// }); + +// // Temporary response - remove this when you implement the above +// res.status(501).json({ +// success: false, +// error: +// "POST endpoint not implemented yet - implement task creation above", +// }); +// } catch (error) { +// res.status(500).json({ +// success: false, +// error: "Error creating task", +// }); // 500 = Server Error +// } +// }); + +// PUT /api/tasks/:id - Update task +// PUT requests are used to update existing resources +// The entire resource is replaced with the new data +router.put("/:id", async (req, res) => { + try { + // TODO: Implement task update + // 1. Extract the task ID from req.params + const { id } = req.params; + + // 2. Get the update data from req.body + + //const { id } = req.params; + const updatedTaskData = req.body; + + //const updateData = req.body; + + // 3. Validate the data if status or priority is being updated + + if (!updatedTaskData.title || !updatedTaskData.description || !updatedTaskData.status || !updatedTaskData.priority) { + return res.status(400).json({ message: 'Missing required fields for update' }); + } + + if (taskIndex === -1) { + return res.status(404).json({ message: 'Task not found' }); + } + + // 4. Get all tasks and find the task by ID + + const tasks = await readTasks(); + + // 5. Check if task exists, return 404 if not found + + const taskIndex = tasks.findIndex(t => t.id === taskId); + + if (taskIndex === -1) { + return res.status(404).json({ message: "Task not found" }); + } + // 6. Update the task with new data + const currentTask = tasks[taskIndex]; + //title, description, status, priority + + currentTask.title = title || currentTask.title; + currentTask.description = description || currentTitle.description; + currentTask.status = status !== undefined ? status : currentTask.status; + currentTask.priority = priority || currentTask.priority; + currentTask.updatedAt = new Date().toISOString(); // Update timestamp + + + + tasks[taskIndex] = { ...tasks[taskIndex], ...updatedTaskData }; + + // 7. Save to file using writeTasks() + + await writeTasks(tasks); + + // 8. Send success response with the updated task + + res.json(tasks[taskIndex]); + + // // Temporary response - remove this when you implement the above + // res.status(501).json({ + // success: false, + // error: "PUT endpoint not implemented yet - implement task update above", + // }); + res.status(201).json(updatedTaskData) + } catch (error) { + res.status(500).json({ error, message: "Error updating task"}); // 500 = Server Error + } +}); + + +// DELETE /api/tasks/:id - Delete task +// DELETE requests are used to remove resources +router.delete("/:id", async (req, res) => { + try { + // TODO: Implement task deletion + // 1. Extract the task ID from req.params + + const taskId = parseInt(req.params.id); + + // 2. Get all tasks and find the task by ID + + const tasks = await getAllTasks(); + const taskIndex = tasks.findIndex(t => t.id === taskId); + + // 3. Check if task exists, return 404 if not found + + if (taskIndex === -1) { + return res.status(404).json({ message: "Task not found" }); + } + // 4. Store the task before deletion (for response) + + const deletedTask = tasks[taskIndex]; + + // 5. Remove the task from the array + + tasks.splice(taskIndex, 1); + + // 6. Save to file using writeTasks() + + await writeTasks(tasks); + + // 7. Send success response with the deleted task + + res.json(deletedTask); + + } catch (error) { + console.error(error); + res.status(500).json({ + success: false, + error + }); // 500 = Server Error + } + + // // Temporary response - remove this when you implement the above + // res.status(501).json({ + // success: false, + // error: + // "DELETE endpoint not implemented yet - implement task deletion above", + // }); + // } catch (error) { + // res.status(500).json({ + // success: false, + // error: "Error deleting task", + // }); // 500 = Server Error + // } +}); + +export default router; diff --git a/routes/tasks.js b/routes/tasks.js deleted file mode 100644 index b2bcfcb..0000000 --- a/routes/tasks.js +++ /dev/null @@ -1,233 +0,0 @@ -import express from "express"; -import fs from "fs/promises"; -import path from "path"; -import { fileURLToPath } from "url"; - -const router = express.Router(); - -// ES module __dirname equivalent -// In CommonJS, __dirname is automatically available, but in ES modules we need to create it manually -// import.meta.url gives us the URL of the current module file -// fileURLToPath converts the URL to a file path string -// path.dirname gets the directory name from the file path -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// Path to the data file -// path.join combines the current directory with the relative path to our data file -// "../data/tasks.json" means: go up one directory, then into 'data' folder, then 'tasks.json' -const dataFilePath = path.join(__dirname, "../data/tasks.json"); - -// Helper function to read tasks from JSON file -// fs.readFile reads the file asynchronously and returns a promise -// JSON.parse converts the string data back to a JavaScript array -// If file doesn't exist or has errors, return empty array -async function getAllTasks() { - try { - const data = await fs.readFile(dataFilePath, "utf8"); - return JSON.parse(data); - } catch (error) { - return []; - } -} - -// Helper function to write tasks to JSON file -// JSON.stringify converts the array back to a string with nice formatting (null, 2) -// fs.writeFile writes the data to the file asynchronously -async function writeTasks(tasks) { - await fs.writeFile(dataFilePath, JSON.stringify(tasks, null, 2)); -} - -// Helper function to validate task data -// This function checks if the required fields are present and valid -function validateTaskData(taskData) { - const requiredFields = ["title", "description", "status", "priority"]; - const validStatuses = ["pending", "in-progress", "completed", "cancelled"]; - const validPriorities = ["low", "medium", "high", "urgent"]; - - // Check if all required fields are present - for (const field of requiredFields) { - if (!taskData[field]) { - return { isValid: false, error: `Missing required field: ${field}` }; - } - } - - // Validate status - if (!validStatuses.includes(taskData.status)) { - return { - isValid: false, - error: `Invalid status. Must be one of: ${validStatuses.join(", ")}`, - }; - } - - // Validate priority - if (!validPriorities.includes(taskData.priority)) { - return { - isValid: false, - error: `Invalid priority. Must be one of: ${validPriorities.join(", ")}`, - }; - } - - return { isValid: true }; -} - -// GET /api/tasks - Get all tasks -// This route handles GET requests to /api/tasks -// req = request object (contains data sent by client) -// res = response object (used to send data back to client) -router.get("/tasks", async (req, res) => { - try { - const tasks = await getAllTasks(); - - // Add query parameter support for filtering - let filteredTasks = tasks; - - // Filter by status if provided - if (req.query.status) { - filteredTasks = filteredTasks.filter( - (task) => task.status === req.query.status - ); - } - - // Filter by priority if provided - if (req.query.priority) { - filteredTasks = filteredTasks.filter( - (task) => task.priority === req.query.priority - ); - } - - // Filter by assignedTo if provided - if (req.query.assignedTo) { - filteredTasks = filteredTasks.filter((task) => - task.assignedTo - .toLowerCase() - .includes(req.query.assignedTo.toLowerCase()) - ); - } - - res.json({ - success: true, - count: filteredTasks.length, - data: filteredTasks, - }); - } catch (error) { - res.status(500).json({ - success: false, - error: "Error retrieving tasks", - }); - } -}); - -// GET /api/tasks/:id - Get task by ID -// :id is a route parameter - it captures the value from the URL -// Example: /api/tasks/1 will set req.params.id = "1" -router.get("/tasks/:id", async (req, res) => { - try { - const { id } = req.params; // Extract the ID from the URL - const tasks = await getAllTasks(); - const task = tasks.find((task) => task.id === id); // Find task with matching ID - - if (!task) { - return res.status(404).json({ - success: false, - error: "Task not found", - }); // 404 = Not Found - } - - res.json({ - success: true, - data: task, - }); - } catch (error) { - res.status(500).json({ - success: false, - error: "Error retrieving task", - }); // 500 = Server Error - } -}); - -// POST /api/tasks - Create new task -// POST requests are used to create new resources -// req.body contains the data sent in the request body -router.post("/tasks", async (req, res) => { - try { - // TODO: Implement task creation - // 1. Extract data from req.body (title, description, status, priority, etc.) - // 2. Validate the data using validateTaskData function - // 3. Get all existing tasks using getAllTasks() - // 4. Generate a new ID for the task - // 5. Create a new task object with all required fields - // 6. Add the task to the tasks array - // 7. Save to file using writeTasks() - // 8. Send success response with status 201 - - // Temporary response - remove this when you implement the above - res.status(501).json({ - success: false, - error: - "POST endpoint not implemented yet - implement task creation above", - }); - } catch (error) { - res.status(500).json({ - success: false, - error: "Error creating task", - }); // 500 = Server Error - } -}); - -// PUT /api/tasks/:id - Update task -// PUT requests are used to update existing resources -// The entire resource is replaced with the new data -router.put("/tasks/:id", async (req, res) => { - try { - // TODO: Implement task update - // 1. Extract the task ID from req.params - // 2. Get the update data from req.body - // 3. Validate the data if status or priority is being updated - // 4. Get all tasks and find the task by ID - // 5. Check if task exists, return 404 if not found - // 6. Update the task with new data - // 7. Save to file using writeTasks() - // 8. Send success response with the updated task - - // Temporary response - remove this when you implement the above - res.status(501).json({ - success: false, - error: "PUT endpoint not implemented yet - implement task update above", - }); - } catch (error) { - res.status(500).json({ - success: false, - error: "Error updating task", - }); // 500 = Server Error - } -}); - -// DELETE /api/tasks/:id - Delete task -// DELETE requests are used to remove resources -router.delete("/tasks/:id", async (req, res) => { - try { - // TODO: Implement task deletion - // 1. Extract the task ID from req.params - // 2. Get all tasks and find the task by ID - // 3. Check if task exists, return 404 if not found - // 4. Store the task before deletion (for response) - // 5. Remove the task from the array - // 6. Save to file using writeTasks() - // 7. Send success response with the deleted task - - // Temporary response - remove this when you implement the above - res.status(501).json({ - success: false, - error: - "DELETE endpoint not implemented yet - implement task deletion above", - }); - } catch (error) { - res.status(500).json({ - success: false, - error: "Error deleting task", - }); // 500 = Server Error - } -}); - -export default router; diff --git a/server.js b/server.js index 47a9f9a..afca375 100644 --- a/server.js +++ b/server.js @@ -3,7 +3,7 @@ import cors from "cors"; import bodyParser from "body-parser"; // Import routes -import taskRoutes from "./routes/tasks.js"; +import taskRoute from "./routes/taskRoute.js"; // Initialize Express app const app = express(); @@ -16,7 +16,7 @@ app.use(bodyParser.urlencoded({ extended: true })); // Parse URL-encoded bodies // Mount API routes -app.use("/api", taskRoutes); +app.use("/api/tasks", taskRoute); // Error handling middleware app.use((err, req, res, next) => { @@ -36,6 +36,12 @@ app.use("*", (req, res) => { }); }); +//Basic API + +app.get("/", (req, res) => { + res.json({message: "Welcome to NODE JS and EXPRESS"}) +}) + // Start server app.listen(PORT, () => { console.log(`🚀 Server is running on http://localhost:${PORT}`);