I have a dashboard that generates JSON data and saves it as a .json file. This was initially written in PHP but for various reasons we have re-written the application in node. The code below takes the post data and then should check to see if the file exists then if it does update it if not it should create the file and directory.
However it only seems to create the first file and I cannot fathom why it doesn't create the subsequent files as this post route is called once for each post.
the post method looks like this
$.ajax({
type : "POST",
url : '/save/',
dataType : 'json',
data : {
category : settings.category_id,
name : settings.campaignId,
json : JSON.stringify(settings)
}
});
I have debugged and when called all the correct file paths are passed but its almost as if the file isn't being written with the data.
During debugging using node-inspector and nodemon the code loops through all the requested new file names and gives me the error code ENOENT, so it should then follow the create file path.
If you know anything about node and the file system module and feel like helping me out that would be amazing even if it's just pointing me in the direction of some more tutorials, ... anything would be great!
-
'use strict'
const fs = require('fs');
const path = require('path');
const express = require('express');
const router = express.Router();
/* Save Data */
router.post('/', function(req, res) {
if (!(req.body.json && req.body.name && req.body.category)) {
res.sendStatus(400);
return;
}
let dir = 'public/savedData/' + req.body.category;
let filepath = dir + '/' + req.body.name + '.json';
fs.access(filepath, function(error) {
console.log(filepath);
console.log(error.code);
if (error) {
if (error.code == 'ENOENT') {
console.log(error.code);
//debugger;
// Create file since it doesn't exist
createFile(req, res, filepath);
} else {
//debugger;
console.log('access error:', error);
res.sendStatus(500);
}
} else {
//debugger;
// Update file since it already exists
updateFile(req, res, filepath);
}
});
});
function createFile(req, res, filepath) {
try {
let json = JSON.parse(req.body.json);
let output = JSON.stringify([json], null, 4);
fs.mkdir(path.dirname(filepath), function(error) {
if (error) {
if (error.code == 'EEXIST') {
updateFile(req, res, filepath);
} else {
res.sendStatus(500);
console.log('create file error :', error);
}
} else {
fs.writeFile(filepath, output, function(error) {
if (error) {
res.sendStatus(500);
console.log('write file error :', error);
} else {
res.sendStatus(200);
console.log('Data successfully saved');
}
});
}
});
} catch (error) {
res.sendStatus(500);
console.log(error);
}
}
function updateFile(req, res, filepath) {
try {
fs.readFile(filepath, 'utf-8', function(error, data) {
if (error) {
res.sendStatus(500);
console.log('update error:', error);
} else {
try {
let newJSON = JSON.parse(req.body.json);
let jsonArray = JSON.parse(data);
let output;
jsonArray.push(newJSON);
output = JSON.stringify(jsonArray, null, 4);
fs.writeFile(filepath, output, function(error) {
if (error) {
res.sendStatus(500);
console.log(error);
} else {
res.sendStatus(200);
console.log('Data successfully saved');
}
});
} catch (error) {
res.sendStatus(500);
console.log(error);
}
}
});
} catch (error) {
res.sendStatus(500);
console.log(error);
}
}
module.exports = router;
Instead of checking if the file exists, you should try to write with flags wx, which creates a file but fails if it does already exist. That way you won't be subjecting yourself to race conditions. I would also suggest the package mkdirp, which does not emit an error if the directory already exists.
router.post('/', (req, res) => {
if (!(req.body.json && req.body.name && req.body.category)) {
res.sendStatus(400);
return;
}
const dirpath = `public/savedData/${req.body.category}`;
const filepath = `${dirpath}/${req.body.name}.json`;
mkdirp(dirpath, err => {
if (err) {
console.error('mkdirp failed', err);
return res.sendStatus(500);
}
const output = JSON.stringify([JSON.parse(req.body.json)]);
fs.writeFile(filepath, output, { flags: 'wx' }, err => {
if (err) {
console.error('writeFile failed', err);
return res.sendStatus(500);
}
console.log('Data successfully saved');
res.sendStatus(200);
});
);
});
Make sure you sanitize the req.body.name and req.body.category parameters, since you could expose your filesystem to unintentional overwrites.
Thanks to #Iso this is my solution
router.post('/', (req, res) => {
if (!(req.body.json && req.body.name && req.body.category)) {
res.sendStatus(400);
return;
}
const dirpath = 'public/savedData/' + req.body.category;
const filepath = dirpath + '/' + req.body.name + '.json';
mkdirp(dirpath, err => {
if (err) {
console.error('mkdirp failed', err);
return res.sendStatus(500);
}
const output = JSON.stringify([
JSON.parse(req.body.json)
]);
fs.readFile(filepath, 'utf-8', function(error, data) {
if(error) {
fs.writeFile(filepath, output, err => {
if (err) {
console.error('writeFile failed', err);
return res.sendStatus(500);
}
console.log('Data successfully saved');
res.sendStatus(200);
});
} else {
let newJSON = JSON.parse(req.body.json);
let jsonArray = JSON.parse(data);
let output;
jsonArray.push(newJSON);
output = JSON.stringify(jsonArray, null, 4);
fs.writeFile(filepath, output, err => {
if (err) {
console.error('writeFile failed', err);
return res.sendStatus(500);
}
console.log('Data successfully saved');
res.sendStatus(200);
});
}
});
});
});
Related
The following code does not create a new directory, nor does it output any err
const fs = require("fs-extra");
fs.mkdir(dirPath, { recursive: true }, (err) => {
if (err) {
console.log("ERR: When attempting to mkdir", err);
} else {
console.log("MKDIR made " + dirPath);
}
cb(null, dirPath);
});
I would expect the directory to be created... or an error.
When I console.log(err) I find that the value of err is null.
How can I ensure this directory has been created?
I am trying to call [https://jsonplaceholder.typicode.com/albums/1/photos] in my node codes so that i create an end-point that is dynamic...like if i change 1 in url i get the relevant photos.
here are my codes
const request = require('request');
const callExtrenalApiUsingRequest = async (callback, req, res) => {
try {
let id = req.params.id
await request(`https://jsonplaceholder.typicode.com/albums/${id}/photos`, { json: true }, (err, res, body) => {
if (err) {
return callback(err);
}
return callback(body)
})
}
catch (error){
console.log(error)
}
}
module.exports.callApi = callExtrenalApiUsingRequest;
request.js
const apiCallFromRequest = require( './request.js');
const http = require('http')
http.createServer((req, res) => {
try {
if (req.url === "/request/photos/:id") {
apiCallFromRequest.callApi(function (response) {
res.write(JSON.stringify(response));
res.end();
})
}
}
catch (err) {
console.log(err)
}
}).listen(3000)
console.log("service running on port 3000...")
I am using MongoDB, nodeJS, express, multer, jimp and gridFS to upload an image. I first uploaded the image with multer then resized it with jimp then uploaded the jimp buffer to MongoDB now when I delete the multer image an error comes that the file is probably corrupt as the chunks file is not written(i don't know why but it is actually not written when I want to delete it) can any one tell how to achieve this and what is the error in my code.
here is my post route
app.post('/upload', upload.single("file"), (req, res) => {
if(req.file === undefined || req.file === 0 || req.file === ""){
res.redirect("/");
}
console.log(req.file);
filename = req.file.filename;
Jimp.read( "http://localhost:3000/image/" + req.file.filename, (err, image) => {
if (err) {
console.log(err);
}
// .then(lenna => (tpl.clone().write(imgActive)))
image
.resize(500, Jimp.AUTO)
// console.log(img);
image.getBase64(Jimp.AUTO, (error1, base64Image) => {
if(error1){
console.log(error1);
}
const image1 = new Image({
image: base64Image,
User: "Avichal",
forTest: "Hindi1"
});
image1.save(function(error){
if(error){
console.log(error);
}
})
})
})
gfs.remove({ _id: req.file.id, root: 'uploads' }, (err, gridStore) => {
if (err) {
console.log(err);
}
});
res.redirect('/');
});
here is the error:
MongoError: no chunks found for file, possibly corrupt
just a small error I have to put the remove function In the jimp read function the corrected code is:
app.post('/upload', upload.single("file"), (req, res) => {
if(req.file === undefined || req.file === 0 || req.file === ""){
res.redirect("/");
}
console.log(req.file);
filename = req.file.filename;
Jimp.read( "http://localhost:3000/image/" + req.file.filename, (err, image) => {
if (err) {
console.log(err);
}
// .then(lenna => (tpl.clone().write(imgActive)))
image
.resize(500, Jimp.AUTO)
// console.log(img);
image.getBase64(Jimp.AUTO, (error1, base64Image) => {
if(error1){
console.log(error1);
}
const image1 = new Image({
image: base64Image,
User: "Avichal",
forTest: "Hindi1"
});
image1.save(function(error){
if(error){
console.log(error);
}
})
})
gfs.remove({ _id: req.file.id, root: 'uploads' }, (err, gridStore) => {
if (err) {
console.log(err);
}
res.redirect('/');
});
})
});
I am using mongoose to read and update and remove some documents.
The find and update and remove are working fine. Except the last data.remove(); which is not being removed and hits an error.
I am getting this error in my code below:
events.js:160
throw er; // Unhandled 'error' event
^
Error: Can't set headers after they are sent.
and the line that it is pointing to is:
res.status(200).json({
success: true
});
at the end of the code.
router.post('/some/route', function (req, res) {
if (req.isLoggedIn()) {
return res.status(403).json({});
}
MyModel.findById(req.user._id,function (err, data) {
if(err || data.rights !== 'super'){
return res.status(403).json({});
}
if(req.body.writer){
Books.update(
{ writer : req.body.id},
{ $set : { writer : req.body.writer} },
function (err) {
if(err){
res.status(500).send(err);
}
else{
res.status(200).send('updated successfully.');
}
}
);
}else{
Books.remove({writer: req.body.id}, function(err){
if (err){ return console.log(err)}
});
}
MetaInfo.findOneAndRemove({_id: req.body.id}, function (err, data) {
console.log(err);
});
Archive.findOne({_id: req.body.id},function (err, data) {
smtpTransporter.sendMail({...}, function (error, response) {
if (error) {
console.log(error);
} else {
console.log("Mail sent");
}
smtpTransporter.close();
});
data.remove();
if (err) {
console.log(err);
return res.status(200).json({
success: false,
message: 'server error',
err: err
});
}
res.status(200).json({
success: true
});
})
});
});
Basically when you do res.send or res.json it sets headers for response. When javascript finds another res.send to execute after one, it throws error that the headers are already set.
Make sure you are returning the res.send or json every time or you are using proper if else statement for it.
To elaborate :
Example 1 :
app.get('/', (req, res) => {
if(true){
res.send('first');
}
res.send('second');
});
This will throw error in console.
Example 2 :
app.get('/', (req, res) => {
if(true){
return res.send('first');
}
res.send('second');
});
No error thrown.
Example 3 :
app.get('/', (req, res) => {
if(true){
res.send('first')
}
else{
res.send('second');
}
});
No error thrown.
The error prevents my webpage from being rendered. As mentioned in the title, the error lies in styles.css, when I take this file out, I do not get any errors.
styles.css is included in a separate headers.ejs file which is added in all pages, but there is only one route for which the error is shown(/cats/new). I put up some some logs around my routes and it seems when I enter /cats/new/, I am automatically redirected to a new route (get /cats/:id). I am wondering if this is the cause of the error?
I have attached my routes and the full error message below:
routes:
var express = require('express');
var router = express.Router();
var User = require('../models/user.js');
var Cat = require('../models/cat.js');
var Comment = require('../models/comment.js');
//middleware
function isAuthenticated(req,res,next) {
req.isAuthenticated() ? next() : res.redirect('/login');
}
router.get("/", function(req,res) {
res.redirect("cats");
});
router.get('/cats', function(req,res) {
Cat.find({}, function(err, cats) {
if (err) {
console.log(err);
} else {
res.render('cats', {cats: cats});
}
});
});
router.get('/cats/new', isAuthenticated, function(req,res) {
console.log('went to /cats/new');
res.render('new', {user: req.user});
});
router.post('/cats', isAuthenticated, function(req,res) {
console.log('went to post /cats');
var name = req.body.name;
var image = req.body.url;
var owner = req.user.username
var description = req.body.description;
cat = new Cat({
name: name,
image: image,
owner: owner,
description: description
});
cat.save();
User.findById(req.user._id, function(err, user) {
if (err) {
console.log(err);
} else {
user.cats.push(cat);
user.save();
}
})
res.redirect('cats');
});
router.get('/cats/:id', function(req,res) {
var id = req.params.id;
Cat.findById(id).populate('comments').exec(function(err, cat) {
if (err) {
console.log('entering get /cats/:id');
console.log(err);
} else {
console.log('no errror yet');
console.log(cat.comments);
res.render('show', {cat:cat});
}
});
});
router.post('/cats/:id', isAuthenticated, function(req,res) {
console.log(isAuthenticated);
var id = req.params.id;
Cat.findById(id, function(err, cat) {
console.log('findById running');
if (err) {
console.log(err);
console.log('err finding cat');
res.redirect('/cats');
} else {
console.log('before Comment.create');
Comment.create(req.body.comment, function(err, comment) {
console.log('after Comment.create');
if (err) {
console.log(err);
} else {
console.log('right after 2nd else');
comment.author.id = req.user._id;
console.log(req.user._id);
console.log(req.user.username);
comment.author.username = req.user.username;
comment.cat = id;
comment.save();
console.log('after saving comment');
cat.comments.push(comment);
cat.save();
console.log('saved cat');
User.findById(req.user._id, function(err, user) {
if (err) {
console.log(err);
} else {
user.comments.push(comment);
user.save();
console.log('saved user');
}
});
console.log(comment);
res.redirect("/cats/" + cat._id);
}
});
}
});
});
router.get('/cats/:id/edit', function(req,res) {
var id = req.params.id;
Cat.findById(id, function(err, cat) {
if (err) {
console.log(err);
} else {
res.render('edit.ejs', {cat:cat});
}
});
});
router.put('/cats/:id', function(req,res) {
console.log('beginning /cat/:id');
Cat.findByIdAndUpdate(
req.params.id, req.body.cat, function(err, updatedCat) {
if (err) {
console.log(err);
} else {
console.log('------------ req.body.cat');
console.log(req.body.cat);
console.log('------------ updated cat');
console.log('updated cat');
res.redirect('/cat/' + req.params.id);
console.log('not redirecting?');
}
});
router.delete('/cats/:id',isAuthenticated, function(req,res) {
var id = req.params.id;
console.log('YOU ARE TRYING TO DESTROY A CAT!');
Cat.findByIdAndRemove(id, function(err) {
if (err) {
console.log(err);
res.redirect('/user');
} else {
res.redirect('/user');
}
});
})
});
module.exports = router;
Error:
entering get /cats/:id
{ [CastError: Cast to ObjectId failed for value "styles.css" at path "_id"]
message: 'Cast to ObjectId failed for value "styles.css" at path "_id"',
name: 'CastError',
kind: 'ObjectId',
value: 'styles.css',
path: '_id',
reason: undefined }
It seems you’re including styles.css using a relative path in your template.
So when you navigate to /cats/:id, it tries to load /cats/styles.css.
In order to avoid that, you have to use an absolute path (e.g.: /styles.css or /public/styles.css – I’d recommend serving static files from a dedicated base path).
Go to
<head>
and change
<link rel="stylesheet" href="style.css">
to
<link rel="stylesheet" href="/style.css">