firebasegoogle-cloud-platformgoogle-cloud-functionsfirebase-storagepdfmake

How to generate pdf with pdfmake and store it at firebase storage with firebase cloud functions


I am developing an application in firebase. When an order is created I want to generate its invoice. I have implemented the function, but something is wrong with the URLs because the pdf is created, but as you can see in the image the URL to open it is wrong.

This is my code in Cloud Function index.js:

'use strict';

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const nodemailer = require('nodemailer');
//...

var PdfPrinter = require('pdfmake');
const fs = require('fs');

var fonts = {
  Courier: {
    normal: 'Courier',
    bold: 'Courier-Bold',
    italics: 'Courier-Oblique',
    bolditalics: 'Courier-BoldOblique'
  },
  Helvetica: {
    normal: 'Helvetica',
    bold: 'Helvetica-Bold',
    italics: 'Helvetica-Oblique',
    bolditalics: 'Helvetica-BoldOblique'
  },
  Times: {
    normal: 'Times-Roman',
    bold: 'Times-Bold',
    italics: 'Times-Italic',
    bolditalics: 'Times-BoldItalic'
  },
  Symbol: {
    normal: 'Symbol'
  },
  ZapfDingbats: {
    normal: 'ZapfDingbats'
  }
};

exports.generateInvoice = functions.database.ref('/pedidos/{documentId}').onCreate((snap, context) => {
  return (async () => {
    var docDefinition = {
      pageSize: 'A4',
      pageOrientation: 'portrait',
      content: [
        //Cabecera
        { image: 'img/logo.png', width: 90, alignment: 'left' },
        { text: `Pedido${snap.key}`, fontSize: 32, margin: [0, 8, 0, 0] }
      
        //Body
      ],
      defaultStyle: {
        font: 'Helvetica'
      }
    };
    console.log("Doc defined okey");

    const pdfName = snap.key + ".pdf";
    const fileName = "pedidos/" + pdfName;
    const myPDFfile = admin.storage().bucket().file(fileName);

    var printer = new PdfPrinter(fonts);
    var pdfDoc = printer.createPdfKitDocument(docDefinition);
    pdfDoc.pipe(myPDFfile.createWriteStream());
    pdfDoc.end();

  })().then(() => {

  }).catch (err => {
    console.log("An error has ocurred " + err);
  });
});

As you can see, the pdf is created correctly but the URL is wrong and I can't open it.

enter image description here

I would be very grateful if someone helped me.


Solution

  • This is a known problem when uploading files to Cloud Storage via the Admin SDK, see https://github.com/firebase/firebase-admin-node/issues/694.

    As you will read there are mainly two possible approaches:


    If you want to use the second option (despite the fact it seems to be not recommended), the following would do the trick:

    const pdfDoc = printer.createPdfKitDocument(docDefinition);
    pdfDoc.pipe(myPDFfile.createWriteStream());
    
    pdfDoc.on('end', async function () {
       const uniqueId = admin.firestore().collection("_").doc().id;
       await myPDFfile.setMetadata({
            metadata: {
               firebaseStorageDownloadTokens: uniqueId,
            }
       });
    });
    
    pdfDoc.end();
    

    I would recommend the first approach however, with the getSignedUrl() method.