CodeGenieApp/serverless-express

Binary data not retuned correctly

tvanhanen opened this issue · 1 comments

I have an existing express app which I'm moving to AWS Lambda. I'm using @vendia/serverless-express version 4.10.1 while doing this.

I have one API endpoint that returns a binary file. I'm having issues with corrupted binary response. I'm using AWS API GW V2.

I first returned the binary without any base64 encoding:

console.debug('Returning file to client. Length: ' + data.length)
res.setHeader('content-type', 'application/octet-stream')
res.status(200)
res.send(data)

When using API GW Payload format version 2.0 I got back something that looked like the correct binary, but it was corrupted. Data length before sending was about 75kb while I received file size of 110kb. I got the same 110kb regardless if the call was via API GW or directly to Function URL. Hence I think it's serverless-express tried to manipulate the response.

I then tried to return the data as base64 encoded:

const base64data = data.toString('base64');
res.setHeader('content-type', 'application/octet-stream')
res.status(200)
res.send(base64data)

In these cases I only get the base64 encoded string back (size about 100kb), API GW does not convert the base64 to binary.

My client sends Accept: application/octet-stream in the request headers.

My understanding is that with serverless-express version 4, I don't need to pass any isBase64Encoded or binaryMimeTypes . Many of the guidelines are also for AWS API GW 1.0. I've tried returning base64 encoded file using API GW payload format versions 1.0 (explicit response format) and 2.0 (interpreted response format). Both have the same result.

My API uses "ProtocolType": "HTTP", and my integration uses below configs, so I believe I cannot set ContentHandlingStrategy (CONVERT_TO_BINARY) together with "ProtocolType": "HTTP",.

"ConnectionType": "INTERNET",
"IntegrationMethod": "POST",
"IntegrationType": "AWS_PROXY",

Is serverless-express manipulating data if I simply try to retun the binary with res.send(data), as it seems like APIGW would pass it through.

Ok, so it seemed serverless-express did a base64 encoding for the content I passed as base64 encoded. I resolved this by:
In lambda.ts I added the binary setting:

exports.handler = serverlessExpress({
  app,
  binarySettings: {
    contentTypes: ['application/octet-stream']
  }
})

and in the API I returned binary without base64 encoding:

res.setHeader('content-type', 'application/octet-stream')
res.status(200)
res.send(data)