The body of the request being sent is empty according to req.body in my express route.
My main node file is as follows -
var express = require('express');
var bluebird = require('bluebird')
const bodyParser = require('body-parser');
const cors = require('cors');
/*initializations*/
global.mongoose = require('mongoose');
mongoose.Promise = bluebird
global.app = express();
global.config = require('./config/config');
global.jwt = require('jsonwebtoken');
app.use(bodyParser.json({ type: 'application/json' }))
app.use(bodyParser.urlencoded({ extended: true }));//accept strings, arrays and any other type as values
app.disable('x-powered-by');
require('./routes/auth.routes');
//DB connection
app.listen(config.port, function(){
console.log("Express started on " +config.base_url +' in '+config.env +' environment. Press Ctrl + C to terminate');
mongoose.connect(config.db.uri, config.db.options)
.then(()=> { console.log(`Succesfully Connected to the Mongodb Database at URL : `+config.db.uri)})
.catch((error)=> { console.log(error)})
});
The auth.routes file has the signup route and this is where the req.body is empty but it does not hit the if statement that checks, but when i console.log(re.body), it gives me that - {}
app.post('/signup', function(req,res,next){
if (!req.body||req.body=={}){
return res.status(400).send("Bad Request")
}
var user = new User(req.body);
user.password = bcrypt.hashSync(req.body.password, 10);
User.create(user, function(err,new_user){
if (err) {
console.log('A Big Error');
return res.status(500).send("There was a problem registering the user.")
}
//success code
})
});
And the request from the angular 4 app is
signup(user:User):Observable<boolean>{
return this.http.post(this.signup_url,JSON.stringify(user),
{
headers: new HttpHeaders().set('Accept', "application/json;q=0.9,*/*;q=0.8").set('Content-Type', "x-www-form-encoded")
})
.map((response: Response) => {
if(response){
if(response.json() && response.json().token&&response.json().user&&response.json().expires){
this.setSession(response.json());
return true;
}
else{
return false;
}
}
else{
return false;
}
});
}
I am certain the Angular 4 app is sending the right data to the server and that its not empty - checked chromes network request body.
I have tried the following links but none worked.
Express app empty request body with custom content type headers
Express receiving empty object
Node.js: Receiving empty body when submitting form.
Also tried with postman and the result is the same - which means the problem is from the express server and not the client side.
There is no need to stringify the posted data, the body-parser middleware will be responsible for parsing the data into object:
return this.http.post(this.signup_url, user, { ... }).map( ... );
One other thing, In the post handler, you might want to use .save() method instead of .create() because you already create a model instance, Remember that the .save() method is available on the model instance, while the .create() is called directly from the Model and takes the object as a first parameter
Example with .save() method:
app.post('/signup', function(req,res,next) {
if (!req.body){
return res.status(400).send("Bad Request");
}
var user = new User(req.body);
var salt = bcrypt.genSaltSync(saltRounds);
user.password = bcrypt.hashSync(req.body.password, salt);
user.save(function( err ) {
if (err) {
console.log('A Big Error');
return res.status(500).send("There was a problem registering the user.");
}
//success code
res.json({ success: true });
})
});
Example with .create() method:
router.post('/signup', function(req,res,next){
if (!req.body){
return res.status(400).send("Bad Request")
}
var salt = bcrypt.genSaltSync(saltRounds);
req.body.password = bcrypt.hashSync(req.body.password, salt);
User.create ( req.body, function( err, new_user) {
if (err) {
console.log('A Big Error');
return res.status(500).send("There was a problem registering the user.")
}
//success code
res.json({ success: true });
});
});
Related
I'm currently learning angular and working on a project with a mongoDB database and express for my APIs. I want to fetch the comments of a post by the post ID,
The get request returns me a list of comments. the problem is when I first run node js the get request doesn't work, it only works when I first post a new comment and then run the get request for the comments again.
And as long as node is running the get request will continue to work whenever it's called for, until I restart node once again for the error to happen again.
it returns a 404 not found error.
This error doesn't happen with any other route, but my code is the same in all of them.
PS : I Have made sure that the function is getting the post id before the get request is made.
this is my server.js file
let express = require('express'),
path = require('path'),
mongoose = require('mongoose'),
cors = require('cors'),
bodyParser = require('body-parser'),
dbConfig = require('./database/db');
//create Error definition
const createError = require('http-errors');
// Connecting with mongo db
mongoose.Promise = global.Promise;
mongoose.connect(dbConfig.db, {
useNewUrlParser: true
}).then(() => {
console.log('Database sucessfully connected')
},
error => {
console.log('Database could not connected: ' + error)
}
)
const userRoute = require('./routes/user.route');
const postRoute = require('./routes/post.route');
const galleryRoute = require('./routes/Gallery.route');
const likeRoute = require('./routes/Like.Route');
const commentRoute = require('./routes/Comment.route');
const shareRoute = require('./routes/Share.route');
const profilePicRoute = require('./routes/ProfilePic.route');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cors());
app.use(express.static(path.join(__dirname, 'dist/mean-stack-crud-app')));
app.use('/', express.static(path.join(__dirname, 'dist/mean-stack-crud-app')));
app.use('/api/users', userRoute);
app.use('/api/posts', postRoute);
app.use('/api/likes', likeRoute);
app.use('/api/profilePics', profilePicRoute);
app.use('/api/comments', commentRoute);
app.use('/api/shares', shareRoute);
app.use('/api/gallery', galleryRoute);
// Create port
const port = process.env.PORT || 4000;
const server = app.listen(port, () => {
console.log('Connected to port ' + port)
})
// Find 404 and hand over to error handler
app.use((req, res, next) => {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
console.error(err.message); // Log error message in our server's console
if (!err.statusCode) err.statusCode = 500; // If err has no specified error code, set error code to 'Internal Server Error (500)'
res.status(err.statusCode).send(err.message); // All HTTP requests must have a response, so let's send back an error with its status code and message
});
this is my commentRoute.js
const express = require('express');
const commentRoute = express.Router();
// Comment model
let Comment = require('../models/Comment');
const createError = require('http-errors');
//multer for pic upload
const uploadMedia = require('../middleware/picUpload')
// Add Comment
commentRoute.route('/create').post((req, res, next) => {
// if(req?.files[0]){
// newComment.media = req?.files[0]
// }
let newComment = req.body;
newComment.creationDate = new Date(req.body.creationDate)
console.log(newComment)
Comment.create(newComment, (error, data) => {
// if (error instanceof multer.MulterError ) {
// error.message += "\nmulter Error";
// return next(error)
// }else
if (error){
return next(error)
}
else {
res.json(data);
}
})
//Get comments by parent ID
commentRoute.route('/read/byParentId/:idParent').get( async (req, res, next) => {
await Comment.find({idParent : req.params.idParent}, (error, data) => {
if(error){
return next(error)
}else{
res.json(data)
}
})
})
})
module.exports = commentRoute;
this is my mongoose comment schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Define collection and schema
let Comment = new Schema({
idUser: {
type : String
},
idParent : {
type : String
},
text : {
type : String
},
media : {
fieldname : { type : String },
originalname : { type : String },
encoding : { type : String },
mimetype : { type : String },
buffer : { type : Buffer },
},
creationDate : {
type : Date
}
},
{
collection: 'comments'
})
module.exports = mongoose.model('Comment', Comment);
this is my client side http get request
baseUrl = 'http://localhost:4000/api/comments';
headers = new HttpHeaders().set('Content-Type', 'application/json');
constructor(private http : HttpClient) { }
getCommentsByParentId(idParent : any){
return this.http.get(`${this.baseUrl}/read/byParentId/${idParent}`);
}
this is how I consume the api in the client side
getComments(){
this.commentService.getCommentsByParentId(this.idPost).subscribe({
next : (res : any) => {
this.comments = res
this.commentsCount = res.length
},
error : (err : any) => {
console.log("error getting comment list for post "+this.idPost)
}
})
}
client side error :
server side error :
thank you.
Edit :
post without the list of comments before I post a new comment
post after I post a new comment
Well, that's very obvious that the server can't find the entity in the DB.
You need to check one of the following:
Maybe when you restart the node server, you restart the db too. that can happen if you're using docker-compose locally. then when you run your node server again your DB starts but there's no data in the DB, therefore the service can't find any data.
After service restart you're using non-existing ID because of wrong UI flow.
I would guess that you're facing the first option.
I'm trying to upload some data to the school database when the user clicks a submit button on a form. I've set up the server.js, and it works with Postman. However, when I try to fetch (POST) the data on the button click, I get a 404 error in the browser console.
For some reason, I also can't open my html files if the server is already running. I don't know if this is relevant.
I've double-checked every string that connects the client-side fetch and the server-side app.post() together. I've also checked that the JSON data sent from my application is accepted by using the same text in Postman. This works. I've also tried looking at similar posts, but no one has the exact same problem (as far as I can tell).
This is my server.js:
let express = require("express");
let mysql = require("mysql");
let bodyParser = require("body-parser");
let app = express();
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
let pool = mysql.createPool({
connectionLimit: 2,
host: "---",
user: "---",
password: "---",
database: "---",
debug: false
}
);
app.post("/send", (req, res) => {
console.log("Received Post from client");
pool.getConnection((err, connection) => {
if (err) {
console.log("Connection error");
res.json({ error: "connection error" });
} else {
console.log("Connection established");
console.log(req.body);
let val = [req.body.some_value];
console.log(val);
connection.query(
"insert into some_table (some_value) values (?)",
val,
err => {
if (err) {
console.log(err);
res.status(500);
res.json({error: "Insertion error"});
} else {
console.log("Insertion OK!");
res.send("");
}
}
);
}
});
});
let server = app.listen(8080);
console.log("Server running");
My client (sendButton.js):
document.getElementById("submit").addEventListener("click", function(){
let data = {some_value: document.getElementById("some_value_input")};
console.log(JSON.stringify(data));
fetch("http://localhost:8080/send", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(function(response){
alert("We're trying");
if (response.ok){
console.log("Data uploaded");
return;
}
throw new Error("Data not uploaded");
})
.catch(function(error){
console.log(error);
});
});
And the HTML button is just a standard button with an the id "submit".
My expected results: Insertion OK, values sent to the database with no error.
Actual results: 404 page not found error:
Remove the let server variable and leave the app.listen(8080), so that the end result would be
app.listen(8080, () => console.log('Server is running'));
In my ReactJS project, I am currently running the server with NodeJS and ExpressJS, and connecting to the MongoDB using MongoClient. I have a login API endpoint set up that accepts a request with user's username and password. And if a user is not found, should catch the error and respond with an error (status(500)) to the front-end.
But rather than responding to the front-end with an json error, the server gets crashed. I have tried everything to figure out why but still no luck.
How can I fix the following error? Any guidance or insight would be greatly appreciated, and will upvote and accept the answer.
I intentionally made a request with a username and a password ({ username: 'iopsert', password: 'vser'}) that does not exist in the database.
Here is the login endpoint:
//login endpoint
app.post('/api/login/', function(req, res) {
console.log('Req body in login ', req.body)
console.log('THIS IS WHAT WAS PASSED IN+++++', req._id)
db.collection('users').findOne({username: req.body.username}, function(err, user) {
console.log('User found ')
if(err) {
console.log('THIS IS ERROR RESPONSE')
// Would like to send this json as an error response to the front-end
res.status(500).send({
error: 'This is error response',
success: false,
})
}
if(user.password === req.body.password) {
console.log('Username and password are correct')
res.status(500).send({
username: req.body.username,
success: true,
user: user,
})
} else {
res.status(500).send({
error: 'Credentials are wrong',
success: false,
})
}
})
And here is the terminal error log:
Req body in login { username: 'iopsert', password: 'vset' }
THIS IS WHAT WAS PASSED IN+++++ undefined
User found
/Users/John/practice-project/node_modules/mongodb/lib/utils.js:98
process.nextTick(function() { throw err; });
^
TypeError: Cannot read property 'password' of null
at /Users/John/practice-project/server/server.js:58:12
at handleCallback (/Users/John/practice-project/node_modules/mongodb/lib/utils.js:96:12)
at /Users/John/practice-project/node_modules/mongodb/lib/collection.js:1395:5
at handleCallback (/Users/John/practice-project/node_modules/mongodb/lib/utils.js:96:12)
at /Users/John/practice-project/node_modules/mongodb/lib/cursor.js:675:5
at handleCallback (/Users/John/practice-project/node_modules/mongodb-core/lib/cursor.js:165:5)
at setCursorNotified (/Users/John/practice-project/node_modules/mongodb-core/lib/cursor.js:505:3)
at /Users/John/practice-project/node_modules/mongodb-core/lib/cursor.js:578:16
at queryCallback (/Users/John/practice-project/node_modules/mongodb-core/lib/cursor.js:226:18)
at /Users/John/practice-project/node_modules/mongodb-core/lib/connection/pool.js:430:18
And /Users/John/practice-project/node_modules/mongodb/lib/utils.js:98 is referring to the following:
var handleCallback = function(callback, err, value1, value2) {
try {
if(callback == null) return;
if(value2) return callback(err, value1, value2);
return callback(err, value1);
} catch(err) {
process.nextTick(function() { throw err; });
return false;
}
return true;
}
EDIT
Here are everything that's being imported to the server:
"use strict"
var express = require('express');
var path = require('path');
var config = require('../webpack.config.js');
var webpack = require('webpack');
var webpackDevMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
var bodyParser = require('body-parser');
var MongoClient = require('mongodb').MongoClient;
var ObjectId = require('mongodb').ObjectID;
const jwt = require('jsonwebtoken')
var app = express();
var db;
var compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, {noInfo: true, publicPath: config.output.publicPath}));
app.use(webpackHotMiddleware(compiler));
app.use(express.static('dist'));
app.use(bodyParser.json());
And this is how the request is made and error is caught:
loginUser(creds) {
var request = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(creds),
}
fetch(`http://localhost:3000/api/login`, request)
.then(res => res.json())
.then(user => {
console.log(user);
console.log('Successful')
})
.catch(err => {
console.log('Error is', err)
})
},
It looks to me like the error is being thrown on this line because user is not defined.
if(user.password === req.body.password) {...}
Take a harder look at your console statements.
1. Req body in login { username: 'iopsert', password: 'vset' }
2. THIS IS WHAT WAS PASSED IN+++++ undefined
3. User found
4. /Users/John/practice-project/node_modules/mongodb/lib/utils.js:98
5. process.nextTick(function() { throw err; });
^
6. TypeError: Cannot read property 'password' of null
7. at /Users/John/practice-project/server/server.js:58:12
Line 2 shows that req._id is undefined
Your User found statement is printed before you check if there is an error or if the user actually exists, so it isn't representative of there actually being a user.
Line 6 shows that the error is being thrown because you're trying to read a property of password from a null object.
I'd recommend modifying your login logic to look more like this:
//login endpoint
app.post('/api/login/', function(req, res) {
console.log('Performing login with req.body=');
console.log(JSON.stringify(req.body, null, 4));
// check for username
if (!req.body.username) {
return res.status(401).send({message: 'No username'});
}
// find user with username
db.collection('users').findOne({username: req.body.username}, function(err, user) {
// handle error
if(err) {
console.log('Error finding user.');
return res.status(500).send({message: 'Error finding user.'});
}
// check for user
if (!user) {
console.log('No user.');
return res.status(500).send({message: 'No user.'});
}
console.log('User found.');
// check password
if(user.password !== req.body.password) {
console.log('Wrong password.');
return res.status(401).send({message: 'Wrong password.'});
}
// return user info
return res.status(200).send(user);
});
Some final thoughts:
Make sure to handle the error (if it exists) and check that user exists before proceeding.
Always include return in your return res.status(...).send(...) statements, otherwise the subsequent code will execute.
It's generally not a good idea to save passwords as simple strings. Work toward encrypting them. Look at passport or bcrypt.
Hope this helps.
I have a website that is accessing a local node.js server (that accesses a mongolab database), but when I use a front-end function to request a user JSON object, the mongo database returns nothing. (JSON.parse() finds an unexpected end of data at line 1 col 1)
Here is the front-end function that requests the user data by email and password:
function requestUser(email, password) {
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "http://localhost:8888/getUser/" + email + "/" + password, true);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
user = JSON.parse(xmlhttp.responseText);
console.log(user);
}
}
xmlhttp.send();
}
Here is the node.js express server (back-end):
var http = require("http"),
mongojs = require("mongojs"),
express = require('express'),
cors = require('cors'),
fs = require("fs"),
url = require("url");
app = express();
app.use(cors());
var uri = "mongodb://<dbuser>:<dbpassword>#ds036698.mongolab.com:36698/alirodatabase";
var db = mongojs(uri, ["Papers", "Users"]);
app.get('/getUser/:email/:passwd', function(req, res, next) {
var users = db.Users.find({"email": req.params.email,
"password": req.params.passwd});
user = users.toArray[0];
res.json(user);
});
app.listen(8888, function() {
console.log('CORS-enabled web server listening on port 8888');
});
EDIT 1:
app.get('/getUser/:email/:passwd', function(req, res, next) {
var user = db.Users.findOne({
"email": req.params.email,
"password": req.params.passwd
}, function(err, doc) {
if (err) {
res.json({error: 'error retrieving the JSON user' });
}
else {
res.json(doc);
}
});
});
I added async functionality to the nodeserver, but now I am receiving the err: "error retrieving the JSON user". Is this a problem that could be solved by hosting my own database and not using mongolab?
You need to look at the docs for mongojs (https://github.com/mafintosh/mongojs). You're not using callbacks at all. The functions don't return values because it's Javascript/Node.js where things like to be async. So you have to use callbacks to handle the results. The idea is "find these documents" and then some time later when it actually gets the documents "do something with the documents".
app.get('/getUser/:email/:passwd', function(req, res, next) {
var users = db.Users.find({
"email": req.params.email,
"password": req.params.passwd
}, function(err, docs) {
if (err) {
//handle the error
res.json({error: ':(' });
}
else {
docs.toArray(function(err, users) {
if (err) {
//handle the error
res.json({error: ':(' });
}
else {
res.json(users[0]);
}
});
}
});
});
Lastly, I'd recommend using findOne rather than find. Then you won't need to use toArray to get a single document because it's returned as a single document in the first callback.
I have an iOS app which is sending a JSON packet to a webserver. The webserver code looks like this:
var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var app = express();
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function (callback) {
console.log("MongoDB connection is open.");
});
// Mongoose Schema definition
var Schema = mongoose.Schema;
var LocationSchema = new Schema({
X: Number,
Y: Number,
Orientation: Number,
UserID: String,
Time: String
});
// Mongoose Model definition
var LocationsCollection = mongoose.model('locations', LocationSchema);
// create application/json parser
var jsonParser = bodyParser.json();
// URL management
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
app.post('/update', jsonParser, function (req, res) {
if (!req.body) return res.sendStatus(400);
else {
console.log(req.body);
}
});
// Start the server
var server = app.listen(3000, function () {
var host = server.address().address
var port = server.address().port
console.log('App listening at %s:%s',host, port)
});
The key part is the app.post method which processes the incoming http request being sent from my iOS app. At the moment, the method which prints the req.body to the console looks like this:
{
datapoint_1:
{ timestamp: '2015-02-06T13:02:40:361Z',
x: 0.6164286615466197,
y: -0.6234909703424794,
id: 'B296DF8B-6489-420A-97B4-6F0F48052758',
orientation: 271.3345946652066 },
datapoint_2:
{ timestamp: '2015-02-06T13:02:40:961Z',
x: 0.6164286615466197,
y: -0.6234909703424794,
id: 'B296DF8B-6489-420A-97B4-6F0F48052758',
orientation: 273.6719055175781 }
}
So, you can see the request is a nested JSON object. Ideally, I'd like to loop through the request objects (ie. the datapoints) and insert those into the mongoDB database (via mongoose). However, I can't seem to figure out how to do much of anything with the req.body. I can't seem to create a loop to iterate through the request or how to properly parse the nested JSON file so it matches the mongoose schema. Can anyone provide some guidance on how to insert these datapoints into the mongoose database?
Set body-parser's extended property to true to allow parsing nested objects.
var express = require('express');
var app = express()
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: true
}));
Answering my own question. But, after figuring out how to access the key/value pairs inside the nested JSON object... it became relatively easy to figure out the rest. The updated app.post function now looks like this:
app.post('/update', jsonParser, function (req, res) {
if (!req.body) return res.sendStatus(400);
else {
for(var datapoint in req.body){
//create new instance of LocationCollection document
var point = new LocationsCollection({
X:Number(req.body[datapoint]["x"]),
Y:Number(req.body[datapoint]["y"]),
Orientation:Number(req.body[datapoint]["orientation"]),
Time:req.body[datapoint]["timestamp"],
UserID:req.body[datapoint]["id"]
});
//insert the newly constructed document into the database
point.save(function(err, point){
if(err) return console.error(err);
else console.dir(point);
});
}
}
});
I can test if this worked by putting the following method inside the callback function once the mongodb connection is first established:
//Find all location points and print to the console.
console.log("Searching for all documents in Location Points Collection");
LocationsCollection.find(function(err,data){
if(err) console.error(err);
else console.dir(data);
});
This will print any documents that have been previously added to the database. Hopefully this helps.
Try somthing like this.
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json({limit:1024*1024, verify: function(req, res, buf){
try {
JSON.parse(buf);
} catch(e) {
res.send({
error: 'BROKEN_JSON'
});
}
}}));
It should be a simple for (var key in obj) loop:
app.post('/update', jsonParser, function (req, res) {
var locationObject = req.body(),
insertObjects = [],
key;
for (key in locationObject) { // loop through each object and insert them into our array of object to insert.
insertObjects.push(locationObject[key]);
}
if (!insertObjects.length) { // if we don't have any object to insert we still return a 200, we just don't insert anything.
return res.status(200).send({
success: true,
message: 'Nothing inserted, 0 locations in POST body',
count: 0;
});
}
LocationsCollection.create(insertObjects, function (err, res) {
if (err) {
return res.status(400).send({
success: false,
message: err.message
});
}
// we have successfully inserted our objects. let's tell the client.
res.status(200).send({
success: true,
message: 'successfully inserted locations',
count: insertObjects.length;
});
});
});
Mongo allows for inserting multiple documents with a single callback, which makes this a lot easier.
This also checks the schema to ensure only proper documents are created.