Delay on file read on newly created file in node.js - javascript

I am writing a new json file when I run my results.html page and then using express.static to make the public folder files accessible in the browser.
I have my app working but am having to click the button multiple times in order to have the updated file be written and accessed.
How should I send the JSON info to the browser without writing a file? Or not experience this lag?

Send the data back in response
function setData(req, res) {
var data = '';
req.on('data', function(streamData) {
data += streamData;
});
req.on('end', function() {
fs.writeFile('data/data.json', data, 'utf8', function(err) {
if (!err) {
res.writeHead(201, {
'Content-Type': 'text/json'
});
res.end(data)
} else {
res.writeHead(400, {
'Content-Type': 'text/json'
});
res.end("File write error" + err)
}
})
})
}
access the data from front end
$.ajax({
url: '/set/data',
method: 'POST',
data: data
})
.done(function(responseData) {
// update your ui with responseData
})
.fail(function(error) {
console.log(error)
})

Related

EJS view will not render when triggered via fetch API

in my client javascript I am using the following function, which is triggered by an onclick event
function submitForm(event) {
const data = { name, image_url };
console.log(data);
fetch('/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
}
The function above sends a post request to the expressJS backend of the app which triggers another function that is supposed to render one of two EJS views. here is the expressJS function
router.post('/', function (req, res) {
console.log('hitting router post');
var { name, imageURL } = req.body;
console.log(name, imageURL);
if (nicknameIsAvailable(name)) {
let user = {
nickname: name,
id: '',
image: imageURL,
};
console.log("new user connecting")
res.cookie('nickname', name, { signed: false });
res.render('chat', { nickname: name });
} else {
console.log('rejecting user ' + name + ' is already taken');
res.render('index', { message: userTakenErrorMessage });
}
});
problem is that res.render does not actually render the EJS view. I think what is happening is that it's sending back the HTML markup of the view to the client side javascript. The desired behavior would be for it to render the "chat" or "index" views with the given arguments. How can I achieve that?
If this approach does not work then what approach could I use to add some data to the body of a request without using a form and then having that request trigger rendering a view?
This is an ajax request, you will receive rendered HTML in the resolved promise of fetch function. To display the response content use:
fetch(...).then(res => res.text()).then(htmlStr => {
document.open();
document.write(htmlStr);
document.close();
})

Uploading Image to Cloudinary Express.js React Axios post request

I am trying to upload images to cloudinary using react front-end and express server.
The problem is i cant properly post request image to my express server.
This is how i prepare image to send it later:
var data = new FormData();
console.log(event.target.files[0]) // this prints FileObject succesfully
data.append('image', event.target.files[0]);
console.log(data) // this prints {} but i guess its natural since its FormData ??
this.imageToUpload = data;
This is how i post request:
axios.post('/api/courses/uploadImage',this.imageToUpload, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then( (response) => {
alert(JSON.stringify(response));
})
.catch(function (error) {
console.log(error);
});
Now in server side,req.body is empty.
router.post("/courses/uploadImage",(req,res,next)=>{
console.log(req.body) // empty
var image = req.body;
cloudinary.uploader.upload(image, function(error, result) { console.log(result) });
})
Also what should i really put to first parameter of(image in this case) uploader.upload ?
Not a direct answer but if you want Cloudinary also offers a way to directly upload images from your front-end so it saves you some work. You can read here further.
I've worked with their widget and it is very simple to integrate into almost any app.
You can do like this. I have successfully tried in my project.
function upload(){
var data = new FormData();
data.append('image', event.target.files[0]);
data.append('username', 'Saurabh'); //if you have other fields
axios.post('/api/courses/uploadImage', data,
headers: {
//your headers
})
.then( (response) => {
alert(JSON.stringify(response));
})
.catch(function (error) {
console.log(error);
});
}
In your express route you can simply get values like this
router.post('/api/courses/uploadImage', upload.single('image'), async(req,res, next) => {
const result = await cloudinary.v2.uploader.upload(req.file.path);
console.log(req.body.username); //Saurabh
//your logic
});
I solved my problem by directly uploading images to cloudinary from client with their html5 codepen example.

Get image as buffer from URL

I have spent couple of hours trying to get image data as a buffer, search results lead me to using "request" module, others suggestions lead to using other modules in higher version of node, which I cannot use because we depend on node v 6.11 so far.
Here are my trials:
request(imageURL).pipe(fs.createWriteStream('downloaded-img-
1.jpg')).on('close', function () {
console.log('ok');
});
request(imageURL, function (err, message, response) {
fs.writeFile('downloaded-img-2.jpg', response, 'binary', function (err) {
console.log('File saved.');
});
fs.writeFile('downloaded-img-3.jpg', chunks, 'binary', function (err) {
console.log('File saved.');
})
resolve(response);
})
.on('data', function (chunk) {
chunks.push(chunk);
})
.on('response', function (response) {
});
});
The "downloaded-img-1.jpg" gets downloaded correctly, but I have to avoid saving the file on disk, then read it as a stream, it's a PRD environment constraint. So the next option is to use image data, as demonstrated by "downloaded-img-2.jpg" and "downloaded-img-3.jpg", by waiting for the "response" or the hand-made "chunks", the problem is that these 2 images are always corrupted, and I don't know why?
What is the point behind all of that? I am trying to add the image behind the URL in a zip file, and the zip lib I use (js-zip) accepts buffer as an input. Any ideas why I am not getting the "chunks" or the "response" correctly?
I've tested the code below in Node 6.9.2, it will download an image as a buffer. I also write the buffer to a file (just to test all is OK!), the body object is a buffer containing the image data:
"use strict";
var request = require('request');
var fs = require('fs');
var options = {
url: "https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Hubble2005-01-barred-spiral-galaxy-NGC1300.jpg/1920px-Hubble2005-01-barred-spiral-galaxy-NGC1300.jpg",
method: "get",
encoding: null
};
console.log('Requesting image..');
request(options, function (error, response, body) {
if (error) {
console.error('error:', error);
} else {
console.log('Response: StatusCode:', response && response.statusCode);
console.log('Response: Body: Length: %d. Is buffer: %s', body.length, (body instanceof Buffer));
fs.writeFileSync('test.jpg', body);
}
});

Send a file from mobile to Node js server

I'm doing an application with react-native. Now I'm trying to send an image from the mobile to the server (Node Js). For this I'm using react-native-image-picker. And the problem is that when I send the image it save a file but it's empty not contain the photo. I think that the problem probably is that the server can't access to the path of the image because is in a different device. But I don't know how I can do it.
React-Native:
openImagePicker(){
const options = {
title: 'Select Avatar',
storageOptions: {
skipBackup: true,
path: 'images'
}
}
ImagePicker.showImagePicker(options, (imagen) =>{
if (imagen.didCancel) {
console.log('User cancelled image picker');
}
else if (imagen.error) {
console.log('ImagePicker Error: ', imagen.error);
}
else if (imagen.customButton) {
console.log('User tapped custom button: ', imagen.customButton);
}
else {
let formdata = new FormData();
formdata.append("file[name]", imagen.fileName);
formdata.append("file[path]", imagen.path);
formdata.append("file[type]", imagen.type);
fetch('http://X/user/photo/58e137dd5d45090d0b000006', {
method: 'PUT',
headers: {
'Content-Type': 'multipart/form-data'
},
body: formdata
})
.then(response => {
console.log("ok");
})
.catch(function(err) {
console.log(err);
})
}})}
Node Js:
addPhotoUser = function (req, res) {
User.findById(req.params.id, function(err, user) {
fs.readFile(req.body.file.path, function (err, data) {
var pwd = 'home/ubuntu/.../';
var newPath = pwd + req.body.file.name;
fs.writeFile(newPath, data, function (err) {
imageUrl: URL + req.body.file.name;
user.save(function(err) {
if(!err) {
console.log('Updated');
} else {
console.log('ERROR: ' + err);
}
res.send(user);
});
});
});
});
};
Yes, the problem is that the filepath is on the local device and not the server. You want to send the actual data returned to you by react-native-image-picker not the uri. It looks like that library encodes the data with base64 so you're going to want send that to your server, not the uri returned from the library because it won't be accessible on a remote server.
What this means is that you won't be reading any files on your server but instead just decoding a base64 string in the response body and writing that to your filesystem.
For the client side:
let formdata = new FormData();
formdata.append("file[name]", imagen.fileName);
formdata.append("file[data]", imagen.data); // this is base64 encoded!
formdata.append("file[type]", imagen.type);
fetch('http://X/user/photo/58e137dd5d45090d0b000006', {
method: 'PUT',
headers: {
'Content-Type': 'multipart/form-data'
},
body: formdata
})
On the server side atob to decode from base64 before writing to the filesystem:
let decoded = atob(req.body.data)
// now this is binary and can written to the filesystem
From there:
fs.writeFile(newPath, decoded, function (err) {
imageUrl: newPath;
user.save(function(err) {
if(!err) {
console.log('Updated');
} else {
console.log('ERROR: ' + err);
}
res.send(user);
});
});
Note, you don't need the filesystem write that's in your code because you're decoding the image that was sent as a b64 string in your request.
There also seems to be some oddities with how you're using that user object. You seem to be only passing a function that handles errors and not any actual data. I don't know what ORM you're using so it's hard to say how it should work. Maybe something like this?
user.save({imageUrl:uriReturnedByFsWrite}, (err, data)=>{...})
Good luck :)
Make an object then send that object to the server. The object will consist of name,path and type, like this:
var imageData = {name: 'image1', path: uri, type: 'image/jpeg'}
Above is a one way to send the image data. The other way is to convert it into BLOB so that server side programmer doesn't have to do this task on their end. You can make BLOB by use of react-native-fetch-blob.
One more way is to directly upload the images to the amazon server(s3) and send the link to the backend..
Function that returns base64 string:
var RNFetchBlob = require('react-native-fetch-blob').default;
getImageAttachment: function(uri_attachment, mimetype_attachment) {
return new Promise((RESOLVE, REJECT) => {
// Fetch attachment
RNFetchBlob.fetch('GET', config.apiRoot+'/app/'+uri_attachment)
.then((response) => {
let base64Str = response.data;
var imageBase64 = 'data:'+mimetype_attachment+';base64,'+base64Str;
// Return base64 image
RESOLVE(imageBase64)
})
}).catch((error) => {
// error handling
console.log("Error: ", error)
});
},
Cheers :)

Node.JS Request Module Callback Not Firing

I'm running this code using the request module for node.js
var hsKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
var hsForm = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
var hsHost = "https://docs.google.com/"
var url = hsHost + "forms/d/" + hsForm + "/formResponse"
var form = {
"entry.129401737": pointsAvg,
"entry.2000749128": hiddenNeurons,
"submit": "Submit",
"formkey": hsKey
};
request.post({
url: url,
form: form
}, function (err, res, body) {
console.log("Sent data");
});
I have tried running the above code just using standard Node.JS libraries, to no avail. The callback function is never fired and the request doesn't go through. I don't know why.
I believe I've found the answer to my own problem. The issue seems to be that I'm not allocating any time in the Node.js event loop to allow the request to be executed.
Have a look at this question:
your code should look something like
var hsKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var hsForm = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var hsHost = "https://docs.google.com/"
var url = hsHost + "forms/d/" + hsForm + "/formResponse"
var form = {
"entry.129401737": pointsAvg,
"entry.2000749128": hiddenNeurons,
"submit": "Submit",
"formkey": hsKey
};
request.post({
url: url,
form: form
}, function (response) {
response.setEncoding('utf8');
response.on('data', function(chunk){
//do something with chunk
});
});
The data event should get fired on receiving a response.
So if you read the docs for the request module at npm
request
.get('http://google.com/img.png')
.on('response', function(response) {
console.log(response.statusCode) // 200
console.log(response.headers['content-type']) // 'image/png'
});
There is a response event that should get fired.
I ran into this as well. I ended up creating a separate js file containing only the request, without the describe and it methods, and running it with 'mocha mynewbarebonesreq.js'. suddenly I could see that there was an exception being thrown and swallowed by mocha (with the standard reporter, spec).
I finally installed and enabled mocha_reporter which shows the exceptions
now it looks like this:
describe('CMSLogin', function () {
it('should log in as user ' + JSON.stringify(USER_PASS), function (done) {
request({
url: "http://cms.lund.multiq.com:3000/api/CMSUsers/login",
method: "POST",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
json: false,
body: JSON.stringify(USER_PASS)
}, (err, res, body) => {
var parsedBody = JSON.parse(body);
this.token = parsedBody.id;
console.log(this.token)
assert.equal(USER_PASS.userId, parsedBody.userId);
assert.doesNotThrow(() => Date.parse(parsedBody.created));
if (err) { done.fail(err); }
done();
});
});
}

Categories

Resources