Search code examples
node.jsstreamfile-writing

Node - Unable to save file stream


I'm using node to post some data to an external service which is supposed to send me back a PDF to save, but I don't think I'm doing either part correctly (I'm new to node). I've looked on forums and tried a dozen ways but I either get a blank PDF or a corrupt one. Here is the code I'm using for the request (in case I'm doing it wrong), although I tried using postman call the service and I get a prompt to save the file, and it works, so it's not the external service for sure.:

var x = {//data to be sent}
var options = {
        method: 'POST',
        uri: '//link',
        form: x,
        headers: {
            "Content-Type": "application/json",
            'Authorization': 'Basic ' + new Buffer("user:pass").toString('base64')
        }
    };

    request(options, function(error, response, body) {
        //How to properly get the stream and save it as a valid PDF?
        //I tried fs.witeFile, createWriteStream, pipe, and a bunch 
        //of other ways without luck.
    });

Here is the response I get from the external service:

{
  "statusCode": 200,
  "body": "%PDF-1.4\n1 0 obj\n<<\n/Title (��)\n/Creato..{//very long response}..",
  "headers": {
    "x-powered-by": "Express",
    "access-control-allow-origin": "*",
    "vary": "Origin",
    "connection": "close",
    "content-type": "application/pdf",
    "content-disposition": "inline; filename=\"report.pdf\"",
    "file-extension": "pdf",
    "number-of-pages": "1",
    "x-xss-protection": "0",
    "set-cookie": [
      "session=_O2T27N......"
    ],
    "date": "Thu, 21 Jan 2016 23:13:16 GMT",
    "transfer-encoding": "chunked"
  },
  "request": {
    "uri": {
      "protocol": "https:",
      "slashes": true,
      "auth": null,
      "host": "xxxxx.net",
      "port": 443,
      "hostname": "xxxxx.net",
      "hash": null,
      "search": null,
      "query": null,
      "pathname": "/api/report",
      "path": "/api/report",
      "href": "https://xxxxx.net/api/report"
    },
    "method": "POST",
    "headers": {
      "Content-Type": "application/x-www-form-urlencoded",
      "Authorization": "Basic aXRA......",
      "content-length": 129
    }
  }
}

If anyone knows how to properly get and save this file, it would be appreciated.


Solution

  • I expect you are using request module which returns a stream. The only thing you need to do is pipe this stream into a file. This is done in the following way

    request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))
    

    The full example can then look like this:

    var options = {
      method: 'POST',
      body: JSON.stringify({ template: { recipe: 'phantom-pdf', engine: 'handlebars', content: 'Hello world'}}),
      uri: 'http://localhost:3000/api/report',
      headers: {
        "Content-Type": "application/json",
        'Authorization': 'Basic ' + new Buffer("admin:password").toString('base64')
      }
    };
    
    request(options, function(error, response, body) {
    
    }).pipe(fs.createWriteStream("report.pdf"))
    

    You may also check jsreport-client which makes remote report rendering easier in node.js.