req.body.caption return null - node.js

I have this code which send what the active user publish into mongodb id of the post + author + author ID + caption(what the author write), the code works perfectly but the problem that this statementcaption : req.body.caption,is keep returning null to mongodb and I really don't know why or how to solve this,
the code of publish is below :
router.post("/publish", function (req, res, next) {
// Generate a random id
User.findById(req.user.id, function (err, user) {
if (!user) {
req.flash('error', 'No account found');
return res.redirect('/login');
} else {
}
user.posts.push({
_id: guid.raw(),
author: user.userName,
authorID: user.id,
caption : req.body.caption,
comments: [],
likes: [],
createdAt: new Date(),
lastEditedAt: new Date()
});
user.save(err => {
if (err) throw err;
console.log("Post saved");
res.redirect("/");
});
});
});
the schema of caption is below :
caption :{type : String}
the ejs part is also below
<input
type="text"
id="caption"
name="caption"
class="form-control"
placeholder="enter your posts"
value="Share your thoughts!"
/>
MongoDB screen
Please some help,
Best Regards,

Your output from console.log(req.body) -- an empty body object -- proves beyond any doubt that no form fields are arriving at your route handler in your post.
It's possible you need to tell express to use a couple of middleware modules to parse the data in the bodies of POST requests. Try putting these two lines in your code somewhere before your call(s) to app.use('/', router).
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
These will make express populate the req.body object with the data from your forms. It chooses JSON or url-encoding based on the Content-Type: header.
Or it's possible your html (ejs) doesn't have your <input...> fields wrapped in your <form....> object. You can tell if this is true by looking at your POST request in the Network tab of your browser. You'll find a section called Form Data if you click on the POST request. If it's empty, your form post sent nothing. If the caption field is empty, that field wasn't wrapped in the <form ...> tag.

Related

Sending a POST Request from a PUG FORM - Can't send data

Pug layout:
html(lang='en')
block login
form(id="login" action="/users" method="post")
input(type="text", name="username", value="", placeholder="Username")
br
input(type="password", name="password", value="", placeholder="Password")
br
input(type="submit" value="Connect")
And my JS code for the post:
router.post('/', (req, res) => {
const user = new User({
username: req.body.username,
password: req.body.password
});
user.save()
.then(data => {
res.json(data);
})
.catch(err => {
res.json({message: err})
})
});
Can't seem to think on how to send the data from the form to the actual post request. It seems like it sends the request but with no information as I get:
{"message":{"errors":{"username":{"name":"ValidatorError","message":"Path `username` is required.","properties":{"message":"Path `username` is required."
Frustrated that I can make the requests in Postman but having a hard time implementing the requests into my app.
Alright apparently my only problem was that I didn't use
router.use(express.urlencoded({
extended: true
}))
Quite frustrating.

Add variable to a URL (node, express)

I'm using node and express. What I want to do is to do is make a mix of res.render and res.redirect.
Thing is, res.render can only receive a .ejs file and data, and redirect will go to a specific URL. What I need to do is go to a specific URL (e.g. /reviews/new/:id), render a .ejs file and give some data to it.
This is my code. I can't use session or cookies for this project.
This are the routes, user enters to edit a review of some show. If it is a new review, the id of the show is in the URL, if the user is editing one, the ID of the review is on the URL. Either way, if something fails, I have to append something to this URL and send data.
router.get('/new/:id', controller.newReview);
router.post('/store', controller.checkBeforeStoringReview);
router.get('/edit/:id', controller.editReview);
router.post('/update', controller.checkBeforeUpdatingReview);
This is the function to check auth before updating.
checkBeforeUpdatingReview: function(req, res) { // auth before updating review (can't use session or cookies)
console.log(req.body)
DB
.User
.findOne(
{
where : {
email: req.body.email,
},
}
)
.then (function (results) {
if (results[0] != '') {
if (bcrypt.compareSync(req.body.password, results.password)) {
return module.exports.updateReview(req, res, results)
} else { // same as catch
return res.render('reviews/edit/', { // i'm missing the ID (which i have in req.params.id) at the end of the route
id : req.params.id,
errors : "Incorrect username or password",
email : req.body.email,
});
}
}
})
.catch (function (error) {
console.log(error)
return res.render('reviews/edit/', { // i'm missing the ID (which i have in req.params.id) at the end of the route
id : req.params.id,
errors : "An unexpected error happened",
email : req.body.email,
});
})
},
If everything's ok, as seen above, it goes directly to this function
updateReview: function(req, res, results) { // update review
console.log(req.body)
DB
.Review
.update(req.body,
{
where : {
id: req.body.review_id,
}
}
)
.then(function (results) {
return res.redirect('/series/detail/' + req.body.series_id)
})
.catch (error => {
return res.send(error)
})
},
TL;DR: If auth fails, should go back to the review url and send the data that was sent so that the user does not lose it.
So that's it, if I could use sessions/cookies I think I would be able to go back to the last route, but I can't for this.
Thanks in advance!

How to write a find query to compare two fields in Express and MongoDB?

I want to compare two fields using Express. I have tried my best but I am getting errors.
I have enclosed my schema, routes, and controller. These are API calls and I want to know how to pass two fields from AngularJS $http.get method. I have enclosed my AngularJS controller with the API call also
Schema:
var PromusageSchema = new Schema({
StoreID: {
type: String,
default: '',
trim: true
},
StoreName: {
type: String,
default: '',
trim: true
},
});
mongoose.model('Promusage', PromusageSchema);
Controller
exports.promusageByEMAIL = function(req, res, next, id) {
Promusage.find({customer_Email:id})
.populate('user', 'displayName')
.exec(function(err, promusage) {
if (err) return next(err);
if (!promusage) return next(new Error('Failed to load Promusage ' + id));
req.promusage = promusage;
next();
});
};
Routes
app.route('/promusages1/:promusageEmail')
.get(promusages.read)
.put(promusages.update)
.delete(promusages.delete);
// Finish by binding the Promusage middleware
app.param('promusageEmail', promusages.promusageByEMAIL);
If you're trying to send information to an API, you should be using $http.post or similar. $http.get is for retrieving data, not sending data.
That said, it looks like you're actually trying to get information from the API. However, your GET request doesn't appear to be mapped to a usable function. Should this: .get(promusages.read) be this: .get(promusages.find) in your routes?
That's the only function you've defined. Although it's hard to tell since I'm not really sure what Promusage is here.

Node.js API / server post request

I started Node.js and general web few times ago and now I have a project where I have to develop a web server with an API in nodejs running on Express and I want to do it properly but I'm not sure if there's a the good way to do it.
It concerns about every post requests I'm sending to my API, here's an example :
Sign up :
I have a route app.get('/signup') and I'm sending a post request to my API to create new user. So with my guess I send a form with action = /signup method = "post" which means that on my server I've app.post('/signup'). In this post, I create a post request with all the information in my form and I send it to my API which creates the user and send back to the app.post('/signup') the answer. So basically, here the schema:
Get('/signup') -> Post('/signup') -> API('createUser') -> Post('signup')
Then I would like to go back to my app.get('/signup'), because I don't want to send html form the post one, and say "Hey it's ok" instead of showing the form so i'm doing a redirect but how could I know what to display in Get('/signup') ? Can I send a variable to know what to show to the user ? And btw, is it the proper way to do it ?
Thanks !
PS : it doesn't look very clear so here the code :
app.get('/signup', function(req, res) {
res.setHeader('Content-Type', 'text/html');
if (req.session.userId) { res.end("Connected as " + req.session.name); }
else {
res.end('<html><p>As a guest, you\'re signing up : </p><form action="/signup" method="post">' +
'First name: <input type="text" name="firstname"><br>' +
'Last name: <input type="text" name="lastname"><br>' +
'email: <input type="text" name="email"><br>' +
'password: <input type="text" name="password"><br>' +
'role: <input type="text" name="role"><br>' +
'<input type="submit" value="Submit">' +
'</form></html>');
}
});
app.post('/signup', function(req, res) {
request.post({
url: 'http://localhost:4242/signup',
form : {
firstname : req.body.firstname,
lastname : req.body.lastname,
email : req.body.email,
role : req.body.role,
password : req.body.password
}},
function (error, response, body) {
res.redirect('/signup');
});
});
Is it the good way to do it ?
Is there another way to send variable from post to get except the session variable ? (with the redirect) ?
I'm not sure I fully understand the question, but this is how I handle form submits with node.js.
Submit the form using jQuery/Ajax, so we can then get a response from the server after the POST.
$('#your-form').on('submit', function(e) {
e.preventDefault();
var formData = $(this).serializeArray();
$.ajax({
type: 'POST',
url: '/signup',
data: formData
}).success(function(response) {
if (response.success == '1') {
// Do something
} else {
// Do something - e.g. display an error message
}
});
});
Then on your Node.js server, you can handle the app.post('/signup') request, and once you're finished with your API calls, return a status message:
res.json({message: 'User created successfully.', success: '1'});
You can then use this JSON response to take the appropriate action.

Sending JSON error from Node.js backend to iPhone frontend: "Error: Can't set headers after they are sent."

I'm new to Node.js. I'm using it as a server backend to an iPhone client. I'm calling a POST with the JSON: {firstname: "bob", email : bob#someemail.com}
The node.js code looks like this (using Express and Mongoose):
var User = new Schema({
firstname : { type: String, required: true}
, email : { type: String, required: true, unique : true}
});
var User = mongoose.model('User', User);
And for the POST,
app.post('/new/user', function(req, res){
// make a variable for the userData
var userData = {
firstname: req.body.firstname,
email: req.body.email
};
var user = new User(userData);
//try to save the user data
user.save(function(err) {
if (err) {
// if an error occurs, show it in console and send it back to the iPhone
console.log(err);
res.json(err);
}
else{
console.log('New user created');
}
});
res.end();
});
Right now, I'm trying to create duplicate users with the same email. I expect this to throw an error due to the "unique" constraint I have on the email -- which it does.
However, the node.js process dies with, "Error: Can't set headers after they are sent."
I would like to be able to send a message back to the iPhone client in scenarios such as these. For example, in the above, I'd like to be able to send back JSON to the iphone saying the result of the new user creation (successful or failed).
Thank you!
It's because the asynchronous nature of your code. The res.end() runs before the callback function of user.save you should put the res.end()inside that callback ( at the end).
this way:
user.save(function(err) {
if (err) {
// if an error occurs, show it in console and send it back to the iPhone
console.log(err);
return res.json(err);
}
console.log('New user created');
res.end();
});
Send your error using an appropriate http status, you have plenty of 4xx to do that.
res.json(420, err);
That way, you will just have to parse the message in your http fetch, with jquery it gives something like :
jQuery.ajax({
...
error: function (xhr, ajaxOptions, thrownError) {
if(xhr.status == 420) {
JSON.parse(xhr.responseText);
}
}

Resources