Anandu Babu
Anandu Babu

Reputation: 181

How to properly send a blob or file as api response in next 13

I am trying to send a blob (will be a file from another API in future) as the response for a api call in next13 api routes. My handler goes like:

export default async function handler(req, res) {
  const endpoint = `${process.env.UI_ENGINE}/docs/${req.query.id}/download-doc`;

  
    const response = await fetch(endpoint, {
       headers: { Authorization: `${req.headers.authorization}` },
    });

    const blob = await response.blob();
 

    console.log("»»»»»» [DEBUG : blob ] -- :", blob); // Blob { size: 1545, type: 'application/json' }

    res.status(response.status).send(blob);
}

I am calling this api from my component like:

const fetchWithToken = async (service, token) => {
// data fetch function in UI.
    const response = await fetch(`${process.env.basePath}/${service}`, {
      headers: { Authorization: `Bearer ${token}` },
    });

    const blob = await response.blob();

    console.log("»»»»»» [DEBUG : response ] --  :", blob); // Blob {size: 2, type: 'application/json'}

// download as file logic ....
}

as you can see the blob in ui data fetch response gives a blob size of 2 (content will be an empty object) even if the expected size is bigger.

I tried to convert the blob to a readable stream and send it back to the ui from next api. also tried to make use of File(). both idea failed. I was able to convert the blob to text in api (blob.text()) and send it as the response; but it will work only for json,csv,etc... files. But the scope is wide.

I am using nextjs - 13.5.4 node - 18.17.1.

I would prefer to send the file from UI_ENGINE to frontend directly. Please help me to find the best solution. thanks in advance...

Upvotes: 1

Views: 3106

Answers (1)

Anandu Babu
Anandu Babu

Reputation: 181

In the Next.js API handler function, after reading the response blob from the respective API, I attempted to convert it into a stream, array buffer, and file to send the response back to the reading function properly. However, none of these methods worked well. Since I couldn't pinpoint the exact issue, I tried converting the blob to raw buffer and sending it as a response, which surprisingly worked.

To do this first convert the blob to and array buffer - const arrayBuffer = await blob.arrayBuffer(); then use the arraybuffer to create new raw buffer - const buffer = Buffer.from(arrayBuffer);

Since I am sending a file it is important to include some key headers along with the response

export default async function handler(req, res) {
  const endpoint = `${process.env.UI_ENGINE}/docs/${req.query.id}/download-doc`;

  try {
    const response = await fetch(endpoint, {
      headers: { Authorization: `${req.headers.authorization}` },
    });

    const blob = await response.blob();

    const contentType =
      response.headers.get("content-type") || "application/octet-stream";
    const contentLength = response.headers.get("content-length") || blob.size;

    // converting blob to raw buffer for transferring
    // (other formats including blob was not working)
    const arrayBuffer = await blob.arrayBuffer();
    const buffer = Buffer.from(arrayBuffer);

    res
      .status(200)
      .setHeader("Content-Type", contentType)
      .setHeader("Content-Length", contentLength)
      .send(buffer);
  } catch (error) {
    res.status(500).send({ message: "Error fetching the document", error });
  }
}

I am not expecting this to be the exact solution. There has to be a better way to do this.

Upvotes: 3

Related Questions