Search code examples
node.jsfetchbuffer

Sending more than one Buffer in a single response with Node


I am creating two buffers from images and would like to send them in a single response to the client from a Node server.

Server:

    const response1 = await fetch(imageUrls[0]);
    const response2 = await fetch(imageUrls[1]);
    const arrayBuffer1 = await response1.arrayBuffer();
    const arrayBuffer2 = await response2.arrayBuffer();

    const buffer1 = Buffer.from(arrayBuffer1, "base64");
    const buffer2 = Buffer.from(arrayBuffer2, "base64");

    res.setHeader("Content-Type", "application/json");
    res.send(
      JSON.stringify({
        first: buffer1,
        second: buffer2,
      })
    );

Client:

  fetch(endpoint + new URLSearchParams(paramsObj), {
    method: "GET",
    headers: {
      "Content-type": "application/json",
    },
  })
    .then((response) => {
      const { first, second } = JSON.parse(response.body);
      obv.blob().then((blob) => download(blob));
      rev.blob().then((blob) => download(blob));
    })

The issue is that response.body is still a ReadableStream and not a parseable string as I would expect to get with JSON.stringify.

I also tried to send a combined response with two res.write()s but was only getting the first buffer.

The following works if I only send 1 buffer from the server with res.send(buffer1):

    .then((response) => {
      response.blob().then((blob) => download(blob));
    })

Solution

  • If you would like to send the buffers as JSON, you should consider converting them to Base64 strings and then sending a JSON object in the response just like you are already doing. I do not think the JSON format supports Buffers.

    const response1 = await fetch(imageUrls[0]);
    const response2 = await fetch(imageUrls[1]);
    
    const buffer1 = convertBufferToBase64(response1);
    const buffer2 = convertBufferToBase64(response2);
    
    res.setHeader("Content-Type", "application/json");
    res.send(
      JSON.stringify({
        first: buffer1,
        second: buffer2,
      })
    );
    

    An alternative would be to stream the buffer on the response, in which case you would have to set the Content-Type header to some binary format like application/octet-stream or so.

    const response1 = await fetch(imageUrls[0]);
    const arrayBuffer1 = await response1.arrayBuffer();
    
    res.setHeader("Content-Type", "application/octet-stream");
    res.send(
      arrayBuffer1
    );
    

    Personally, I would just redirect the client to fetch the image by itself by setting the location header and status code in the response like so.

    const imageUrls = ["blah", "hablo"];
    res.setHeader("Location", imageUrls[0]);
    res.status(301); //may also use 302 | 303 | 307 | 308
    res.end();