0

I have a simple lambda function setup with a serverless.yml configuration. What I'm looking to do is to have an additional lambda function which would be called for OPTIONS method for any of the deployed lambda functions. For example, if /login is called with OPTIONS I want options handler to handle the execution. If /login is called with GET I want the actual login handler to handle the execution. Same for all the other handler functions as well.

Serverless.yml

functions:
  login:
    handler: handler.login
    events:
      - http:
          path: login
          method: get
  stats:
    handler: handler.Stats
    events:
      - http:
          path: patientset/{id}/stats
          method: get
  options:
    handler: handler.options
    events:
      - http:
          path: '/' //Need something global like this
          method: options

Handler.js

module.exports.options = (event) => {
  const headers = setHeaders(event);  
  return {
    statusCode: 200,
    headers,
    body: JSON.stringify({})
  }
}

//Code updated in edit
  login:
    handler: handler.login
    events:
      - http:
          path: login
          method: get
          cors:
            origin: 'https://d2mo71maq8qx66.cloudfront.net'
            headers: ${self:custom.ALLOWED-HEADERS}
            allowCredentials: true
DV82XL
  • 5,350
  • 5
  • 30
  • 59
shivam aima
  • 103
  • 5
  • 12

1 Answers1

0

If I understand you correctly, then you have to combine the handler functions and handle the differentiation between GET and OPTIONS within your Lambda function's code. At the moment your code does not work properly because you are creating three different Lambda functions and three different REST APIs (where one REST API is integrated with one Lambda function). This is a problem because each REST API has a different endpoint url. So you have http://api-A.../login, http://api-B.../patientset/{id}/stats and http://api-C.../ as your endpoints. In order to call one endpoint with different HTTP methods like GET or OPTIONS, you need to define it like this:

functions:
  login:
    handler: handler.myHandler
    events:
      - http:
          path: '/login'
          method: get
      - http:
          path: '/login'
          method: 'options'

This will produce an endpoint like http://api-X.../login that you can either call with GET or OPTIONS. When you receive the event in your myHandler function, you need to decide on the httpMethod parameter of the event object which code you want to execute.

However, this seems to be not enough for you because you want this for any deployed Lambda function. Unfortunately, I'm not aware of a way to automatically do this for every deployed Lambda function. As far as I know, you need to explicitly add an options event as above to every endpoint/Lambda function that you have in your Lambda function and adjust your handler functions appropriately.

Besides that, you don't need to write an options event for each path. You can also use {proxy+} for the options event instead. For example:

events:
  - http:
      method: 'options'
      path: '/{proxy+}'

A side note on this topic: If you're doing all of this because you want to return some CORS headers, then you should consider using the cors option instead. This usually reduces the amount of config + code you have to write.

s.hesse
  • 1,900
  • 10
  • 13
  • Hi. Actually the issue I have is mainly related to allowing only a single domain in access-control-allow-origin. Any other domain I want to be rejected by the cors protocol automatically. Doing it like this creates an options route for the handler in api-gateway with 'mock' integration type and it still allows access to any domain which is what I'm struggling with. (Code updated in edit). – shivam aima Jan 17 '21 at 13:45
  • And have you tried restricting the domain by setting the `origin` property inside the `cors` config to e.g. your domain name? This should do the trick. So instead of writing `origin: '*'` you write `origin: 'http://example.org'`. This is also documented in the [Serverless cors option documentation](https://www.serverless.com/framework/docs/providers/aws/events/apigateway#enabling-cors). – s.hesse Jan 17 '21 at 13:50
  • Yes its configured exactly like that, please check the end bit in the edited code. Other origins like localhost:3000 and postman are still able to access the api. I have also returned the headers in the handler. – shivam aima Jan 17 '21 at 14:12
  • Not sure about your localhost thing (I don't know your setup) but Postman or similar dev tools usually don't care about CORS. It's a rule that browsers implement mostly. See also this SO thread about it: https://stackoverflow.com/questions/36250615/cors-with-postman (There are also other websites/blog posts about it on the internet) So, how do you call your endpoint? Do you include the Origin and other headers when using Postman? Does it work if you make a call from the domain you're allowing? – s.hesse Jan 17 '21 at 14:24
  • Works for the domain I'm allowing but also works for other domains that I'm not allowing. I'm not sure what exactly the behaviour of api-gateway 'mock' integration type is and how it functions. – shivam aima Jan 17 '21 at 14:33