How to download data created server-side with Node.js? - javascript

I want to retrieve some data from my REST API in Node to the user directly downloaded in json file when he clicks a link.
I tried some stuff using Blop, but it is not working in my case I don't understand why...
HTML
<div class='wrapper_align_vertical'>
<a class='shortCut' id='extract'>Extract</a>
</div>
JS (sample that is working)
Viewed this example on internet and worked well with sample data.
document.getElementById('extract').onclick = function(event){
var data = { a: 1, b: "hello" }
var json = JSON.stringify(data)
var blob = new Blob([json], {type: "octet/stream"})
var url = window.URL.createObjectURL(blob)
this.href = url
this.target = '_blank'
// target filename
this.download = 'data.json'
}
But in my case I am calling API to gather data from database before creating the blop.
How I am getting data
I am calling the API with ajax request.
function getFromDB(){
return new Promise(function(resolve, reject){
$.ajax({
url: '/api/extract',
dataType: "json",
type: 'GET',
headers: {
"x-access-token" : getCookie('token')
},
success: function(data){
if(data.success == 'true'){
resolve(data)
} else{
reject('Promise getFromDB failed !')
}
}
})
})
}
EDIT : I added error verification in case the promise fail, and it is not the case unfortunately ! Moreover I printed the data in the console and everything seems fine, it is complete... Resolve data is sending back the right json object.
What return the route /api/extract
The route get data from DB.
router.get('/', function(req, res, next){
var query = 'SELECT ...'
connection.query(query, function(err, rows){
var result = []
if(!err){
for(label in rows){
result.push(rows[label].path)
}
res.json({
success: true,
data:{
quantity : rows.length,
image: result
}
})
}else{
res.json({
success: false,
message: 'Failure while extracting tags from database !'
})
}
})
})
What I want to do
But it is absolutely not working, maybe I am missing something ?
document.getElementById('extract').onclick = function(event){
getFromDB()
.then(function(data){
var json = JSON.stringify(data)
var blob = new Blob([json], {type: "octet/stream"})
var url = window.URL.createObjectURL(blob)
this.href = url
this.target = '_blank'
this.download = 'data.json'
}, function(err){
// Promise failed
console.log(err)
})
}
More informations
I saw something else that might help debugging... While using the API with Postman I am getting header 200 :
GET /api/extract 200 5.484 ms - 375
BUT ! When it's through the ajax call, I get code 304 :
GET /api/extract 304 6.339 ms - -
If you have any advice or suggestion I'll appreciate, thank you !

Related

Express API Call returning Text/HTML

Currently creating an API with Express.js and trying to call it via Javascript on a plain page.
This is the express.js code:
// Display all accounts
exports.get_accounts = function(req, res) {
// res.send("Front end not implemented: List all accounts");
var params = {
TableName: "HouseAccounts",
}
docClient.scan(params, onScan);
function onScan(err, data) {
if (err) {
console.error("Unable to read: ", JSON.stringify(err, null, 2));
}
else {
res.header("Content-Type",'application/json');
return data.Items;
}
}
}
And this is the call from javascript
var $api = jQuery.noConflict();
const proxyurl = "https://cors-anywhere.herokuapp.com/";
$api(document).ready(function() {
fetch(proxyurl + "myURL/accounts")
.then(res => console.log(res));
});
If I log res to the console, I receive:
Response {type: "cors", url: "https://cors-anywhere.herokuapp.com/https://039f1b…aab34.vfs.cloud9.us-east-2.amazonaws.com/accounts", redirected: false, status: 499, ok: false, …}
This does not contain the data from my database. I know the route itself is working because if I visit the localhost page I can see the data being displayed. If I do console.log(res.json()) I receive SyntaxError: Unexpected token < in JSON at position 0.
In the network tab, it's showing that the data is coming over as text/html. I'm not sure why the data is not coming over as JSON.

How to return database data in HTTP get method

In server side,I fetch data from database
var sql = require('mssql');
app.get('/api/comments', function(request, response) {
var sqlConfig = {
// Connection string parameters.
}
sql.connect(sqlConfig, function() {
var request = new sql.Request();
var stringRequest = 'select TOP 10 * from comment';
request.query(stringRequest, function(err, recordset) {
if(err) console.log(err);
sql.close();
response.json(recordset);
});
});
});
Then,I fetch the data from server side by AJAX (get method)
_fetchComments() {
jQuery.ajax({
method: 'GET',
url: '/api/comments',
success: (comments) => {
this.setState({ comments })
}
});
I get an error when I get the data by Ajax.
(Uncaught TypeError: this.state.comments.map is not a function)
It seems that the data return is undefined.Instead of fetching database,the code is work if I use static data(hard code) in server side.
I think the problem is the callback function in sql.connect() but I have no idea how to solve it.Does anyone can help?
Error:
The solution is adding dataType: 'json' to the ajax
_fetchComments() {
jQuery.ajax({
method: 'GET',
url: '/api/comments',
dataType: 'json',
success: (comments) => {
this.setState({ comments })
}
});
}

res.send not working properly

I am working with a simple CRUD app with jquery ajax and node.js, just to improve my skills with node and ajax. The thing is that I am doing a post request that is handled with my post router in the node server, and everything is working fine. It adds 1 more product to my products.json file, but in the end it doesn't send the response back to the client, the final res.send("done") doesn't work and I don't know why..
here is the code:
ajax
$("#create-form").on('submit',function(){
event.preventDefault();
var createIn = $("#create-input").val();
$.ajax({
url: '/products',
method:'POST',
data:JSON.stringify({name:createIn}),
contentType: "application/json",
dataType: "json",
success: function(data){
console.log(data);
$("create-input").val("");
$("get-button").click();
}
});
})
node
app.post('/products',function(req,res){
fs.readFile('products.json','utf8',function(err,data){
var result = JSON.parse(data);
var productName = req.body.name;
console.log(req.body.name);
currentId++;
var productId = currentId;
var product = {
name: productName,
id: productId
}
result.products.push(product);
fs.writeFile(__dirname + "/products.json",JSON.stringify(result),'utf8');
});
res.send("post done");
});
This is just the important part of the code, it works and just fails at the end in the res.send.
Your client code is looking for a json response, but you are returning a string.
$("#create-form").on('submit',function(){
event.preventDefault();
var createIn = $("#create-input").val();
$.ajax({
url: '/products',
method:'POST',
data:JSON.stringify({name:createIn}),
contentType: "application/json",
dataType: "json", <--------------
success: function(data){
console.log(data);
$("create-input").val("");
$("get-button").click();
}
});
})
Either delete this line or add on the server side
res.send({"message":"post done"});
This does not answer your question directly but you should ideally not send back the response until you know the work has been done, and you should handle errors. In other words you should use the callbacks. (Too many callbacks can be problematic and you should investigate other patterns - eg promises - bit no need here)
app.post('/products',function(req,res){
fs.readFile('products.json','utf8',function(err,data){
if (err) return res.send("error");
var result = JSON.parse(data);
var productName = req.body.name;
console.log(req.body.name);
currentId++;
var productId = currentId;
var product = {
name: productName,
id: productId
}
result.products.push(product);
fs.writeFile(__dirname + "/products.json",JSON.stringify(result),'utf8', function(err, res) {
if (err) return res.send("error");
res.send("post done");
});
});
});

Download a CSV file in EmberJs

I have tried a myriad of different function calls, but can't seem to figure out how to trigger a download for a CSV in EmberJs.
Here is my latest code:
let endpoint = '/api/foo/';
let options = {
url: endpoint,
type: 'POST',
data: {},
dataType: 'text'
};
return new Ember.RSVP.Promise((resolve, reject) => {
options.success = function(result) {
var uri = 'data:application/csv;charset=UTF-8,' + encodeURIComponent(result);
window.open(uri, 'foo.csv');
};
options.error = (xhr, errorThrown) => {
console.log('error');
// return Ember.run(null, reject, this.didError(xhr, xhr.status, xhr.responseJSON, 1));
};
Ember.$.ajax(options);
});
This code doesn't raise any server or client side errors. It's getting a 200 response. No javascript errors, and doesn't console log anything, so I know it's not hitting the error block. But... it won't trigger the file download on the client. Does anyone know what is missing?
I am unable to test this, but I believe your issue is with returning a new promise, whereas what you really want is to return the promise itself.
So change your code to:
let endpoint = '/api/foo/';
let options = {
url: endpoint,
type: 'POST',
data: {},
dataType: 'text'
};
return Ember.RSVP.Promise((resolve, reject) => { // note the deletion of new
options.success = function(result) {
var uri = 'data:application/csv;charset=UTF-8,' + encodeURIComponent(result);
window.open(uri, 'foo.csv');
};
options.error = (xhr, errorThrown) => {
console.log('error');
// return Ember.run(null, reject, this.didError(xhr, xhr.status, xhr.responseJSON, 1));
};
Ember.$.ajax(options);
});
In implementing a similar piece of functionality, I went for a different route. Rather than creating an AJAX request, I create a form and submit it to the server. My API endpoint will then return the CSV in the response, with the appropriate Content-Disposition headers, and the browser will just download the file.
(Depending on your authentication scheme, you may have to include your authentication token as a value in your form data).
Example code below. You'll see I'm adding the auth token. The form's action URL is set in the markup of the page, but you could set it dynamically here if you wanted.
csvDownload () {
let form = Ember.$('#csvdownloadform')
let input = Ember.$('#csvdownloadtoken')
input.val(this.get('session').get('session.content.authenticated.token'))
form.submit()
input.val('')
form_func.val('')
},

AJAX requests to Node.JS to update JSON file for Jquery-comments

Jeez... How about that title, terrible lol.
Well I am using jquery-comments by Viima. (http://viima.github.io/jquery-comments/)
I'm trying to use ajax commands to a Node.JS script that will update a JSON file. All of which is local, no crossing domains or anything.
Here is my Node.JS script:
var http = require('http');
var fs = require('fs');
http.createServer(function (req, res) {
fs.writeFile("/comments-data.json", "commentJSON", function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
});
}).listen(8080, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8080/');
Here is the Ajax post
postComment: function(commentJSON, success, error) {
$.ajax({
type: 'post',
url: 'http://127.0.0.1:8080',
data: commentJSON,
success: function(comment) {
success(comment)
},
error: error
});
},
I don't want to redirect. I just wanted to asynchronously show the new comment. Also this script will ultimately have to be able to handle video attachments as well and store the filepath inside the JSON file. But i believe, Jquery-comments just reads the file path from the JSON
Here is what the support site says for attachments
uploadAttachments: function(commentArray, success, error) {
var responses = 0;
var successfulUploads = [];
var serverResponded = function() {
responses++;
// Check if all requests have finished
if(responses == commentArray.length) {
// Case: all failed
if(successfulUploads.length == 0) {
error();
// Case: some succeeded
} else {
success(successfulUploads)
}
}
}
$(commentArray).each(function(index, commentJSON) {
// Create form data
var formData = new FormData();
$(Object.keys(commentJSON)).each(function(index, key) {
var value = commentJSON[key];
if(value) formData.append(key, value);
});
$.ajax({
url: '/api/comments/',
type: 'POST',
data: formData,
cache: false,
contentType: false,
processData: false,
success: function(commentJSON) {
successfulUploads.push(commentJSON);
serverResponded();
},
error: function(data) {
serverResponded();
},
});
});
}
});

Categories