Serving binary files in a custom function?

Hey there!

I’m working on a Redwood app that needs to serve mp3 files. During development I’m serving them from disk using mock-aws-s3 - npm to mock the s3 API.

My problem is that I can’t figure out how to get a custom function to return binary data. I’ve tried returning a NodeJS Buffer directly, and various permutations of base64 encoding, and none of them seem to correctly serialize to a straight-up binary file. Any idea how to do this? My current function is below.

export const handler = async (event: APIGatewayEvent, context: Context) => {
  logger.info('Invoked serveRecording function')

  const uuid = event.path.split('/').slice(-1).pop()

  const object = await s3
    .getObject({
      Key: `recordings/${uuid}/transcoded.mp3`,
      Bucket: 'record-me-dev',
    })
    .promise()

  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'audio/mpeg',
      'Content-Length': object.ContentLength,
    },
    body: object.Body.toString('base64'),
    isBase64: true,
    contentHandling: 'CONVERT_TO_BINARY',
  }
}

Hi @corbt

I’m not sure that sending that content over a serverless function is practical. First, it won’t stream so everything has to be in memory. Second, you are dealt with the data twice a fetch and a response. Third, the player won’t be able to play as it retrieves. And last a serverless function on Netlify has 10 seconds to of rubtime. So unless your files are really small that may now work.

But, there’s an answer

You can fetch a presigned url from AWS S3 for the bucket’s file that is valid for a short duration like several minutes or an hour or so.

Your function or service (used by a GraphQL query) can generate a presigned url for a protected private bucket file and just return that.

Then your player just plays that url.

For example, see:

Thanks @dthyresson! I agree, normally generating pre-signed S3 URLs and letting the client fetch the media would be a more scalable and straightforward solution.

As a bit more background, my app needs to be able to run both in the cloud and locally on a user’s device (it’s a project to let you store recordings of your conversations, which can obviously be highly sensitive). While running in the cloud an S3 pre-signed URL works great, but locally I still need to be able to serve an mp3 file from disk.

It does look like the AWS Lambda API supports this, so I put up a PR to implement that support for the Redwood API server here.

Not sure I follow - you intend to have people install a Redwood app locally?’on their individual systems?

Or do you mean locally during development?