Serve clickable download URL in NodeJS

Viewed 328

At my endpoint in my NodeJS server, after retrieving an audio file stored as a Buffer in MongoDB, I want to represent it with a URL (much like how you do with URL.createObjectURL(blob) in the frontend on the browser). I then plan to res.render() the URL in HTML through Handlebars on the client, so that the user can click on it to download it:

<a href={{url}}>Click me to download the file!</a>

In the NodeJs server, I have converted the MongoDB Buffer into a JavaScript ArrayBuffer through:

var buffer = Buffer.from(recordingFiles[0].blobFile);
var arrayBuffer = Uint8Array.from(buffer).buffer;

I am unsure where to proceed from here. I seen solutions using fs or res.download(), but they don't seem applicable to my situation. Thanks in advance for any help!

2 Answers

Hopefully this can help.

var blob = new Blob(BUFFER, {type: "audio mime type"});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
var fileName = reportName;
link.download = fileName;
link.click();

Do you always need to preload the audio file onto the page?

If not, then I would advise you to add a separate endpoint to download the file on demand. The frontend link can send a get request to the endpoint and download the file only if the user clicked it.
Otherwise you'd always be downloading the buffer behind the scenes, even if the user didn't intend to download it. This is especially problematic on slow connections.

Frontend:

<a href={{`${baseUrl}/download/${audioId}`}}>Click me to download the file!</a>

Backend:

const stream = require('stream');

app.get('/download/:audioId', function (request, response) {
  // Retrieve the tag from our URL path
  const audioId = request.params.audioId;
  
  const fileData; // TODO: Get file buffer from mongo.
  const fileContents = Buffer.from(fileData, 'base64');

  const readStream = new stream.PassThrough();
  readStream.end(fileContents);

  response.set('Content-disposition', 'attachment; filename=' + fileName);
  response.set('Content-Type', '<your MIME type here>');

  readStream.pipe(response);
});

A list of relevant MIME types can be found here.

Related