AWS API Gateway supports CORS for OPTIONS only when using SAM (without Lambda proxy integration)
Asked Answered
Q

1

6

I'm using AWS Serverless for building a small site with around 15 Lambda functions.
My Cloudformation stack is completely built using SAM.

I'm NOT using Lambda proxy integration.

The Api section in the SAM yaml template config looks like this:

AppApi:
    Type: AWS::Serverless::Api
    Properties:
        Cors:
            AllowMethods: "'*'"
            AllowHeaders: "'Content-Type'" 
            AllowOrigin: "'*'"
    ...........More Stuff..........

When I deploy this SAM yaml template, I see that my ApiGateway created the OPTIONS verb for all methods and when I shoot a request with the OPTIONS verb, I do see the CORS headers correctly.

The problem is that the other verbs (e.g. POST) don't add those headers to their response as the OPTIONS request did and when I run my api from the browser I get the cross origin policy error in my console.

So my current workaround was to add the CORS header using integrated responses to specific status codes, but I cannot and dont want to handle that for 15 methods and I want to support all response status codes (e.g. 4xx\5xx etc.).

My questions:

  1. Am I doing anything wrong here or is this a SAM bug?
  2. If this is a bug, is there any workaround other from adding the headers using integrated responses (or from my code)?
  3. Is there a way I can add headers "globally" from an Api Gateway? Or support some kind of global integrated responses?
Quesnay answered 12/3, 2019 at 15:28 Comment(0)
E
2

If you are using Lambda with Proxy Integrations, you need to specify the CORS Origin in your HTTP response.

For Lambda or HTTP proxy integrations, you can still set up the required OPTIONS response headers in API Gateway. However, you must rely on the back end to return the Access-Control-Allow-Origin headers because the integration response is disabled for the proxy integration. https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html

All responses from Lambda need to have these headers and status code, but you could extract that to a shared library to reduce code duplication. Errors handled by API-G will have the headers added automatically.

You probably already have this, but the NodeJS pattern is like this:

var response = {
    statusCode: 200,
    headers: {
        "Access-Control-Allow-Origin" : "*"
    },
    body: JSON.stringify({
        someReturnData
    })
};
callback(null, response);

If you really don't want to do this then you can turn off Lambda-Proxy Integration, but that means that all request response payloads need to be handled in API-G instead of Lambda. IMO this provides much less flexibility and more configuration required to achieve the same results.

Here is an interesting comparison of the two approaches.

Eachern answered 12/3, 2019 at 15:38 Comment(4)
Hi, Thanks for the answer. I'm NOT using Lambda with proxy int. and I don't want to add CORS headers in my code since I think it's a bad practice for many reasons (One of them is that you can get a response from a resource before entering your code and then how will you support CORS?). Now my alternatives are integrated responses per method\verb - bad as well since I don't want to cover all error codes (who knows which error code I will miss) & I don't want to spam my YAML template and handle every change for every method\verb. I'm looking for a better way to do this..Quesnay
If you are not using Lambda-Proxy, and you have set up the CORS headers in API Gateway, then you should get the headers in the response automatically. As a test, have you tried Enabling CORS on a single method manually (console or CLI), just to see if that works.Eachern
Yes. I've added the CORS section in my template. After deploying the template, there was a OPTIONS verb create for each resource path that returns a valid response. When the browser creates an xhr request, it preflights using the OPTIONS request which returns everything correctly and then continues to the "real request" (let's assume POST). The POST request doesn't return the CORS headers and then the browser simply rejects the response. I don't know if this is a bug or something that I'm missing here..Quesnay
Sorry, I'm not sure what's going on there. I switched to Lambda-Proxy a few years ago, and CORS became much less of an issue. Lambda-Proxy is passionately recommended in the AWS Talks I've been to and the Serverless Meetups I attend. I must admit though, I don't use SAM much, mainly the serverless framework.Eachern

© 2022 - 2024 — McMap. All rights reserved.