venveo/serverless-sharp

serverless-http koa middleware

tyrauber opened this issue · 1 comments

In attempting to resolve #72 and #71, I have developed the following approach of using the serverless-sharp handler as serverless-http koa middleware.

const serverless = require('serverless-http');
const Koa = require('koa');
const { handler } = require('./node_modules/serverless-sharp/src/index')
 
const app = new Koa();

app.use(async(ctx,next) => {
  const event = {
    path: ctx.path,
    headers: ctx.header,
    queryStringParameters: {...ctx.request.query},
    status: 200
  }
  const succeed  = (result) => {
    ctx.set(result.headers)
    ctx.status = result.statusCode
    ctx.body = result.body
  }
  await handler(event, { succeed: succeed })
});

module.exports.handler = serverless(app, { binary: ['image/*'] });

My goal here is to make it easier to implement serverless-sharp within another serverless application. One could load load the serverless-sharp handler on a different function path as detailed in #71, but that doesn't address the scenario detailed in #72, where one may desire different error handling on missing files or different handler of unsupported file types.

This approach is an attempt to address both scenarios. And it almost works.

serverless-http should automatically handle binary data based on supported content_type and that appears to be the case. The only problem is that it renders a broken image. Interestingly, when inspecting the response payload the file size is larger than when using the normal handler for the same image, which leads me to believe the image is perhaps being double encoded? Perhaps, someone has a better idea than me as to what is happening here.

Oh, one minor additional issue is that the handler cannot be used in an async function, and must be provided with a succeed callback, preventing the use of the handler in a chained middleware. This could be resolved by updating the handler function to test if the success callback exists and otherwise return the result directly.

if(context.succeed){
  context.succeed(response)
}
return response

This would allow the middleware to receive a response directly from:

const response = await handler(event, { succeed: succeed })

Or, in a then, catch manner:

await handler(event, { succeed: succeed }).then((response) => {

}).catch((err) => {

})