Express Not able to get request body value - node.js

I am trying to learn the MEAN stack by following a tutorial for CRUD operations using REST Api with express and mongoose. I am able to run the GET and DELETE operations but I am not getting the POST and PUT operations because I am not getting the required request body values.
router.post('/', function (req, res, next) {
var todoObject = {
name: req.body.name
};
Todo.create(todoObject, function (err, todo) {
if (err) res.send(err);
Todo.find(function (err, todos) {
if (err) res.send(err);
res.json(todos);
});
}); });
As you can see from the code that I am setting the name parameter of the json object using the request body value which I pass through POSTMAN. A new document is getting created but the name value is unset in the database.
However, giving the name directly works. Please help me.

the simplest and safest way is to send JSON object from the client using RAW data.
so ,to implement it follow the steps below:
Set the Content/type to application/json in the Headers
Select raw type and put your JSON object in the Body
And finally Your code should be like:
router.post('/', function (req, res, next) {
var todoObject = req.body;
Todo.create(todoObject, function (err, todo) {
if (err) res.send(err);
Todo.find(function (err, todos) {
if (err) res.send(err);
res.json(todos);
});
});
});

You need to use Content-Type: application/json in Headers if it is with JSON format.

Related

Redirect and Render using Express

When I hit my api I want to redirect my url from https://myapp.herokuapp.com/token/aaa.bbb.ccc to https://myapp.herokuapp.com/messages/:id. I also want to render my message view
Code:
app.get('/token/:id' , (req, res) => {
var decoded = jwt.verify(req.params.id, 'blabla');
Message.findById(decoded.messageId, (err, message) => {
if (err) res.json({error: err})
res.render('message', {message})
})
})
Here, I successfully render my message view but the URL for the below api is still https://myapp.herokuapp.com/token/aaa.bbb.ccc and not https://myapp.herokuapp.com/messages/:id
Another attempt:
app.get('/token/:id' , (req, res) => {
var decoded = jwt.verify(req.params.id, 'blabla');
Message.findById(decoded.messageId, (err, message) => {
if (err) res.json({error: err})
res.redirect('/messages/'+message._id)
})
})
Now, the URL is https://myapp.herokuapp.com/messages/:id but the message view is not rendered. A JSON is rendered that displays the message
How do I redirect to https://myapp.herokuapp.com/messages/:id and also render the message view?
You should first redirect:
app.get('/token/:id' , (req, res) => {
var decoded = jwt.verify(req.params.id, 'blabla');
Message.findById(decoded.messageId, (err, message) => {
if (err) return res.json({error: err}); // see #partycoder's answer
res.redirect('/messages/'+message._id)
})
})
Next, you need to adjust the route handler for /messages/:id. Right now, it sounds like it's only used for XHR requests, so it will always return JSON. You can add a check to see if the request is an XHR-request or not, and either return JSON (for XHR) or a rendered template (for non-XHR):
app.get('/messages/:id', (req, res) => {
...
if (req.xhr) {
return res.json(...);
} else {
return res.render(...);
}
});
(documentation for req.xhr, be aware that the method on which this is based is not foolproof)
However, perhaps it's better to use content negotiation, where the client explicitly tells your server what format the response should be. The upside of this is that it's much more explicit, the downside is that you may have to change some client-side code. Documentation here: http://expressjs.com/en/4x/api.html#res.format

NodeJs: Sending picture with Express (Multer)

I have this code
app.get('/imgs/:id', function(req, res) {
// Validate that req.params.id is 16 bytes hex string
// Get the stored image type for this image
var stream = fs.createReadStream(path.join(UPLOAD_PATH, req.params.id));
stream.on("readable", function() {
res.setHeader('Content-Type', "image/jpeg")
stream.pipe(res)
})
stream.on('error', (e) => {
res.redirect(404, "404")
})
});
Now the problem is that I always get an error of
Error: Can't set headers after they are sent.
because I used the res.setHeader function.
However, i don't know how to solve it. Let's say I want to use in a page, that has obviously the res.send() function has well,
the <img src="imgs/pic">, then I must set the header for the this page request to "image/jpeg" because otherwise the browser wouldn't know it's an image and won't show it as one.
What can I do then?
Check Express response document here. Try this code
app.get('/imgs/:id', function (req, res) {
res.sendFile(req.params.id, {root: UPLOAD_PATH, headers: {'Content-Type': 'image/jpeg'}}, function (err) {
if(err) throw err;
else console.log('sent')
})
})

Express.js Routing error: Can't set headers after they are sent

I'm not really sure why I'm getting this error. It's a simple API built on express.js to be able to add and remove posts. The error occurs when I trigger the delete router. I've read that the error typically happens when there are two callbacks, however, I don't seem to be able find any double callbacks.
_http_outgoing.js:344
throw new Error('Can\'t set headers after they are sent.');
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
at ServerResponse.header (/Users/bounty/Projects/_learning/react-express/node_modules/express/lib/response.js:718:10)
at ServerResponse.send (/Users/bounty/Projects/_learning/react-express/node_modules/express/lib/response.js:163:12)
at ServerResponse.json (/Users/bounty/Projects/_learning/react-express/node_modules/express/lib/response.js:249:15)
at /Users/bounty/Projects/_learning/react-express/server/routes/posts.js:86:9
at nextTickCallbackWith0Args (node.js:452:9)
at process._tickCallback (node.js:381:13)
Here is my posts.js router:
module.exports = function(router) {
var Post = require('../models/post.js');
// middleware for the api requests
router.use(function(req, res, next) {
// do logging
console.log('something is happening.');
next(); // make sure we go to our next route and don't stop here
});
// test route to make sure everything is working (accessed at GET http://localhost:8080/api)
router.get('/', function(req, res) {
res.json({ message: 'hooray! welcome to our api!' });
});
// all routes here
// routes that end in /posts
router.route('/posts')
// create a Post (accessed at POST http://localhost:7777/api/posts)
.post(function(req, res) {
var post = new Post();
post.postTitle = req.body.postTitle; // set the post name (comes from request)
// save post and check for errors
post.save(function(err) {
if (err)
res.send();
res.json({ message: 'post created!' });
});
})
// get all Posts (accessed at GET http://localhost:7777/api/posts)
.get(function(req, res) {
Post.find(function(err, posts) {
if (err)
res.send();
res.json(posts);
});
});
// routes that end in /posts for specific id
router.route('/posts/:post_id')
// get the post with that id
.get(function(req, res) {
Post.findById(req.params.post_id, function(err, post) {
if (err)
res.send(err);
res.json(post);
});
})
// update the post with that id
.put(function(req, res) {
Post.findById(req.params.post_id, function(err, post) {
if (err)
res.send(err);
post.postTitle = req.body.postTitle;
// save the post
post.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'post updated!' });
});
});
})
// deletes the post with that id
.delete(function(req, res) {
Post.remove({
_id: req.params.post_id
}, function(err, post) {
if (err) {
res.send(err);
}
res.json({ message: 'post deleted!' });
});
});
}
You need to add the 'return' so that you don't reply twice.
// save post and check for errors
post.save(function(err) {
if (err) {
return res.send();
}
res.json({ message: 'post created!' });
});
That particular error message is pretty much always caused because of a timing error in the handling of an async response that causes you to attempt to send data on a response after the response has already been sent.
It usually happens when people treat an async response inside an express route as a synchronous response and they end up sending data twice.
One place I see you would get this is in any of your error paths:
When you do this:
// save post and check for errors
post.save(function(err) {
if (err)
res.send();
res.json({ message: 'post created!' });
});
If post.save() generates an error, you will do res.send() and then you will do res.json(...) after it. Your code needs to have a return or an else so when there's an error you don't execute both code paths.
So, this can happen in Express when attempting to send res.end twice which res.send and res.json both do. In your if(err) block you'll want to return res.send() as res.send runs asynchronously and res.json is getting called as well. I'm wondering if you're getting an error in your delete route? Hope this helps.
Best!
You are using res.send() or res.json() twice in the same request
this send the headers first, followed by body of the response and then headers again.
req.next is usually not a function, next is rather passed as a third argument of the middleware. Use that if you want to drop to the next middleware. (assuming you are using Express framework)
Just for the sake of completeness I will also mention that:
Sometime problem may be in a the middleware you may be using by calling
app.use.
After checking for obvious errors as mentioned in previous answers:
You should remove all the app.use statement then reintroduce them one by one, to find problematic module.
If you are using res.send() inside any loop, then you need to break it after the use of res.send(). So that it won't allow resetting of the res headers again and again.
for e.g :
for(){
if(){
res.send();
break;
}
else(){
res.send();
break;
}
}
In my case this is the problem and I solved it like this.
Hope it may help someone in future.
Thanks
For a quick fix you can just check res.finished before calling res.send():
if (!res.finished)
res.send()

Deleting a topic in node with mongoose

I am working on a project with node, express, mongo. I am trying to delete a topic.
This is my code:
router.get('/:id/delete', function(req, res, next){
var topicId = req.params.id;
console.log('Logging topic id: ' + topicId);
Topic.findById(topicId, function(err, topic)
{
if(err)
{
console.log('There was no topic with this ID');
return next(err)
}
else
{
Topic.remove(topicId, function(err){
res.render('/mytopics');
console.log('Topic deleted successfuly');
});
}
});
});
The thing is it won't even come into the first console log where I am logging the topic id. So I am wondering if my query is built right?
In RESTful API structure the delete route should expect DELETE request. Try out following code:
router.delete('/:id/delete', function(req, res, next) {
// ...
For additional resources about this issue be sure to check out:
Recommended way to delete object in MongoDB based on a route

404 error trying to load MEAN web app

So I'm trying to set up a basic Todo list/CRUD application using the MEAN stack (Angular, MongoDB, Nodejs, Express) and I keep running into trouble when I switch around the routes and models in the directory and try to load up the application via node server on my command prompt. When I move anything the error below is what I get via a command prompt error. Just an FYI, I'm a total NOOB.
App listening on port 3000
GET /api/todos 404 2ms
GET /api/todos 500 7ms - 1.36kb
ReferenceError: Todo is not defined
at app.delete.Todo.remove._id (C:\Users\Basel\WebstormProjects\TEST\node-tod
o-tut1-starter\server.js:41:3)
at callbacks (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\no
de_modules\express\lib\router\index.js:164:37)
at param (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\node_m
odules\express\lib\router\index.js:138:11)
at pass (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\node_mo
dules\express\lib\router\index.js:145:5)
at Router._dispatch (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-sta
rter\node_modules\express\lib\router\index.js:173:5)
at Object.router (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starte
r\node_modules\express\lib\router\index.js:33:10)
at next (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\node_mo
dules\express\node_modules\connect\lib\proto.js:193:15)
at Object.methodOverride [as handle] (C:\Users\Basel\WebstormProjects\TEST\n
ode-todo-tut1-starter\node_modules\express\node_modules\connect\lib\middleware\m
ethodOverride.js:48:5)
at next (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\node_mo
dules\express\node_modules\connect\lib\proto.js:193:15)
at multipart (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\no
de_modules\express\node_modules\connect\lib\middleware\multipart.js:86:27)
app.post('/api/todos', function(req, res) {
// create a todo, information comes from AJAX request from Angular
Todo.create({
text : req.body.text,
done : false
}, function(err, todo) {
if (err)
res.send(err);
// get and return all the todos after you create another
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});
});
// delete a todo
app.delete('/api/todos/:todo_id', function(req, res) {
Todo.remove({
_id : req.params.todo_id
}, function(err, todo) {
if (err)
res.send(err);
// get and return all the todos after you create another
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});
});
// application -------------------------------------------------------------
app.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});
(Assuming you send correct _id from client) you have to reconstruct the _id as BSON object.
Do not know what db-driver you use, but in mongoskin it goes like that:
var mongo = require('mongoskin');
var BSON = mongo.BSONPure;
...
var proper_id = BSON.ObjectID(req.params.todo_id)
In mangoose try following:
var todo = Todo.find({_id : req.params.todo_id});
todo.remove(callback(err, todo)); // callback is optional

Resources