13

Recently I have started working with node.js. While going through a requirement in one of my projects I am facing an issue where I should be able to write some data to a csv file dynamically and let it prompt as a popup to download for user (with save and cancel options - as we normally see). After googling for some time I decided to use csv npm module https://github.com/wdavidw/node-csv-parser. I am able to write data into a file and save it using this module. I want to prompt a popup for saving this file with/without saving the file.

my code looks something like this:

    // Sample Data 
    var data = [["id", "subject1", "subject2", "subject3"], ["jack", 85, 90, 68], ["sam", 77, 89, 69]]

    // Server Side Code    
    var csv = require('../../node_modules/csv');            
    var fs = require('fs');

    createCSV = function(data, callback) {
        csv().from(data).to(fs.createWriteStream('D:/test.csv')) // writing to a file           
    }

    // Client side call sample
    $("#exportToCSV").click(function() {
        callToServer.createCSV(data);
       return false;
    });

This is working good as far as writing the csv file is concerned.

  • I want to prompt this file immediately to download for users.
  • If this can be done without saving the file, that will be great.
  • How can I set content-type and content-disposition as we do in PHP

Any help is greatly appreciated. -Thanks

Manish Kumar
  • 15,269
  • 5
  • 18
  • 27

5 Answers5

36

Manish Kumar's answer is spot on - just wanted to include a Express 4 syntax variant to accomplish this:

function(req, res) {
  var csv = GET_CSV_DATA // Not including for example.

  res.setHeader('Content-disposition', 'attachment; filename=testing.csv');
  res.set('Content-Type', 'text/csv');
  res.status(200).send(csv);

}
joel.software
  • 1,505
  • 1
  • 12
  • 15
  • 7
    I feel like it is confusing and inconsistent to mix `setHeader` with `set`. Even though they do the same thing, they come from different places. Using `setHeader()` comes from NodeJS's `http` module. If you use `res.set`, that is from the Express framework; it allows for setting multiple headers if you give it an object: `res.set({ 'Content-Disposition': 'attachment; filename=testing.csv', 'Content-Type': 'text/csv' })` – nbkhope Mar 22 '18 at 21:27
15

I did it something like this :

http.createServer(function(request, response) {
    response.setHeader('Content-disposition', 'attachment; filename=testing.csv');
    response.writeHead(200, {
        'Content-Type': 'text/csv'
    });

    csv().from(data).to(response)

})
.listen(3000);
Manish Kumar
  • 15,269
  • 5
  • 18
  • 27
  • Just a note, once you complete the above server code, link your client side location.href to the node request url [no need for ajax call]. – vinod Sep 08 '15 at 09:23
  • A quick note on syntax for Express 4: res.setHeader('Content-disposition', 'attachment; filename=testing.csv'); res.set('Content-Type', 'text/csv'); res.status(200).send(csv); – joel.software Nov 06 '15 at 19:25
  • without csv library, and without express, instead of the csv() line, you can do response.write(myCSVText); resonse.end(); – ABCD.ca Jul 21 '16 at 18:56
12

Following solution is for Express

Express is evolved, instead of setting attachment and content type header, directly use attachment api http://expressjs.com/4x/api.html#res.attachment

Note: attachment() don't transfer the file, it just sets filename in header.

response.attachment('testing.csv');
csv().from(data).to(response);
Palani
  • 8,962
  • 11
  • 53
  • 62
3

Express-csv is a great module for writing csv contents to stream from a node.js server, which will be sent as a response to the client (and downloaded as a file). Very easy to use.

app.get('/', function(req, res) {
  res.csv([
    ["a", "b", "c"]
  , ["d", "e", "f"]
  ]);
});

The docs: https://www.npmjs.com/package/express-csv

When you pass an object, you need to prepend the headers explicitly (if you want them). Here's my my example using npm mysql

router.route('/api/report')
    .get(function(req, res) {
            query = connection.query('select * from table where table_id=1;', function(err, rows, fields) {
                if (err) {
                    res.send(err);
                }
                var headers = {};
                for (key in rows[0]) {
                    headers[key] = key;
                }
                rows.unshift(headers);
                res.csv(rows);
            });
    });
Federico
  • 6,388
  • 6
  • 35
  • 43
0

Check out this answer: Nodejs send file in response

Basically, you don't have to save the file to the hard drive. Instead, try sending it directly to the response. If you're using something like Express then it would look something like this:

var csv = require('csv');
req.get('/getCsv', function (req, res) {
    csv().from(req.body).to(res);
});
Community
  • 1
  • 1
Max
  • 8,671
  • 4
  • 33
  • 46
  • I am not using express, but just a custom framework of node.js – Manish Kumar Oct 26 '12 at 11:45
  • Either way, the `http` module responds to requests with callbacks of the same parameters, `function (request, response)`. I think you should be able to send the results of the CSV directly to the `response`. – Max Oct 26 '12 at 14:16