Generating PDF Documents on the Fly Using Nodejs and Bull
Tags: node, redis
Published: 2021-04-19 08:55:30

PDF documents are commonly used files in the majority of web applications. PDF documents are used in billing invoices, generating transaction reports, drafting the online agreement, etc. If you are building a SaaS then you might end up writing code or using a service to handle generating PDF documents on the fly as required by the system. 

In this tutorial, we are going to learn how to generate PDF documents on the fly using Node.js and the Bull queue system. 

<h2>Generating PDF Documents using Nodejs and Bull</h2>
Bull is a Redis-backed queue system built for scalability. To use Bull, you must have Redis key-value database running in your system. You can download and run Redis by following the guide from the <a href="https://redis.io/download" rel="noopener" target="_blank">official download page of Redis</a>.

Let's begin with the project.

<h3>Create new project in Node</h3>
To create a new project in Node, create a new folder and name it as you like, open the terminal or command prompt and switch to the folder you created using the <strong>cd</strong> command.

Run this command to create a new Node project.

```
npm init --y
```

This command will generate the boilerplate <strong>package.json</strong> for your project.

Run this command to install the dependencies required by the project.

```
npm install --save bull pdfkit
```

Let's code our project. Our codebase is divided into two important files, first is <strong>job.js</strong> which is responsible for creating <strong>jobs</strong> in the queue, and the second file is <strong>worker.js</strong> responsible for fulfilling the jobs and creating PDF files. 

Let's check out each file and codebase first. Here is the job.js code.

```javascript
const bull = require('bull');
const invoice = require('./invoice');
const queue = new bull('pdf-generation');

function startJob() {
    let invoiceData = invoice.content;
    invoiceData.forEach(async (singleInvoice) => {
        // push data in queue
        let job = await queue.add({
            title: `Generate invoice ${singleInvoice.index}`,
            template: singleInvoice.text,
        }, {'delay': 1000});
    });
}

startJob();
```


In this file, we are going through all the records present in the <strong>invoice.js</strong> file. This is for sample record purposes, you can very well use the database records to the same.

Here is the sample content of <strong>invoice.js</strong>.

```javascript
module.exports = {
    content: [{
        'index': 1,
        'text': 'Hello Shahid, You are charged $100 this month for services.'
    },{
        'index': 2,
        'text': 'Hello Jack, You are charged $50 this month for services.'
    },{
        'index': 3,
        'text': 'Hello Linda, You are charged $76 this month for services.'
    }]
}
```

The codebase in <strong>job.js</strong> retrieve and loop over this records and creates jobs in the queue for each record by having a delay of 1000ms. Let's check out our <strong>worker.js</strong> code.

```javascript
const bull = require("bull");
const queue = new bull('pdf-generation');
const pdfKit = require('pdfkit');
const fs = require('fs');

function startProcess() {
    // listen to the queue
    // start processing email
    queue.process((job) => {
        // on each request generate the pdf
        console.log(`Processing Job with id ${job.id}`);
        generatePdfInvoice(job.data);
    });
}

function generatePdfInvoice(data) {
    let doc = new pdfKit;
    doc.pipe(fs.createWriteStream(`${__dirname}/invoice/${data.title}.pdf`));
    doc.fontSize(14).text(data.template, 100, 100);
    doc.end();    
    console.log(`Generated PDF document`);
}

startProcess();
console.log('Worker running');
```

We are using a node module called <strong>pdfkit</strong> to generate our PDF documents. The function <strong>startProcess()</strong> invokes the worker job and it listens to the queue and wait for any messages.

Once it receives a message, we are calling <strong>generatePdfInvoice()</strong> function with the information received in the message. In the <strong>generatePdfInvoice()</strong> function, we are creating the PDF record by using the data coming from the queue and writing the PDF file in the <strong>invoice</strong> folder. 

Let's run the code and see it's working.

First, run the job.js code using the following command.

```
node job.js
```

Then, run the worker.js file.

```
node worker.js
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pdkf381l57n5kd0xpizn.png)

Open the invoice folder and check the PDF files.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e442vtf0pzogv6139o9s.png)

We have successfully created the PDF file. This is a sample PDF file and you can add as many details as you want including images, tables, etc in your PDF files. 

<h2>Conclusion</h2>
We have studied how to use Node and queue systems such as Bull to design and build systems to generate PDF documents on the fly for business purposes.

This article was first published on [codeforgeek.com](https://codeforgeek.com/generating-pdf-documents-on-the-fly-using-nodejs-and-bull/)