-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Description:
I have a nested application setup where each child application template defines a AWS::Serverless::Api. Some of those Serverless::Apis had a Cors property defined, but not all
What I have found is that when running sam local start-api, all of your the Apis must define Cors, or none of them will be able to support OPTIONS requests. The OPTIONS routes for each defined endpoint is not added.
I dug into the code a little bit and think I've identified the issue. See the Details section below
Steps to reproduce:
Here's a simple example
parent.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
Parent SAM Template
Resources:
Api1:
Type: AWS::Serverless::Application
Properties:
Location: service1/template.yaml
Api2:
Type: AWS::Serverless::Application
Properties:
Location: service2/template.yaml
service1/template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
service1 template
Globals:
Api:
Cors:
AllowOrigin: "'*'"
AllowHeaders: "'*'"
Function:
Timeout: 5
Runtime: go1.x
...
Resources:
ServiceApi1:
Type: AWS::Serverless::Api
Properties:
...
service2/template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
service2 template
Globals:
Function:
Timeout: 5
Runtime: go1.x
...
Resources:
ServiceApi2:
Type: AWS::Serverless::Api
Properties:
...
Note that service2 does not have Cors defined anywhere.
Observed result:
Running sam local start-api , you will see the following in the logs
Mounting Service1LambdaFunction at http://0.0.0.0:3003/service1/ [POST]
Mounting Service2LambdaFunction at http://0.0.0.0:3003/service2/ [POST]
Note that both routes dont have an OPTIONS method. If I make an OPTIONS request to either URL, I get a 403 {"message":"Missing Authentication Token"} response. No lambda is launched.
Now... if I update service2/template.yaml in my example above, and add the same Cors config that is in service1, and then run start-api again, I see that both functions support an OPTIONS request
Mounting Service1LambdaFunction at http://0.0.0.0:3003/service1/ [POST, OPTIONS]
Mounting Service2LambdaFunction at http://0.0.0.0:3003/service2/ [POST, OPTIONS]
At this point, im able to make an OPTIONS request to both APIs.
So the main observation here is that, Cors must be enabled on all APIs, or there is a chance that I can't make an OPTIONS request to any of the APIs
Expected result:
I would not expect it to be "all or nothing". I would expect to be able to make OPTIONS requests to any services that have Cors defined.
Details
I dug into the code a bit, and have identified why this is happening...
ApiCollector.normalize_cors_methods() is where the OPTIONS methods are added to the routes. However, they are only added if the APICollector's cors variable is set
APICollector.cors is set when the resources are being extracted in _extract_from_serverless_api(). Basically, it looks at the Cors property on the Serverless::Api resource, and parses that.
However, _extract_from_serverless_api() is called in a for-loop here. So, the collector loops through all the resources across all stacks. And for each iteration of that for-loop, it extracts out the Cors config, and sets it to its collector.cors variable. If a resource does not have Cors defined in the template file, then collector.cors will be set to None for that iteration of the for loop.
So... what I think is happening here, is that after all the resources have been extracted, the value of collector.cors will be set based on the last resource that was extracted. And if the last resource in the for loop did not have a Cors configuration defined on the Api, then collector.cors will be None. And when it goes to ApiCollector.normalize_cors_methods() later, collector.cors will still be None, and thus the OPTIONS method is not added to any of the routes. I believe that is what was happening in my case.
Hope that helps.
Additional environment details (Ex: Windows, Mac, Amazon Linux etc)
- OS: Linux
sam --version: SAM CLI, version 1.48.0- AWS region: local (not in AWS)