Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node express HTML to PDF

I'm looking to render a pdf version of a webpage directly to the browser using express. Something like express.render() only render the page as pdf

I have found a module that will convert HTML or a URL to a pdf

https://github.com/marcbachmann/node-html-pdf

What i need to know is how can I use the response from that libary directly in a HTTP route handler to respond to requests with the PDF, I would prefer not to store the PDF, I just want to render it on the fly, and return it as a buffer or a stream to the browser

This is the basic API the module provides:

var pdf = require('html-pdf');
pdf.create(html).toFile([filepath, ]function(err, res){
  console.log(res.filename);
});

pdf.create(html).toStream(function(err, stream){
  stream.pipe(fs.createWriteStream('./foo.pdf'));
});

pdf.create(html).toBuffer(function(err, buffer){
  console.log('This is a buffer:', Buffer.isBuffer(buffer));
});

I want to use one of these methods stream or buffer and wrap it in a route handler like this one:

router.get('invoice/pdf', function(req, res) {
    res.status(200).send(..pdf data);
});
like image 877
MartinWebb Avatar asked Apr 17 '17 17:04

MartinWebb


1 Answers

This is quite easy to do in Node just using streams. The primary reason to use a stream over a Buffer is that a stream doesn't need to keep all of its data in memory like a Buffer does. Instead it can provide the data as needed to the reader or writer. This means that it is lightweight and will be better for performance in regards to latency and throughput.

In your case, you just want to pipe() the contents of the stream directly to your res object.

router.get('/invoice/pdf', (req, res) => {
  pdf.create(html).toStream((err, pdfStream) => {
    if (err) {   
      // handle error and return a error response code
      console.log(err)
      return res.sendStatus(500)
    } else {
      // send a status code of 200 OK
      res.statusCode = 200             

      // once we are done reading end the response
      pdfStream.on('end', () => {
        // done reading
        return res.end()
      })

      // pipe the contents of the PDF directly to the response
      pdfStream.pipe(res)
    }
  })
})
like image 67
peteb Avatar answered Oct 18 '22 03:10

peteb