Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lambda@Edge Support #79

Open
spencerbeggs opened this issue Feb 21, 2019 · 18 comments
Open

Lambda@Edge Support #79

spencerbeggs opened this issue Feb 21, 2019 · 18 comments

Comments

@spencerbeggs
Copy link

Hi, Doug. Thank you for this fantastic module. I got it up and running a a couple projects where I use Lambda@Edge to serve HTML. This requires a small transform of the payload to conform to the Blacklisted and Read-Only Headers. Would you be interested in a PR for this use case, perhaps we could add a second argument to the exported serverless function to support vendor platforms, eg:

// vanilla Lambda@Edge handling
const handler = serverless(app, "edge");
// html Lambda@Edge handling
const handler = serverless(app, "edge-html");

Alternatively, I could publish separate modules that require this module as a dependency that perform the necessary transformations.

@dougmoscrop
Copy link
Owner

Sure, would love to support this, there already is a second argument for options - I had started to refactor this library to support different providers but I got sidetracked. how about:

serverless(app, {
    platform: 'aws-lambda' // or 'aws-lambda-edge', eventually also 'gcf', 'ibm', etc.
});

Or is there specific changes that have to happen for HTML vs other Lambda@Edge scenarios?

@spencerbeggs
Copy link
Author

The base case for Lambda@Edge is that the output of the current implementation has to transform headers into AWS' format. This is what my handler looks like:

const zlib = require("zlib");
const serverless = require("serverless-http");
const app = require("./app");
const handler = serverless(app);

const readOnlyHeaders = [
  "accept-encoding",
  "content-length",
  "if-modified-since",
  "if-none-Match",
  "if-range",
  "if-unmodified-since",
  "range",
  "transfer-encoding",
  "via"
];

module.exports.handler = async (event, context, callback) => {
  const obj = await handler(event, context);
  const buffer = zlib.gzipSync(obj.body);
  const base64EncodedBody = buffer.toString("base64");
  callback(null, {
    status: obj.statusCode.toString(),
    statusDescription: "OK",
    bodyEncoding: "base64",
    headers: Object.keys(obj.headers).reduce(
      (acc, key) => {
        let normalizedKey = key.toLowerCase();
        if (!readOnlyHeaders.includes(normalizedKey)) {
          if (acc[normalizedKey]) {
            acc[normalizedKey].push({
              key: normalizedKey,
              value: obj.headers[key]
            });
          } else {
            acc[normalizedKey] = [
              {
                key: normalizedKey,
                value: obj.headers[key]
              }
            ];
          }
        }
        return acc;
      },
      { "content-encoding": [{ key: "content-encoding", value: "gzip" }] }
    ),
    body: base64EncodedBody
  });
};

That only does the Read-Only handlers and then does the HTML processing. Since there are different requirements for the type of function being called, maybe the API can look like:

serverless(app, {
    platform: 'aws-lambda-edge',
    type: 'origin-request'
});

We could then encapsulate the monekying with the header and detect HTML content-type and handle that automatically and the API can remain nice and clean like it is.

@dougmoscrop
Copy link
Owner

Okay, seems pretty straightforward! I don't know that I have a strong preference for the names of these properties, I had alternative thought of something like:

provider: aws
type: lambda-edge-origin-request

i.e. default provider is aws, default type is lambda for aws, then gcp and ibm would be other providers, etc.

@dougmoscrop
Copy link
Owner

^ I don't think this is really going to change much of the impl, if you want to PR something for further discussion great, if not I can start re-introducing the multi-provider code and then you can build on it there. I won't be able to do that today though, maybe not this week either.

@spencerbeggs
Copy link
Author

I started a two-week sprint today that requires this functionality, so I will fork and get to work.

@wmertens
Copy link

wmertens commented Aug 6, 2019

@spencerbeggs I see you instead forked aws-serverless-express-edge - was that a better fit? I also tried to use that, in the end running express in lambda seems like overkill, the http handling is already done by AWS. There's also modofunjs and now I just don't know what to choose.

@spencerbeggs
Copy link
Author

I have a fork of that, too, but this package works better. You can find my fork here: https://github.com/spencerbeggs/serverless-http

I got the origin-request parsing to work, if you want to check it out. Getting this package to be multi-provider might incur a lot of overhead. In fact, getting this package to handle all the lambda proxy request types might be overkill as the routing stuff really only needs to be done on the origin request. Check out my package, I write a bunch of tests. And let me know what you think. I am still hacking on my fork as I am using it in an upcoming project.

@dougmoscrop
Copy link
Owner

I did some refactoring to make multi-provider support easier, so your fork is a bit behind!

I hope these changes make it easier for you to bring your changes in! See https://github.com/dougmoscrop/serverless-http/tree/master/lib/provider

@EdisonHarada
Copy link

EdisonHarada commented Aug 25, 2019

I started implementing Lambda@Edge some hours ago using your latest commit. But I still need to implement tests and refactor my code.

I implemented in this simple application to get the server Ip and client Ip: https://d1lrl7frx0ubqe.cloudfront.net
But I still need to figure out why it's getting the same ip for server and client, my bet is probably how the lambda@edge works, but I need to confirm it.

The original project is running in: https://koa-serverless.edisonharada.dev

If someone wants to check the changes my fork is here: https://github.com/EdisonHarada/serverless-http
Also, I created a new provider to make the implementation easily for now and after we can check which approach would be better (and also the name for the provider haha), to use it I just changed:

const handler = serverlessHttp(app, {
  provider: 'awsEdge'
})

@yshrsmz
Copy link

yshrsmz commented Jul 29, 2020

Hi, any news regarding Lambda@Edge support?
I recently started to develop an app for Lambda@Edge and found this issue.
Would be great if this happens.

@eelayoubi
Copy link

Hey @dougmoscrop will this be merged? I imagine that it can be used for cloudfront -> Lambda Edge origin request event, right?

@dougmoscrop
Copy link
Owner

This is an issue not a PR - I will merge a PR that adds this support, absolutely

@eelayoubi
Copy link

@dougmoscrop ah yes, I was looking at the fork that has the edge support, and asking the question here 🙄. Thanks for the reply and sorry for the confusion 🙏. Do you have a timeline for when this will be done?

@dougmoscrop
Copy link
Owner

Oh it's been a while! I don't know if anyone is working on it, if you have the cycles to pick it up from that fork that would be great

@eelayoubi
Copy link

@dougmoscrop here is a PR #192 that includes lambda edge origin request. However, I did not have time to add Unit Tests for it.

@lolJS
Copy link

lolJS commented Feb 9, 2021

I've continued this effort on #196 which addresses some of the issues that @ljwagerfield brought up in the PR review.

@bfischer1121
Copy link

hi any update of whether #196 will be merged?

@logusgraphics
Copy link

For anyone interested, the following library achieves lambda@edge integration seamlessly with singleton accessor to the event object. https://github.com/vendia/serverless-express/tree/mainline/examples/lambda-edge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants