Very simple get request yields in error: 'Cast to ObjectId failed' - node.js

So I was testing my backend with postman and have no clue what the heck is going on at the moment. I got a file users.js where I define some of my routes. I import that file into my app.js with:
// Bring in the Users route
const users = require('./routes/api/users');
app.use('/api/users', users);
So all the api requests within users.js are actually going to /api/users/......
I defined a simple route here to test it out.
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.send('hello world')
})
module.exports = router;
So if I send a request with postman to: http://localhost:5000/api/users/ I get back a response: hello world
If I ONLY change the endpoint to something like /test, I get an error message. In other words, If I change the route to:
const express = require('express');
const router = express.Router();
router.get('/test', (req, res) => {
res.send('hello world')
})
module.exports = router;
And again send a request with postman to http://localhost:5000/api/users/test, I get back the following error message:
{
"stringValue": "\"test\"",
"kind": "ObjectId",
"value": "test",
"path": "_id",
"reason": {},
"message": "Cast to ObjectId failed for value \"test\" at path \"_id\" for model \"Project\"",
"name": "CastError"
}
Does anyone have a clue what is going on? I cannot see why this doesn't work...
EDIT:
Okay, so I figured it out, but I still don't know why it works in scenario 1 and doesn't work in scenario 2:
This works:
router.get('/test', (req, res) => {
res.send('hello world')
})
//load project
router.get('/:id', (req, res) => {
Project.findById(req.params.id)
.then(projectFound => {
res.status(200).send(projectFound)
})
.catch(err => {
res.status(500).send(err)
})
})
This doesn't work:
//load project
router.get('/:id', (req, res) => {
Project.findById(req.params.id)
.then(projectFound => {
res.status(200).send(projectFound)
})
.catch(err => {
res.status(500).send(err)
})
})
router.get('/test', (req, res) => {
res.send('hello world')
})

Order to Precedence of Controllers
:id is a variable. When you declare the router.get('/:id', (req, res) first, your test method never gets executed.
This is because :id takes the value of test.
And your code doesn't like the 'test' id, so you get an error.
When you declare the other method first, router.get('/test' is found first, and executed first for any request that is /test. All other requests are forwarded to the :id method.
Answer to Initial Question
var express = require('express')
var app = express()
app.get('/test', function (req, res) {
res.send('HELLO WORLD')
})
Source

I got a file users.js where I define some of my routes.
How are the routes defined?
Given the error message, presumably it is expecting /api/users/{id}, where {id} is a number, not a string like "test".

Related

How to pass request body object to other routes?

Anyone know the solution? When I console log the variable it shows undefined. I need to pass the req.body (name and email) element to second post route which is "/company" route. I have two forms and I want to pass the first form data to second form the "/company" route form. then the two form data will be stored in mongoDb. I tried everything but I got only undefined in second route the "/company" route
import express from "express";
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
//Assign the name and email to variable and sent to last route
const middleware = (req, res, next) => {
const { name, email } = req.body;
let nameNew = name;
let emailNew = email;
// add nameNew and emailNew to req object
// so that it can be access in other routes
req.nameNew = nameNew;
req.emailNew = emailNew;
// console.log(nameNew);
// console.log(emailNew);
next();
};
//Get name email from user input and sent it middleware
app.post("/", middleware, (req, res, next) => {
const { name, email } = req.body;
res.send("Home route");
});
//Get the name and email from middleware
app.post("/company", middleware, (req, res) => {
// console.log(nameNew);
// access req.body without middleware
// console.log(req.body);
// access req.body using middleware
console.log(req.nameNew);
console.log(req.emailNew);
res.send("Company route");
});
//Server running
app.listen(4000, () => {
console.log(`Server Started `);
});
When your request gets into your app.post("/") it sets the nameNew variable inside your middleware scope. You cannot access this variable in your other routes.
If you want to access variables shared from your middleware you can use res.locals : https://expressjs.com/en/api.html#res.locals
You can't pass data from route 1 to route 2 through middleware.
It passes through the middleware and sets the variables but on your res.send theses variable will disappear. These are just set for the "instance" of the incoming request and on res.send will be destroyed.
You would need to send back data to the front-end to pass it back to your API for route 2.
You can call functions from your route definition :
app.get('/getUserInfos', isLoggedIn, (req, res) => {
return getUserInfos(res);
});
This way you can process your data and save it however you want.
Also, looks like you can chain functions there : https://stackoverflow.com/a/62723674/12343548
I use req.app.locals to send the data in first route to second route. Anyone want to do this type of program in future Here is the solution.
const express = require("express");
const app = express();
const path = require("path");
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const middleware = (req, res, next) => {
const { name, email } = req.body;
req.app.locals.nameNew = name;
req.app.locals.emailNew = email;
next();
};
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname + "/index.html"));
});
app.post("/", middleware, (req, res) => {
const { name, email } = req.body;
res.send("Home Route");
});
app.get("/company", (req, res) => {
res.sendFile(path.join(__dirname + "/company.html"));
console.log(req.app.locals.nameNew);
console.log(req.app.locals.emailNew);
});
app.post("/company", (req, res) => {
console.log(req.app.locals.nameNew);
console.log(req.app.locals.emailNew);
res.send("Company Route");
});
//Server running
app.listen(4001, () => {
console.log(`Server Started `);
});

how to make my route to work with my controller in nodejs

I am building an API with NodeJS and express
When ever i visit a route, it will work if its not connected with my controller like for example
router.get("/get", (req, res) => res.send({"data":"Its works"}));
But when ever i add the controller, it will take forever for that route to respond
const controllers = require('./controllers');
router.get("/get", (req, res) => controllers.findAll);
Here is the controller code
const findAll = async (req, res) => {
res.send({ error: "error.message" })
}
module.exports = { findAll }
How can I solve this issue?
Your function is never executed. Change it to pass the controller function instead:
const controllers = require('./controllers');
router.get("/get", controllers.findAll);

In Node/Express, how to fetch the current route handler?

How do I fetch the syntax/name of the current route handler, ignoring the current specific param values?
e.g.:
app.get('/users/:id', (req, res) => {
let route = ?
console.log(route) // --> "/users/:id"
})
(Question 2 - can I do this in a middleware function?)
The correct answer is req.route.path
e.g.
1. Call directly from main file (app.js / index.js):
app.get('/admin/:foo/:bar/:baz', async (req, res) => {
console.log(req.originalUrl);
console.log(req.url);
console.log(req.path);
console.log(req.route.path); // this one is your answer
console.log(req.baseUrl);
console.log(req.hostname);
res.sendStatus(200);
});
API call:
http://localhost:3000/admin/a/b/c
Output
/admin/a/b/c (originalUrl)
/admin/a/b/c (url)
/admin/a/b/c (path)
/admin/:foo/:bar/:baz (route.path)
<nothing> (baseUrl)
localhost (hostname)
2. Call from a module:
app.js
const express = require('express');
const app = express();
...
const users = require('./users');
app.use('/api/users', users);
users.js
const express = require('express');
const router = express.Router();
...
router.get('/admin/:foo/:bar/:baz', async (req, res) => {
console.log(req.originalUrl);
console.log(req.url);
console.log(req.path);
console.log(req.route.path); // this one is your answer
console.log(req.baseUrl);
console.log(req.hostname);
res.sendStatus(200);
});
API call:
http://localhost:3000/api/users/admin/a/b/c
Output
/api/users/admin/a/b/c (originalUrl)
/admin/a/b/c (url)
/admin/a/b/c (path)
/admin/:foo/:bar/:baz (route.path)
/api/users (baseUrl)
localhost (hostname)
You can see below example for information about req object that you get.
/users can be obtained from req.baseUrl and :id can be obtained from req.params.id
app.use('/admin', function (req, res, next) { // GET 'http://www.example.com/admin/new?a=b'
console.dir(req.originalUrl) // '/admin/new?a=b' (WARNING: beware query string)
console.dir(req.baseUrl) // '/admin'
console.dir(req.path) // '/new'
console.dir(req.baseUrl + req.path) // '/admin/new' (full path without query string)
next()
})

On a Node.js server in a GET request response how to output any data about the user in the console?

The goal is to make a simple Node server. Create a GET request with a response "Hello World", but also output any data about the user in the console.
For example, you can create a middleware if you are using ExpressJS:
module.exports = async function (req, res, next) {
req.user = {id: 1, name: "John Doe"}
next()
}
and then add this middleware into your request:
const userMiddleware = require('../middleware/userMiddleware')
router.get("/", userMiddleware, function(req, res) {
console.log(req.user)
})
This is a basic express server that will respond with "Hello World" to any request and console log request object. If you need to log anything in particular, check documentation that lists all of the properties of request object.
const express = require('express');
const app = express();
app.use((req, res) => {
res.send('Hello World');
console.log(req);
});
app.listen(3000);

Error : Cannot set headers after they are sent to the client

When I hit the signup route "req.body" doesn't pick any up any of the POST values, however whenever the same code is tested on Postman - with body raw method - the values display.
const router = require('express').Router();
const bodyParser = require('body-parser');
const Promise = require('bluebird');
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({
extended: true
}));
const registration = require('./services/registration');
router.get('/', (req, res, next) => {
res.send('Admin Welcome');
});
router.get('/signup', (req, res, next) => {
res.render('user/signup');
});
router.post('/signup', (req, res, next) => {
res.send(req.body);
registration.registration(req.body);
.then(ok=>{
res.redirect('signin')
})
.catch(err => {
res.render('error', {message: err})
})
})
router.get('/signin', (req, res, next) => {
res.render('user/signin');
});
original code
router.post("/signup", (req, res, next) => {
res.send(req.body);
registration
.registration(req.body)
.then(ok => {
res.redirect("signin");
})
.catch(err => {
res.render("error", { message: err });
});
});
The res object represents the HTTP response that an Express app sends when it gets an HTTP request. In the following link you can see all the methods that are exposed for res object:
https://expressjs.com/en/api.html#res
Method that you are using at the beginning of you route handler is:
res.send([body])
And as it can be read from the documentation it sends the HTTP response. Now you can send that response only once, otherwise you will get an error:
Error : Cannot set headers after they are sent to the client
And what you are trying to do in the handler is to redirect result to "signin" page afterwards already sending the response with res.send(req.body).
Take this fake route for an example:
router.post("/example", (req, res, next) => {
res.send('1');
res.send('2');
res.send('3');
});
Contrary to what you might believe, it wont return values (1,2,3), but actually return value 1 and raise and error that was previously described.
Finally to solve your issue you need to remove line containing res.send(req.body) and double check if registration.registration service is correctly handling provided data, in this case req.body.

Resources