Background
I'm generating a PDF file dynamically in the backend of my web app using pdf-lib
. Then, I send the PDF bytes in the form of Uint8Array
to frontend in order to open a new tab that will display the file outside of the app's frontend.
The Problem
While the request is successfully completed with the desired Uint8Array
payload, there is an error alert in the new tab (Chrome) that says:
Error
Failed to load PDF document.
The Uint8Array
data is inside the response body:
{
success: true,
data: {0: 37, 1: 80, 2: 68, 3: 70, 4: 45, ...}
}
What I tried
Before returning the bytes to the frontend I am able to save and access the PDF file on my PC using the fs.readFileSync()
method.
I tried using both Chrome and Edge, but the problem persists.
Backend code
try {
const pdfBytes = await pdfDoc.save() // .save() method returns Promise<Uint8Array>
const filePath = './dddd.pdf'
fs.writeFileSync(filePath, pdfBytes) // This line creates a file to PC successfully
return pdfBytes
} catch (err) {
console.log('erroe while saving');
console.log(err);
}
Frontend Code
if (result.success) {
const pdfBlob = new Blob([result.data], { type: 'application/pdf' })
const pdfURL = URL.createObjectURL(pdfBlob)
console.log(pdfURL); // --> blob:http://localhost:3000/8f168e27-934e-4d80-a479-31975e22eaa1
window.open(pdfURL, '_blank')
}
As it seems the problem is that I cant directly use the .json()
or JSON.stringefy()
methods on an Uint8Array and just send it to the frontend because it corrupts the binary data.
Solution
In the backend, I first had to convert the Uint8Array to a base64string, send the string in a json to the front end, convert the base64string back to Uint8Array and only then create the blob, create a temporary URL and open it in a new tab.
Backend code:
import { NextRequest, NextResponse } from "next/server";
import { generatePdf } from "@/lib/pdf/generate/generatePDF";
export async function POST(req: NextRequest, res: NextResponse , context: {}) {
try {
console.log(' request reached!!!');
const body = await req.json()
const pdfBytes = await generatePdf(body)
const base64PDF = Buffer.from(pdfBytes as Uint8Array).toString('base64')
return NextResponse.json({success: true, data: base64PDF}, { status: 200 })
} catch (err) {
console.log('Error occurred while ...');
console.log(err);
return NextResponse.json({success: false}, { status: 500 })
}
}
Frontend code
if (result.success) {
const base64PDF = result.data;
const pdfBytes = new Uint8Array(atob(base64PDF).split('').map(char => char.charCodeAt(0)));
const pdfBlob = new Blob([pdfBytes], { type: 'application/pdf' });
const pdfURL = URL.createObjectURL(pdfBlob);
window.open(pdfURL, '_blank');
}