Node.js route sends to the incorrect controller - node.js

Problem: When I call this route /topproducts it enters in the orders_get_order function and not in the orders_most_ordered_products. This is very strange I can't understand why it enters in the wrong function.
The console error message:
message: 'Cast to ObjectId failed for value "topproducts" at path "_id" for model "Order"',
name: 'CastError',
stringValue: '"topproducts"',
kind: 'ObjectId',
value: 'topproducts',
path: '_id',
reason: undefined,
model: Model { Order }
My route.js
router.get("/topproducts", checkAuth, OrdersController.orders_most_ordered_products);
My controller order.js
exports.orders_most_ordered_products = async (req, res) => {
try{
let order = await order_service.get_most_ordered_products();
if ('error' in order){
res.status(order['status']).json(order)
}else{
res.status(200).json(order)
}
}catch(err){
console.log("most orders")
console.log(err)
//res.status(500).json(fatal_error_status);
}
};
//get uma order
exports.orders_get_order = async (req, res) => {
try{
let order = await order_service.get(req.params.orderId);
if ('error' in order){
res.status(order['status']).json(order)
}else{
res.status(200).json(order)
}
}catch(err){
console.log("get orders")
console.log(err)
//res.status(500).json(fatal_error_status);
}
};
And then it sends to the service order.js
exports.orders_most_ordered_products = async (req, res) => {
try{
let order = await order_service.get_most_ordered_products();
if ('error' in order){
res.status(order['status']).json(order)
}else{
res.status(200).json(order)
}
}catch(err){
console.log("most orders")
console.log(err)
}
};
exports.orders_get_order = async (req, res) => {
try{
let order = await order_service.get(req.params.orderId);
if ('error' in order){
res.status(order['status']).json(order)
}else{
res.status(200).json(order)
}
}catch(err){
console.log("get orders")
console.log(err)
}
};

The problem was the order of the routes, the route that takes an Id as a parameter was first so the server though I was calling that one.
router.get("/topproducts", checkAuth, OrdersController.orders_most_ordered_products);
router.get("/:orderId", checkAuth, OrdersController.orders_get_order);

Related

How to pass data from express-validation middleware to next function?

I have an express app that looks like this.
const app = require('express')();
// Task model
const Task = require('./models/Task');
const { param, validationResult } = require('express-validator');
const getTaskValidations = [
param('id')
.custom(async (id, { req }) => {
try {
const task = await Task.findOne({ _id: id, user: req.user.id });
if (!task) Promise.reject('Task not found');
} catch (err) {
// Handle error
}
})
]
const validate = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(401).json({ message: errors.array()[0].msg });
}
next();
}
// Get Task by id
app.get('/tasks/:id', getTaskValidations, validate, async (req, res) => {
try {
const task = await Task.findById(req.params.id);
res.json(task)
} catch (err) {
// Handle err
}
})
I want to get the task by id. In GET tasks/:id the req.params.id will contain the id of the task.
The Task Model looks like this
{
id:
task:
user:
}
By looking at the endpoint it is clear that I'm passing two middlewares.
The first middleware getTaskValidations will check if the task will given id and req.user exists.
The second middleware validate will check for errors.
And then again will query database for task and send data to the client causing 2 database queries.
How can I reuse the same task obtained in the getTaskValidations middleware.
you can add result of query add to the req.body.task like this
const getTaskValidations = [
param('id')
.custom(async (id, { req }) => {
try {
const task = await Task.findOne({ _id: id, user: req.user.id });
req.body.task = task
if (!task) Promise.reject('Task not found');
} catch (err) {
// Handle error
}
})
]
in controller
app.get('/tasks/:id', getTaskValidations, validate, async (req, res) => {
try {
let {task} = req.body
res.json(task)
} catch (err) {
// Handle err
}
})
You can store the response you get from the query in the request(req).
const task = await Task.findOne({ _id: id, user: req.user.id });
if (task)
req.task = task;
else
Promise.reject('Task not found');
Later on, in the API endpoint, you can simply use
app.get('/tasks/:id', getTaskValidations, validate, async (req, res) => {
try {
const task = req.task;
res.json(task)
} catch (err) {
// Handle err
}
});
to get the task obtained in the getTaskValidations middleware.

req.params returns undefiened

I'm trying to get back the ID from the params but it keeps sending back undefiened, what would be the problem here and how can i solve it ?
this is the route:
app.delete(`${api_version}/delete-branch/:id`, verifyToken, branches.deleteBranch)
this is the controller:
exports.deleteBranch = (req, result) => {
const {branch_id} = req.params
console.log(branch_id) // => returns undefined
if(branch_id === undefined) {
result.status(404).send({
message: 'This branch does not exist',
statusCode: 404
})
} else {
// console.log(req.params)
Branches.deleteBranch(branch_id, (err, data) => {
if (err) {
result.status(500).send({
message: err.message
})
} else {
result.status(200).send({
message: 'Branch deleted successfully',
statusCode: 200,
data
})
}
})
}
}
You need to destruct req.params like this:
const {id} = req.params
instead of:
const {branch_id} = req.params
Or either defined the route as follow:
app.delete(`${api_version}/delete-branch/:branch_id`, verifyToken, branches.deleteBranch)
and then destruct const {branch_id} = req.params;

'req.params.id' is only accessed by first two middleware functions, but not the third. Why?

Here is the code snippet in index.js:
const { loginRequired, ensureCorrectUser } = require("./middlewares/auth");
const tasks = require("./routes/task");
app.use("/api/tasks/:id", loginRequired, ensureCorrectUser, tasks);
Here, only loginRequired and ensureCorrectUser can access the :id, but tasks can't...
Here is the code snippet from the router:
const { getTasks, addTask } = require("../handlers/task");
const router = express.Router();
router.route("/").get(getTasks).post(addTask);
module.exports = router;
auth.js:
exports.loginRequired = function (req, res, next) {
try {
let token = req.headers.authorization.split(" ")[1];
jwt.verify(token, process.env.SECRET_KEY, function (err, decoded) {
if (decoded) {
return next();
} else {
return next({
status: 401,
message: "Please login first",
});
}
});
} catch (err) {
return next({
status: 401,
message: "Please login first",
});
}
};
exports.ensureCorrectUser = function (req, res, next) {
try {
let token = req.headers.authorization.split(" ")[1];
jwt.verify(token, process.env.SECRET_KEY, function (err, decoded) {
if (decoded && decoded.id === req.params.id) {
console.log(req.params.id); //prints correct id
return next();
} else {
return next({
status: 401,
message: "Unauthorized!",
});
}
});
} catch (err) {
return next({
status: 401,
message: "Unauthorized!",
});
}
};
handler snippet:
exports.getTasks = async function (req, res, next) {
await db.User.findById(req.params.id)
.then((data) => {
console.log(req.params); //prints empty object
res.status(200).json([...data.tasks]);
})
.catch((err) => next(err));
};
exports.addTask = async function (req, res, next) {
try {
let user = await db.User.findById(req.params.id);
console.log(req.params); //prints empty object
user.tasks.push(req.body);
await user.save();
return res.status(200).json({ message: "Task Added!" });
} catch (err) {
next(err);
}
};
Why is it so..? Please help..
This thing worked finally. But it's quite messy.
router
.route("/:id")
.get(loginRequired, ensureCorrectUser, getTasks)
.post(loginRequired, ensureCorrectUser, addTask);
router.delete("/id/:id2", loginRequired, ensureCorrectUser, removeTask);
router.post("/id/complete/:id2", loginRequired, ensureCorrectUser, setComplete);

Cast to ObjectId failed for value ... at path "_id" for model but I am not doing any query

I have an express route that gets call with axios from the frontend. The thing is, not matter what I put into the route I always get the same error:
"Cast to ObjectId failed for value "getTodosMisProductos" at path "_id" for model "local""
I'm not doing any query to mongoose in that route but in any other route where I make a query everything works fine.
I've checked the middleware but there is not any query to mongoose
getTodosMisProductos
router.get("/getTodosMisProductos", auth, async (req, res) => {
/*
try {
const data = await Local.findOne({ user: req.user.id }).populate("products.producto");
console.log(data);
if (!data) {
return res
.status(404)
.json({ errors: [{ msg: "No se encontro el local" }] });
}
return res.status(200).json(data.products);
} catch (error) {
console.log(req.user.id);
console.error("error en llamado");
return res.status(500).send("Server Error");
}
*/
console.log("algo");
return res.status(200).json({ msg: "success" });
});
the code commented is the code I need to use, I changed it for testing purposes but even with that simple new code I get the same error.
auth middleware
const jwt = require("jsonwebtoken");
const config = require("config");
module.exports = function (req, res, next) {
// Get token from header
const token = req.header("x-auth-token");
// Check if not token
if (!token) {
return res
.status(401)
.json({ msg: "No tienes autorización para hacer esto" });
}
// Verify token
try {
const decoded = jwt.verify(token, require("../config/keys").jwtSecret);
req.user = decoded.user;
next();
} catch (error) {
res.status(401).json({ msg: "El token es inválido" });
}
};
action from where the route gets called
export const getAllProductos = () => async (dispatch) => {
try {
console.log("Esto se llama");
const res = await axios.get("/api/local/getTodosMisProductos/");
dispatch({
type: SET_PRODUCTS,
payload: res.data,
});
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, "danger")));
}
}
};
The response status is always 500 (Internal Server Error)
EDIT
//#route GET api/local/:id
//#desc obtener local por id
//#access private
router.get("/:id", auth, async (req, res) => {
try {
const local = await Local.findById(req.params.id);
if (!local) {
return res
.status(404)
.json({ errors: [{ msg: "No se encontro el local" }] });
}
return res.status(200).json(local);
} catch (error) {
console.error(error.message);
res.status(500).send("Server Error");
}
});
You have another route that also match /api/local/getTodosMisProductos/
Apparently it got matched with /api/local/:id,
where you get req.params.id = "getTodosMisProductos" and got passed down to await Local.findById(req.params.id)
And mongoose can't convert "getTodosMisProductos" to ObjectId, hence the error.
The order in which you declare the route affects the matching priority.
The order is first comes first serves, so make sure you declare /api/local/addProducto or any other routes that starts with /api/local/ before declaring /api/local/:id

Why does my register user post request fail with a 500 error?

I'm building an app with React and Node/Express, and I'm having trouble with my register user function. The data I am passing in is correct, and other endpoints work fine. The register one keeps returning a 500 error and I can't figure out why.
This is my request:
console.log(values)
axios
.post(
'https://foodtrackr-backend.herokuapp.com/api/register',
values
)
.then(res => {
console.log('res.data', res.data);
})
.catch(error => {
console.log('nope');
console.error(error);
});
};
and this is my endpoint:
router.post('/register', async (req, res) => {
let user = req.body;
const newUser = await Users.add(user);
try {
if (newUser) {
res.status(201).json(user);
} else res.status(404);
} catch (error) {
res.status(500).json('noooooo');
}
});
and this is my model:
function findById(id) {
return (
db('users')
.where({ id })
.first()
);
}
async function add(user) {
const [id] = await db('users').insert(user, 'id');
return findById(id);
}
Any help would be appreciated!

Resources