`pdfmake` missing docs for node.js create and send binary to client (Lambda as example)
Published: 2018-11-02 04:44:09

---
title: `pdfmake` missing docs for node.js create and send binary to client (Lambda as example)
published: true
description: 
tags: 
---

What for? I needed this to send text-only faxes through Twilio's Fax API, which required a PDF link.

Why `pdfmake`? Why not `puppeteer` on a server/lambda that renders any webpage into PDF? `pdfmake`'s layout language has much more features for paged documents, and I don't need the fancy stuff html+css+js affords. `pdfmake` has tables and columns and good font support. Having worked with html to print layout I know how much of a pain in the ass it is.

On to the documentation

First of all `pdfmake` is, I believe a wrapper around `pdfkit`. `pdfkit` does not have any convenient features to generate documents other than one-column stuff. `pdfmake` can do tons, but an API doc is non-existence.

The best place to discover features and usage is the [README](https://github.com/bpampuch/pdfmake/blob/master/README.md) and the [Playground](http://pdfmake.org/playground.html). Neither is comprehensive.

The docs also assume browser usage. Server side is VERY different. Here's what I gathered from various Github Issues and past experience with `pdfkit`, which also does not have a comprehensive documentation. This script creates a pdf as binary, which you can send directly to client.

You need to download Roboto fonts from google fonts and place it in the project folder of your script, then reference them in the `fonts` object in the code below.

Roboto is the default font used, so if you produce a pdf document without specifying any font, that's what it will use. So having Roboto avoids all bugs caused by not having a fallback font.

```js
import {Base64Encode} from 'base64-stream'
const PdfPrinter = require('pdfMake/src/printer')
const fonts = {
      Roboto: {
          normal: './fonts/Roboto-Medium.ttf',
          bold: './fonts/Roboto-Black.ttf',
          italics: './fonts/Roboto-MediumItalic.ttf',
          bolditalics: './fonts/Roboto-BlackItalic.ttf'
      }
    };
const printer = new PdfPrinter(fonts)
const docDef = {content: 'Hello World'}
const doc = printer.createPdfKitDocument(docDef)
const stream = doc.pipe(new Base64Encode())
doc.end()
let finalString = ''
stream.on('data', function(chunk) {
  finalString += chunk;
});
stream.on('end', function() {
  console.log('binary pdf: ', finalString)
});

```

For an express server, simply send respond with finalString in the `body` and set `Content-Type` to `application/pdf`. Still need help? search for "responding with pdf binary in express". There are many solutions.

I use it on a AWS Lambda via [serverless nodejs starter kit](https://github.com/AnomalyInnovations/serverless-nodejs-starter.git). It cannot work with callbacks, just promises (there may be a solution but you don't need callbacks). You can wrap `stream.on` in a new `Promsise`

```js
return new Promise((resolve, reject) => {
  stream.on('end', function() {
    resolve(finalString)
  });
})
```

Also AWS Lambda by default does not support binary response, so you need a plugin called `serverless-apigw-binary`. But the plugin doesn't have instructions for PDF binary, which is:

```yaml
custom:
  apigwBinary:
    types:  
      - '*/*'
```

Having `application/pdf` as types does not work here for reasons I don't know.

This configuration can cause bugs with normal lambda functions (e.g. CORS won't work for your other functions, I don't know about the pdf function itself, you may test). So you should not have other functions that deal with text responses in the same project. The underlying reason is that all functions in the same project share an API Gateway, which is now configured to treat all content types as binary.

That's all the missing docs for the project I needed to do.

Contact me if you want a working example.