Home > Enterprise >  File responsed by response.download() and download as blob containing undefined
File responsed by response.download() and download as blob containing undefined

Time:06-02

I'm building a client-server certificate generator.


On Backend I'm using two endpoints:

/
  • Receives a JSON containing data extracted from inputs, sanitize them, and returns if they're valid or not
/download
  • Receives whether data is valid or not. If it's, generate a certificate.pdf file and responses it with res.download(certificatePath)
  • I guess I should use some kind of token/authentication/authorization because someone could just ignore the first endpoint but I'll do that once the downloading itself is fixed

I think the problem with backend is in some of those functions:

const getCertificatePDF = (name, validValuesData, validValuesQty, response) => {
    // ... ommited for brevity
    pdf.create(document, options)
        .then(res => {
            console.log(res)
            let filePath = path.join(__dirname, 'certificate.pdf');
            console.log("FILE PATH: ", filePath);                            
            response.download(filePath, "certificate.pdf");
        })
        .catch(error => {
            console.error(error)
        });
}

app.post('/download', (req, res) => {
    const data = req.body;
    console.log("DATA", data);
    getCertificatePDF(data.name, data.validValuesData, data.validValuesQty, res)
});

On frontend, I chained both requisitions using promises, created a blob, created a link with download attribute for that blob and triggered anonClick:

const sendForm = (filledCodeValues, email, name) =>{
    // ...ommited for brevity

    fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: data,
      })
        .then((res) => res.json())
        .then((processedData) => {
            alertAllFilledInvalid(processedData.validValuesQty)
            const dataString = JSON.stringify(processedData);
            if(processedData.validValuesQty > 0){
                console.log("DATA STRING ", dataString)
                const downloadUrl = url   "download";
                fetch(downloadUrl, {
                    method: "POST",
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: dataString,
                  })
                .then((res2) => {
                    res2.blob()
                })
                .then((blob)=>{
                    const newBlob = new Blob([blob]);
                    const newUrl = window.URL.createObjectURL(newBlob);

                    const link = document.createElement('a');
                    link.href = newUrl;
                    link.setAttribute('download', 'certificate.pdf');
                    document.body.appendChild(link);
                    link.click();
                    link.parentNode.removeChild(link);

                    window.URL.revokeObjectURL(newBlob);
                })
            }
        })
}

Issue

The issue is, the certificate.pdf downloaded by frontend is containing undefined: undefined certificate downloaded by frontend

I know the first request is correct, because the console.log() is printing the expected contents for stringData:

frontend manages to complete first request

I also know the second request work, because on backend, certificate.pdf is being correctly generated:

Backend receives second requisition correctly and generated pdf

Ps - i'm manually deleting certificate.pdf on backend to ensure it's a new one generated

Since certificate is being generated, I believe there's something wrong with either:

  1. Backend'sresponse.download(filePath, "certificate.pdf");
  2. FrontEnd blob creating and downloading

I manually moved certificate(25).pdf (generated by frontend) to backend and run a script for reading both certificate.pdf(generated by backend) files, to test if the issue is on filePath using a readFiles.js script:

const fs = require('fs');
let path = require('path');

let filePath = path.join(__dirname, 'certificate.pdf');
console.log("FILE PATH: ", filePath);
fs.readFile(filePath, 'utf8', (err, data) => {
    if (err) {
        console.error(err);
        return;
    }
    console.log(">>>>> FilePath content <<<<< ", data);
});


let filePath2 = path.join(__dirname, 'certificate(25).pdf');
console.log("FILE PATH 2: ", filePath2);
fs.readFile(filePath2, 'utf8', (err, data) => {
    if (err) {
        console.error(err);
        return;
    }
    console.log(">>>> FilePath2 content <<<< ", data);
});

readFiles

It turns out the path is correct, and certificate.pdf (backend) has content, while certificate(25).pdf (frontend) has just an undefined value.


Can someone help me please?

CodePudding user response:

You need to return the value of res2.blob():

.then((res2) => {
  return res2.blob()
})

Or leave out the brackets:

.then((res2) => res2.blob())
  • Related