Can't parse json with node.js - html

I am a node.js beginner and I am trying to read a json file, but when I'm running 'npm start' in the terminal I get this error:
undefined:3462
SyntaxError: Unexpected end of input
at Object.parse (native)
at /Users/alonbond/node_apps/analoc_2/analoc/routes/index.js:15:20
at fs.js:334:14
at FSReqWrap.oncomplete (fs.js:95:15)
this is index.js:
var express = require('express');
var fs = require('fs');
var app = express.Router();
/* GET home page. */
app.get('/', function(req, res, next) {
console.log('Welcome to Express.js');
res.render('index', { title: 'Express' });
});
/* GET json */
app.get('/analoc/', function(req, res) {
fs.readFile('./sample_data.json', function(error, data){
jsonObj = JSON.parse(data);
res.send('THE DATA: ', jsonObj);
});
});
module.exports = app;
Any help?
thanks!

readFile is the asynchronous version. You should either just use readFileSync, or rewrite it to be properly asynchronous.
console.log('analoc request');
var fs = require('fs');
fs.readFile('./files/sample_data.json', function(err,config){
console.log('Config: ' + JSON.parse(config));
});
Or:
var config = fs.readFileSync('./files/sample_data.json');
console.log('Config: ' + JSON.parse(config));

readFile doesn't have a return value. You are trying to parse "undefined" as if it were JSON. The file is passed to the callback function after it has been read.
fs.readFile('./files/sample_data.json', function (err, data) {
if (err) throw err;
var config = JSON.parse(data);
console.log('Config: ', config);
});

Related

fs.readFile() returns undefined [duplicate]

This question already has answers here:
Returning a value from callback function in Node.js [duplicate]
(4 answers)
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
i'm trying to display a html page creating a node http server, when i try to take the code of the html file it returns undefined, this is the code...
var http = require('http');
var fileContent = function(path, format) {
var fs = require('fs');
fs.readFile(path, format, function(error, contents) {
if (error) throw error;
return contents;
});
}
var server = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
page = fileContent('./page.html','utf8');
console.log(page);
res.end(page);
}).listen(8080);
i printed the error,
[Error: ENOENT: no such file or directory, open './page.html'] {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: './page.html'
}
the two files are in the same directory
Firstly, fs.readFile is asynchronous function. Which means is not returning the answer instantly or blocks the thread to wait for answer. Instead it requires a callback to let you know when answer is ready.
Secondly, I suggest using path module to merge __dirname (the directory name of the current module) and file name to make absolute file paths.
I will provide 3 solutions using different methods.
Solution 1. Using callback method
var http = require('http');
var fs = require('fs');
var path = require('path');
var fileContent = function(path, format, cb) {
fs.readFile(path, format, function(error, contents) {
if (error) throw error;
cb(contents);
});
}
var server = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
fileContent(path.join(__dirname, 'page.html'), 'utf8', function (page) {
console.log(page);
res.end(page);
});
}).listen(8080);
Solution 2. Promises using .then
var http = require('http');
var fs = require('fs');
var path = require('path');
var fileContent = function(path, format) {
return new Promise(function (resolve, reject) {
fs.readFile(path, format, function(error, contents) {
if (error) reject(error);
else resolve(contents);
});
});
}
var server = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
fileContent(path.join(__dirname, 'page.html'), 'utf8')
.then(function(page) {
console.log(page);
res.end(page);
});
}).listen(8080);
Solution 3. Promise using async/await
var http = require('http');
var fs = require('fs');
var path = require('path');
var fileContent = function(path, format) {
return new Promise(function (resolve, reject) {
fs.readFile(path, format, function(error, contents) {
if (error) reject(error);
else resolve(contents);
});
});
}
var server = http.createServer(async function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var page = await fileContent(path.join(__dirname, 'page.html'), 'utf8');
console.log(page);
res.end(page);
}).listen(8080);

nodejs - stub module.exports functions with sinon

I have an expressjs app with the following routes and middleware modules. I am trying to test the routes module using mocha, chai, http-chai and sinonjs.
The API uses mysql and in order to test the routes module, I have it all modularized so that I can stub out the mysql module.
However when I try to stub middleware/index, I am having trouble. If I try to require index normally, the module doesn't actually get stubbed. If I try to require it using require.cache[require.resolve('./../../lib/routes/middleware/index')];, it seems to stub something, but indexStub.returns(indexObj) returns an error TypeError: indexStub.returns is not a function and TypeError: indexStub.restore is not a function.
How do I stub out index.js properly in order to control the code flow and keep it from trying to connect to mysql?
routes.js
'use strict';
const express = require('express');
const router = express.Router();
const configs = require('./../config/configs');
const middleware = require('./middleware/index');
const bodyParser = require('body-parser');
const useBodyParserJson = bodyParser.json({
verify: function (req, res, buf, encoding) {
req.rawBody = buf;
}
});
const useBodyParserUrlEncoded = bodyParser.urlencoded({extended: true});
// creates a new post item and return that post in the response
router.post('/posts', useBodyParserUrlEncoded, useBodyParserJson, middleware.validatePostData, middleware.initializeConnection, middleware.saveNewPost, middleware.closeConnection, function(req, res) {
if (res.statusCode === 500) {
return res.send();
}
if (res.statusCode === 405) {
return res.send('Item already exists with slug ' + req.body.slug + '. Invalid method POST');
}
res.json(res.body).end();
});
module.exports = router;
middleware/index.js
'use strict';
const configs = require('./../../config/configs');
const database = require('./../../factories/databases').select(configs.get('STORAGE'));
const dataV = require('./../../modules/utils/data-validator');
module.exports = {
initializeConnection: database.initializeConnection, // start connection with database
closeConnection: database.closeConnection, // close connection with database
saveNewPost: database.saveNewPost, // creates and saves a new post
validatePostData: dataV.validatePostData, // validates user data
};
spec-routes.js
'use strict';
var chai = require('chai');
var chaiHttp = require('chai-http');
var sinonChai = require("sinon-chai");
var expect = chai.expect;
var sinon = require('sinon');
chai.use(sinonChai);
chai.use(chaiHttp);
var app = require('./../../app');
describe('COMPLEX ROUTES WITH MIDDLEWARE', function() {
var indexM = require.cache[require.resolve('./../../lib/routes/middleware/index')];
describe('POST - /posts', function() {
var indexStub,
indexObj;
beforeEach(function() {
indexStub = sinon.stub(indexM);
indexObj = {
'initializeConnection': function(req, res, next) {
return next();
},
'closeConnection': function(req, res, next) {
return next();
},
'validatePostData': function(req, res, next) {
return next();
}
};
});
afterEach(function() {
indexStub.restore();
});
it('should return a 500 response', function(done) {
indexObj.saveNewPost = function(req, res, next) {
res.statusCode = 500;
return next();
};
indexStub.returns(indexObj);
chai.request(app)
.post('/posts')
.send({'title': 'Hello', 'subTitle': 'World', 'slug': 'Example', 'readingTime': '2', 'published': false})
.end(function(err, res) {
expect(res).to.have.status(500);
done();
});
});
});
});
You don't use Sinon at all, as it doesn't deal with module loading at all. I see you have started doing this manually using the internal Node API's, but I suggest you do it the way we advise in the Sinon docs regarding this usecase: juse use proxyquire.
It enables you to substitute require calls to ./middleware/index.js for a mock object of your own liking (possibly made using sinon).
You would use it something like this:
var myIndex = {
initializeConnection: sinon.stub(),
closeConnection: sinon.stub(),
saveNewPost: sinon.stub()
};
var app = proxyquire('./../../app', {'./middleware/index': myIndex});

get json from a post request to a nodejs server

Where in the request object is the json?
For example I know I can use body-parser to do this
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.post('/', function(req, res){
console.log(req.body)
res.json({ message: 'goodbye'})
})
And start my server and hit it with
curl -H "Cont/json" -X POST -d '{"username":"xyz"}' http://localhost:3000/
but is there a way to do it without the body parser includes? Can I just see the json in the request?
You could do it through node stream as below
app.post('/', function(req, res){
var body = "";
req.on("data", function (data) {
body += data;
});
req.on("end", function() {
console.log(JSON.parse(body));
res.json({ message: 'goodbye'})
});
})
Yep, you can
//pipe to any writable stream
req.pipe(process.stdout);
Sure if u want - u may save it to string using something like this
var tmpstr = "";
req.on("data", function (data) {
tmpstr += data;
});
req.on("end", function() {
//do stuff
console.log("\ndata length is: %d", tmpstr.length);
});

show json data in index file

I dont understand why I cant display my json data. I am new to javascript and I want to display the data in the json file to my index file.
I have used the express generator for all the files. I did read that I should add this FS code in my app.js, but I cant use the data variable in my index file in my view. Any help ?
var express = require('express');
var router = express.Router();
var fs = require('fs');
/* GET home page. */
router.get('/', function(req, res, next) {
var file = __dirname + '/public/list/list.json';
var data;
fs.readFile(file, 'utf8', function (err, data) {
if (err) {
console.log('Error: ' + err);
return;
}
data = JSON.parse(data);
console.log(data);
});
res.render('index', { title: data });
console.log(data);
});
module.exports = router;
here is my json file
{
"username":"xyz",
"password":"xyz#123",
"email":"xyz#xyz.com",
"uid": 1100
}
fs.readFile is asynchronous , so you should put res.render(..) inside his callback , because it will fired when the readFile function ends. So change your code to :
fs.readFile(file, 'utf8', function (err, data) {
if (err) {
console.log('Error: ' + err);
return;
}
data = JSON.parse(data);
console.log(data);
res.render('index', { title: data });
});
The above answer is correct, but there's also an alternative.
If you're using this file for your index page, it'd be used a lot. If the data isn't changing, you can simply require the JSON file at the top of your code and return it in the request.
var express = require('express');
var router = express.Router();
var list = require(__dirname + '/public/list/list.json');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: list });
});
module.exports = router;
However, if that data does change frequently, reading the file is the way to go.

Type error: TypeError: Cannot read property '_id' of undefined

I have been working on Building an Angular + Node Comment App using Yeoman.
I am unable to resolve the error "TypeError: Cannot read property '_id' of undefined".
This is my /api/comment/index.js file
'use strict';
var express = require('express');
var controller = require('./comment.controller');
var auth = require('../../auth/auth.service');
var router = express.Router();
router.get('/:id', controller.show);
router.put('/:id', controller.update);
router.patch('/:id', controller.update);
router.get('/', controller.index);
router.post('/', auth.isAuthenticated(), controller.create);
router.delete('/:id', auth.isAuthenticated(), controller.destroy);
module.exports = router;
This is my comment.controller.js file
/ Gets a single Comment from the DB
exports.show = function(req, res) {
Comment.findByIdAsync(req.params.id)
.then(handleEntityNotFound(res))
.then(responseWithResult(res))
.catch(handleError(res));
};
// Updates an existing Comment in the DB
exports.update = function(req, res) {
if (req.body._id) {
delete req.body._id;
}
Comment.findByIdAsync(req.params.id)
.then(handleEntityNotFound(res))
.then(saveUpdates(req.body))
.then(responseWithResult(res))
.catch(handleError(res));
};
// Deletes a Comment from the DB
exports.destroy = function(req, res) {
Comment.findByIdAsync(req.params.id)
.then(handleEntityNotFound(res))
.then(removeEntity(res))
.catch(handleError(res));
};
// Get list of comments
exports.index = function(req, res) {
Comment.loadRecent(function (err, comments) {
if(err) { return handleError(res, err); }
return res.json(200, comments);
});
};
// Creates a new comment in the DB.
exports.create = function(req, res) {
// don't include the date, if a user specified it
delete req.body.date;
var comment = new Comment(_.merge({ author: req.user._id }, req.body));
comment.save(function(err, comment) {
if(err) { return handleError(res, err); }
return res.json(201, comment);
});
};
Looking at the code you provided, the issue is that req.body is undefined.
By doing: if (req.body._id), you're still trying to access a property of undefined.
The correct if statement would be:
if (req.body && req.body._id) {
// do stuff
}