Search code examples
node.jspdfloopbackjsstronglooploopback

Loopback - download pdf using remote method


I wanted to download a pdf file from a third party API using a remote method, my implementation is:

Staff.statement = async (id, year, month) => {
  const fileData = await ThirdPartyAPI.restGET(id, year, month);
  const filename = `Statement_${month}${year}.pdf`;
  return [fileData, 'application/pdf', `inline;filename=${filename}`];
};

Staff.remoteMethod('statement ', {
  accepts: [
    { arg: 'id', type: 'any', required: true },
    { arg: 'year', type: 'string', required: true },
    { arg: 'month', type: 'string', required: true }
  ],
  description: 'Download statement file',
  http: { path: '/:id/statement', verb: 'GET' },
  returns: [
    { arg: 'body', type: 'file', root: true },
    { arg: 'Content-Type', type: 'string', http: { target: 'header' } },
    { arg: 'Content-Disposition', type: 'string', http: { target: 'header' } }
});

The issue is that the file gets view/downloads properly (if I set Content-Disposition: attachment;filename=${filename}) but it was a blank pdf:

enter image description here

I check the response data from the swagger and the data was the same as the one I get directly from the third party API:

enter image description here

This is the response headers:

{
  "strict-transport-security": "max-age=0; includeSubDomains",
  "content-encoding": "",
  "x-content-type-options": "nosniff",
  "date": "Mon, 16 Jul 2018 04:50:36 GMT",
  "x-download-options": "noopen",
  "x-frame-options": "SAMEORIGIN",
  "content-type": "application/pdf",
  "transfer-encoding": "chunked",
  "content-disposition": "inline;filename=Statement_062016.pdf",
  "connection": "keep-alive",
  "access-control-allow-credentials": "true",
  "vary": "Origin",
  "x-xss-protection": "1; mode=block"
}

What is wrong with the display or data?

Updates: My implementation after the help of Mohammad Raheem

Staff.statement = (id, year, month, res, cb) => {
    const options = {
      url: // {{request_url}},
      headers: {
        authorization: // {{token}}
      }
    }; 

    request(options)
      .on('error', err => cb(err))
      .on('response', response => cb(null, response, 'application/pdf'))
      .pipe(res);

    // using 'request-promise' package:
    // request(options)
    //   .then(response => cb(null, response, 'application/pdf'))
    //   .catch(err => cb(err));
  };
};

Staff.remoteMethod('statement ', {
  accepts: [
    { arg: 'id', type: 'any', required: true },
    { arg: 'year', type: 'string', required: true },
    { arg: 'month', type: 'string', required: true },
    { arg: 'res', type: 'object', http: { source: 'res' } }
  ],
  description: 'Download statement file',
  http: { path: '/:id/statement', verb: 'GET' },
  returns: [
    { arg: 'body', type: 'file', root: true },
    { arg: 'Content-Type', type: 'string', http: { target: 'header' } }
});

Solution

  • You can check here I did sample code for downloading pdf file

        var request = require('request');
        var fs = require("fs");
    
    var _downloadPdf = function (url,callback) {
        var url = 'your-url';
        var options = {
            method: 'GET',
            url: url,
            headers: {
                'Content-Type': 'application/pdf',
            }
        };
        var _filepath = 'D://Node/upload/temp/sample.pdf';
        //If you want to go with pipe in case of chunk data
        var dest = fs.createWriteStream(filepath);
        request(options, function (error, response, body) {
            if (error)
                throw new Error(error);
    
        }).on('end', function () {
            return callback(filepath);
        }).on('error', function (err) {
            return callback(err);
        }).pipe(dest);
    }