14

I've looked at the other related questions on SO but this seems different. In fact, my question is very similar to this one, except I don't have the 400 status issue.

The set up:

  • lambda function through API Gateway
  • Authorization: None, API KEY Required: false
  • deploying to stage: test

  • 1 resource, 1 POST method integrating the lambda.

  • Calling the POST endpoint directly e.g. with curl always returns 200 (with/without payload, bad payload, etc.) - so that's different from the referenced question.

I've used the "Enable CORS" option - I've tried applying this option on both the resource, and the POST request (and deploying the API afterwards).

In API GW, I can see Access-Control-Allow-Origin listed in 200 Response Headers under POST method - Method Response area.

Result: Calling the endpoint from client code in Chrome, OPTIONS passes but POST fails due to missing Access-Control-Allow-Origin header.

In curl: OPTIONS call

curl -X OPTIONS -H "Access-Control-Request-Method: POST" \
     -H "Access-Control-Request-Headers: Content-Type" \
     -H "Origin: http://example.com" --verbose <endpoint>

the response is:

< HTTP/1.1 200 OK
< Content-Type: application/json
...
< Access-Control-Allow-Headers: Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token
< Access-Control-Allow-Methods: POST,OPTIONS
< Access-Control-Allow-Origin: *
...

but with POST:

curl -X POST -d '{}' -H "Content-Type: application/json" \
     -H "Origin: http://example.com" --verbose <endpoint>

it returns:

< HTTP/1.1 200 OK
< Content-Type: application/json
...

and the response json body - but no Access-anything header.

What else can I check?

Community
  • 1
  • 1
bebbi
  • 2,489
  • 3
  • 22
  • 36

3 Answers3

25

The problem has been that the API gateway has called my lambda function using the "Lambda Proxy Integration" option checked.

I believe this is activated by default when adding a API gateway trigger to a newly created lambda function.

When inside the API Gateway - Resource - Method view, the "Integration Response" box is greyed out and it seems there's no way (even for the Enable CORS function) to add a Access-Control-Allow-Origin header there, which according to @Abhigna_Nagaraja is required.

Solution: If using "Lambda Proxy Integration", add the 'Access-Control-Allow-Origin': '*' header to your lambda function.

Even better: in the same view - Integration Request, turn off "Lambda Proxy Integration" and Enable CORS again (deploy afterwards).

(Then, in the callback, you'll have to return just the payload json instead of the { statusCode, headers, body } object.)

Update:

Some useful reads if you're unsure whether to return request response status information in http status codes or in the json payload:

http status vs json status

json status standards

bebbi
  • 2,489
  • 3
  • 22
  • 36
  • 2
    I believe the new "Lambda Proxy Integration" is broken, as it only creates a new ANY method. It seems to be not perfectly integrated with CORS, and even with the default Lambda triggers wizard. For now, I managed to fix this only by disabling the "Lambda Proxy Integration" and manually creating GET/POST methods. – alexcasalboni Oct 24 '16 at 09:26
  • 1
    In my experience that part had worked. The ANY method is a catch-all that in the case of LPI will direct all methods (POST, GET, etc.) to the lambda. Errors if lambda has any issue at all are very misleading though. – bebbi Oct 26 '16 at 08:07
  • The "Lambda Proxy Integration" is a way to control the status code and response headers from your lambda function. Disabling the proxy integration will always return a 200 response and will only allow you to set the response content. The docs mention the setting of a CORS header inside your lambda as required when using the API GW with the proxy integration enabled. (http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html) – Eelke van den Bos Aug 18 '17 at 08:50
3

'Enable CORS' option is a convenient tool that sets up all the integration/method response header mappings. If you clicked 'Enable CORS' and then added a new resource, it won't have the required settings. You can either click 'Enable CORS' again or you can manually set it up as

  • Add 'Access-Control-Allow-Origin' Method Response Header to POST method
  • Add 'Access-Control-Allow-Origin' Integration Response Header Mapping to POST method

Also, don't forget to deploy the API before testing the changes with curl.

Abhigna Nagaraja
  • 1,874
  • 15
  • 17
  • Everything was done as you suggested. However, I note one thing when confirming with the manual steps: Method Response looks alright, but Integration Response cannot be viewed or edited. The box says "Proxy integrations cannot be configured to transform responses". I'm using Lambda Proxy integration. Could this be related to the issue I'm seeing? – bebbi Oct 21 '16 at 07:20
  • 1
    I was able to get the header by adding it to the headers section in the lambda callback. As that looks like an ugly mix of code and config, I suspect we shouldn't use Lambda Proxy integration when needing CORS? – bebbi Oct 21 '16 at 07:39
  • do you know if adding CORS header to Integration Response in LPI has been fixed? – bebbi Nov 29 '16 at 20:41
0

If you're willing to use serverless-express to wrap a simple Express app in your Lambda, the Express cors package makes this very straightforward and highly configurable for a Lambda proxy. No need to configure CORS at the level of API Gateway.

index.js

const app = express();
app.use(cors());
// ...your backend implementation

lambda.js

const serverlessExpress = require('@vendia/serverless-express')
const app = require('./app')
exports.handler = serverlessExpress({ app })
zhark
  • 391
  • 3
  • 8