Getting pdf file from api response

Viewed 12901

I am calling an api and getting pdf in return.

fetch(`api` + guid, {
   method: "GET",
   headers: {
    "Accept": "application/octet-stream",
    "Authorization": "Bearer " + token,
   },
   responseType: 'arraybuffer',
})
.then((res) => res.text())
.then((data) => {
    fs.writeFileSync('file.pdf', data);
});

I get the pdf file but the issue is the pdf file is always empty. But when I accept response as json, it works fine.

I found similar problems like this but none of the solution worked for me yet.

It would be great if someone can point out the issue.

4 Answers

I found the issue. As I am using fetch not Axios. We cannot pass responseType as Fetch's option.

fetch(`api` + guid, {
   method: "GET",
   headers: {
    "Accept": "application/octet-stream",
    "Authorization": "Bearer " + token,
   },
   // responseType: 'arraybuffer' //#1 remove this,
})

Instead the response in itself can be passed as arraybuffer as below.

.then((res) => res.arraybuffer())

instead of

.then((res) => res.text())

Now instead of directly using the response to write our pdf file. We can change the data to base64 string and decode it back again to create our pdf file. I used base64ToPdf npm package to handle that.

.then(data => {
  var base64Str = Buffer.from(data).toString('base64');
  base64.base64Decode(base64Str, "file.pdf");
})

I hope this help others. :)

    Change res.arraybuffer() to  res.arrayBuffer()

Below is the working code with webdriverio-

  var headers = {
            Authorization: "Bearer " + accessToken,
            Accept: 'application/pdf'
        }
       
           fetch(
                apiurl,
                {
                    headers: {
                        Accept: "application/octet-stream",
                        Authorization: "Bearer " + accessToken
                    },
                },
            )
                .then((res) => {
                    if (!res.ok) {
                        return res.status.toString()
                    }
                    return res.arrayBuffer()
                })
                .then((data) => {
                    var base64Str = Buffer.from(data).toString('base64');
                    base64.base64Decode(base64Str, filename);
                })
                .catch(
                    (err) => {
                        return err.Message;
                    })

    

Here's example which works for me:

async createPdf(context, data) {
    let url = new URL(baseURL + '/invoice/createPdf');
    url.search = new URLSearchParams({
        id: data
    })

    await fetch(url, {
        method: 'GET',
        headers: {
            'Authorization': "Bearer " + localStorage.getItem("jwt"),
            'Accept': 'application/octet-stream'
        },
    }).then((res) => res.arrayBuffer())
        .then(data => {
            var base64Str = Buffer.from(data).toString('base64');

            var binaryString = window.atob(base64Str);
            var binaryLen = binaryString.length;
            var bytes = new Uint8Array(binaryLen);
            for (var i = 0; i < binaryLen; i++) {
                var ascii = binaryString.charCodeAt(i);
                bytes[i] = ascii;
            }
            var arrBuffer = bytes;

            var newBlob = new Blob([arrBuffer], { type: "application/pdf" });

            if (window.navigator && window.navigator.msSaveOrOpenBlob) {
                window.navigator.msSaveOrOpenBlob(newBlob);
                return;
            }

            data = window.URL.createObjectURL(newBlob);

            var link = document.createElement('a');
            document.body.appendChild(link);
            link.href = data;
            link.download = "Faktura.pdf";
            link.click();
            window.URL.revokeObjectURL(data);
            link.remove();
        })
}

In my case, the response is same as yours and I'm trying to convert it to a pdf file so that I can preview it on the UI.

For this, I need to fetch the URL already present in the response which is of type blob... to fetch the URL I did URL.createObjectURL(myblob)

const [url,seturl] = useState('');
response
  .then((resp) => resp.blob())
  .then((myBlob) => {
    seturl(URL.createObjectURL(myBlob)); //<-- use this for fetching url from your response
    console.log(myBlob);
  })
  .catch((err) => {
    console.log(err.message());
  });
Related