I got some problem about routing on express js, when I hit some endpoint for example :
http://localhost:3000/api/v1/projects/task/f9488b07-76f8-4f8a-bafb-471f99dde7b8
http://localhost:3000/api/v1/project/0592679a-93f1-467b-b2cd-4226f0668036
I got the message on function handling like this:
{
"errors": "Failed to find a project: Project ID is required"
}
but that message on function findProjectID
:
todo-service.js
/* eslint-disable no-useless-catch */
const prismaClient = require("../prisma-client");
const { ResponseError } = require("../error/error-response");
const createProject = async ({
projectname,
description,
owner,
expiresAt,
}) => {
try {
const userConnections =
Array.isArray(owner) && owner.length > 0
? owner.filter((o) => o.user_id).map((o) => ({ user_id: o.user_id }))
: null;
console.log();
// Parse the input date string using Date constructor
// Check if `expiresAt` is provided and is a valid date
const timestamp = expiresAt ? new Date(expiresAt).toISOString() : null;
if (expiresAt && isNaN(new Date(expiresAt))) {
throw new Error("Invalid date format for expiresAt.");
}
const data = {
projectname,
description,
...(timestamp && { expiresAt: timestamp }),
...(userConnections.length > 0 && {
owner: { connect: userConnections },
}),
};
const createdProject = await prismaClient.project.create({
data,
include: {
owner: {
select: {
user_id: true,
username: true,
},
}, //
},
});
return createdProject;
} catch (error) {
console.error("Error creating project:", error);
throw error;
}
};
//getvalueprojectbyownerid
const getProject = async (projectId) => {
try {
const project = await prismaClient.project.findMany({
where: {
project_id: projectId,
},
include: {
owner: {
select: {
user_id: true,
username: true, // Adjust according to your user model fields
},
},
},
});
console.log(project);
return project;
} catch (error) {
console.log(error);
}
};
//editproject
const editproject = async (project_id, projectname, description, owner) => {
try {
const findProject = await findProjectID(project_id);
console.log(findProject);
if (!findProject) {
throw new ResponseError(404,"Project ID not Found");
}
const data = {
projectname,
description,
};
if (Array.isArray(owner)) {
const connectOwners = owner
.filter((o) => o.user_id)
.map((o) => ({ user_id: o.user_id }));
if (connectOwners.length > 0) {
data.owner = {
connect: connectOwners,
};
} else {
const disconnectOwners = findProject.owner.map((o) => ({
user_id: o.user_id,
}));
if (disconnectOwners.length > 0) {
data.owner = {
disconnect: disconnectOwners,
};
}
}
}
console.log("Data to update:", data);
const projectUpdate = await prismaClient.project.update({
where: {
project_id,
},
data,
include: {
owner: {
select: {
user_id: true,
username: true,
},
},
},
});
return projectUpdate;
} catch (error) {
console.log(error);
throw new Error("Failed to update project");
}
};
//delete todo projectbyid
const deleteProjectById = async (project_id) => {
try {
const findProject = await findProjectID(project_id);
if (!findProject) {
throw new ResponseError(404, "Project Not Found");
}
const deleteProject = await prismaClient.project.delete({
where: {
project_id,
},
});
return deleteProject;
} catch (error) {
console.log(error);
}
};
//findProjecID
const findProjectID = async (project_id) => {
try {
if (!project_id) {
throw new Error("Project ID is required");
}
const project = await prismaClient.project.findUnique({
where: { project_id },
include: { owner: true },
});
return project;
} catch (error) {
console.error("Error finding a project:", error.message);
throw new Error(`Failed to find a project: ${error.message}`);
}
};
//Task
const createTask = async ({
title,
description,
status,
priority,
projectId,
assigneeId,
expiresAt
}) => {
try {
const timestamp = expiresAt ? new Date(expiresAt).toISOString() : null;
if (expiresAt && isNaN(new Date(expiresAt))) {
throw new Error("Invalid date format for expiresAt.");
}
const createTasks = await prismaClient.task.create({
data: {
title : title || null,
description : description || null,
status : status || null,
priority: priority || null,
project: projectId
? { connect: { project_id: projectId } }
: undefined,
Assignee: assigneeId
? { connect: { user_id: assigneeId } }
: undefined,
...(timestamp && { expiresAt: timestamp }),
},
include: {
Assignee: {
select: {
user_id: true,
username: true,
},
},
project: {
select: {
project_id: true,
projectname: true,
},
},
},
});
return createTasks;
} catch (error) {
console.error("Error creating task:", error.message);
throw new Error(`Failed to create task: ${error.message}`);
}
};
const getTaskById = async (task_id) => {
try {
if (!task_id) {
throw new Error("task ID is required");
}
const task = await prismaClient.task.findUnique({
where: { task_id : task_id},
include : {
project : {
select : {
projectname : true
}
},
Assignee : {
select : {
username : true
}
}
},
});
return task;
} catch (error) {
throw error;
}
};
const editTask = async (task_id, title, description, status, priority, projectId, assigneeId, expiresAt) => {
try {
const findTask = await findTaskById(task_id);
if (!findTask) {
throw new ResponseError(404, "Task not found");
}
const timestamp = expiresAt ? new Date(expiresAt).toISOString() : null;
const editedTask = await prismaClient.task.update({
where: {
task_id
},
data: {
title: title || null,
description: description || null,
status: status || null,
priority: priority || null,
project: projectId
? { connect: { project_id: projectId } }
: { disconnect: true },
Assignee: assigneeId
? { connect: { user_id: assigneeId } }
: { disconnect: true },
...(timestamp && { expiresAt: timestamp }),
},
include: {
Assignee: {
select: {
user_id: true,
username: true,
},
},
project: {
select: {
project_id: true,
projectname: true,
},
},
},
});
return editedTask;
// eslint-disable-next-line no-unused-vars
} catch (error) {
console.error("Error finding a project:", error.message);
throw new Error("Failed to Edit Task");
}
};
const deleteTask = async(taskid) => {
try {
if(!taskid) {
throw new ResponseError(404, "task id is required!")
}
const findTaskId = await findTaskById(taskid)
console.log("idne apa :: ",findTaskId)
if(!findTaskId){
throw new ResponseError(404, "task id not found")
}
const deleteTask = await prismaClient.task.delete({
where : {
task_id : taskid
}
})
return deleteTask
} catch (error) {
throw error
}
}
const findTaskById = async (task_id) => {
try {
if (!task_id) {
throw new ResponseError(404,"task Id is required");
}
const task = await prismaClient.task.findUnique({
where: { task_id : task_id},
});
if (!task) {
throw new ResponseError(404,"Task id not found");
}
return task;
} catch (error) {
throw error;
}
};
module.exports = {
createProject,
getProject,
editproject,
deleteProjectById,
findProjectID,
createTask,
getTaskById,
editTask,
deleteTask,
findTaskById
};
its a controller file :
todo-controller.js
const { createProject, getProject, editproject, deleteProjectById, findProjectID, createTask, getTaskById, editTask, findTaskById, deleteTask} = require("../services/todo-services");
const createProjectHandler = async (req, res , next) => {
try {
const {projectname, description, owner,expiresAt} = req.body
console.log("Request body:", req.body);
if (!owner) {
throw new Error('User ID is required for connecting an owner.');
}
const createNewProject = await createProject({
projectname,
description,
owner,
expiresAt
});
res.status(201).json({status : 201,
data: createNewProject
})
} catch (error) {
console.log(error)
next(error)
}
}
const getProjectByIdHandler = async ( req, res , next) => {
try {
const projectId = req.params.projectId
if (!projectId) {
return res
.status(400)
.json({ error: "Invalid project ID", message: "Invalid Request" });
}
const project = await getProject(projectId)
if(!project){
return res.status(404).json({ error: "Project not found", message: "No project found for the given owner ID" });
}
return res.status(200).json(project);
} catch (error) {
console.log(error)
next()
}
}
const editProjectHandler = async ( req, res, next ) => {
try {
const projectId = req.params.projectId
const {projectname, description, owner} = req.body
console.log("project ID :: " ,projectId)
if(!projectId) {
return res
.status(400)
.json({ error: "Invalid Project ID", message: "Invalid Request" });
}
const updateProject = await editproject(projectId,projectname,description,owner)
return res.status(201).json({message : "Project Succesfully to Update",updateProject})
} catch (error) {
console.log(error)
next (error)
}
}
//delete handler project
const deleteProjectHandler = async (req, res, next) => {
try {
const projectId = req.params.projectId;
// Await the result of findProjectID to ensure it completes
const findProject = await findProjectID(projectId);
if (!findProject) {
return res.status(404).json({ error: "Invalid Project ID", message: "Project not found" });
}
// Proceed to delete the project
await deleteProjectById(projectId);
// Return 204 No Content status as the deletion was successful
return res.status(204).send();
} catch (error) {
// Log the error for debugging
console.error("Delete Project Handler Error:", error);
// Forward the error to the error handling middleware
next(error);
}
};
const createTaskHandler = async(req, res, next) => {
try {
const {title, description,status, priority,projectId,assigneeId, expiresAt} = req.body
const newTask = await createTask({title, description,status, priority,projectId,assigneeId,expiresAt})
console.log("newtask :: ", newTask)
res.status(201).json({status : 201,
data: newTask
})
} catch (error) {
next(error)
}
}
const getTaskByIdHandler = async (req, res, next) => {
try {
const task_id = req.params.taskId;
// Check if taskId is provided
if (!task_id) {
return res.status(400).json({ status: 400, error: "Task ID is required" });
}
// Find the task by ID
const task = await getTaskById(task_id);
if (!task) {
return res.status(404).json({ status: 404, error: "Task Not Found" });
}
// Return the found task
res.status(200).json({
status: 200,
data: task,
});
} catch (error) {
next(error); // Pass the error to the error handling middleware
}
};
const editTaskHandler = async(req, res, next) => {
try {
const taskId = req.params.taskId
console.log("task id :: ", taskId)
const { title, description, status, priority,projectId,assigneeId, expiresAt} = req.body
console.log("body ?? :: ",req.body)
if(!taskId || taskId.trim() === ""){
return res.status(404).json({status: 404, message : "taskid required!"})
}
const findTask = await findTaskById(taskId)
if(!findTask) {
return res.status(404).json({status: 200, message : "taskid not found!"})
}
const editNewTask = await editTask(taskId,title, description, status, priority,projectId,assigneeId, expiresAt)
res.status(200).json({status : 200, message: "updated successfull!", editNewTask})
} catch (error) {
console.error("Error in editTaskHandler:", error.message);
next(error)
}
}
const deleteTaskHandler = async(req, res, next) => {
try {
const task_id = req.params.taskId
console.log("paramsid ::", req.params.taskId)
if(!task_id){
return res.status(404).json({
status : 404,
message : "task id is required!"
})
}
await deleteTask(task_id)
return res.status(204).json().send
} catch (error) {
console.error("Error in editTaskHandler:", error.message);
next(error)
}
}
module.exports = {
createProjectHandler,
getProjectByIdHandler,
editProjectHandler,
deleteProjectHandler,
createTaskHandler,
getTaskByIdHandler,
editTaskHandler,
deleteTaskHandler
}
its route file
const express = require("express");
const { authenticationMiddleware } = require("../middleware/auth-middleware");
const {
createProjectHandler,
getProjectByIdHandler,
editProjectHandler,
deleteProjectHandler,
createTaskHandler,
getTaskByIdHandler,
editTaskHandler,
} = require("../controller/todo-controller");
const todoRouter = express.Router();
todoRouter.use(authenticationMiddleware);
//project
todoRouter.post("/project", createProjectHandler);
todoRouter.get("/project/:projectId", getProjectByIdHandler);
todoRouter.put("/project/:projectId?", editProjectHandler);
todoRouter.delete("/project/:projectId", deleteProjectHandler);
//task
todoRouter.post("/project/task/", createTaskHandler);
todoRouter.get("/project/task/:taskId", getTaskByIdHandler);
todoRouter.put("/project/task/:taskId?", editTaskHandler);
todoRouter.delete("/project/task/:taskId?", deleteProjectHandler);
module.exports = todoRouter;
I'm trying to changes the route it's works like for example :
before with method update
http://localhost:3000/api/v1/projects/task/taskid
after with methode update
http://localhost:3000/api/v1/projects/task/:taskId
but when i create a new route with metode delete like
http://localhost:3000/api/v1/projects/task/:taskId
it's not working and the output like that
{
"errors": "Failed to find a project: Project ID is required"
}
help me to best practice to make proper routing
As the middleware is executed in order it is loaded, try moving concrete routes before those with parameters, i.e. move task routes before project:
//task
todoRouter.post("/project/task/", createTaskHandler);
todoRouter.get("/project/task/:taskId", getTaskByIdHandler);
todoRouter.put("/project/task/:taskId?", editTaskHandler);
todoRouter.delete("/project/task/:taskId?", deleteProjectHandler);
//project
todoRouter.post("/project", createProjectHandler);
todoRouter.get("/project/:projectId", getProjectByIdHandler);
todoRouter.put("/project/:projectId?", editProjectHandler);
todoRouter.delete("/project/:projectId", deleteProjectHandler);