Bug: sam local start-api - AttributeError with $ref key in x-amazon-apigateway-integration
- Dominant language
- Python
- Stars
- 6.7k
- Forks
- 1.2k
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 52
Description
### Description:
I'm getting the following error whenever I try to run `sam local start-api`:
**Error: 'NoneType' object has no attribute 'lower'**
My SAM template contains a reference to an OpenAPI doc for API Gateway. Based on the stack trace, it seems to throw an error in the following code block in `_get_integration` in [samcli/commands/local/lib/swagger/parser.py](https://github.com/aws/aws-sam-cli/blob/v1.98.0/samcli/commands/local/lib/swagger/parser.py):
```python
integration = method_config[self._INTEGRATION_KEY]
if (
integration
and isinstance(integration, dict)
and integration.get("type").lower() == IntegrationType.aws_proxy.value
):
# Integration must be "aws_proxy" otherwise we don't care about it
return integration
```
`integration` seems to be looking for `x-amazon-apigateway-integration` in the OpenAPI doc. Then it checks whether the `type` is `aws_proxy`. However, I have a `$ref` which points to a later point in the document. So, `integration.get("type")` becomes `None` and causes an error to be thrown when calling `lower()`.
### Steps to reproduce:
With the following SAM template `template.yaml`:
```yaml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Resources:
# API Gateway
HttpApi:
Type: AWS::Serverless::HttpApi
Properties:
AccessLogSettings:
DestinationArn: !GetAtt AccessLogs.Arn
# $context variables: https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-logging-variables.html
Format: >-
{ "requestId":"$context.requestId", "ip":"$context.identity.sourceIp",
"requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod",
"routeKey":"$context.routeKey", "status":"$context.status",
"protocol":"$context.protocol", "responseLength":"$context.responseLength" }
DefaultRouteSettings:
ThrottlingBurstLimit: 100 # max # of concurrent requests
ThrottlingRateLimit: 100 # max # of requests/sec
DefinitionUri: openapi.yaml # OpenAPI file URI
AccessLogs:
Type: AWS::Logs::LogGroup
DeletionPolicy: Delete
UpdateReplacePolicy: Delete
Properties:
LogGroupName: store-api
RetentionInDays: 365
# Lambda
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/
Handler: app.handler
Runtime: python3.10 # see https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html
Architectures:
- arm64
Events:
HttpApiEvent:
Type: HttpApi
Properties:
ApiId: !Ref HttpApi
FunctionName: aws-service-handler
Outputs:
HttpApiUrl:
Description: URL of the API endpoint
Value: !Sub "https://${HttpApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}"
```
And my OpenAPI doc `openapi.yaml`:
```yaml
openapi: 3.0.3
info:
title: AWS Service Store
description: An API that fetches AWS service pricing
version: 1.1.0
paths:
/health:
get:
summary: Health check for this API
responses:
"200":
description: The API is healthy
# Empty body
x-amazon-apigateway-integration:
$ref: "#/components/x-amazon-apigateway-integrations/lambda"
components:
x-amazon-apigateway-integrations:
lambda:
type: aws_proxy
httpMethod: POST
# !Sub "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations"
uri: arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:701157632481:function:aws-service-handler/invocations
passthroughBehavior: when_no_templates
payloadFormatVersion: "2.0"
timeoutInMillis: 3000
```
Then running `sam local start-api --debug` causes the below error to appear.
### Observed result:
```
2023-10-05 22:26:24,192 | No config file found in this directory.
2023-10-05 22:26:24,194 | OSError occurred while reading TOML file: [Errno 2] No such file or directory:
'/home/abhiek187/github/aws-shop/microservices/store/test/samconfig.toml'
2023-10-05 22:26:24,195 | Config file location: /home/abhiek187/github/aws-shop/microservices/store/test/samconfig.toml
2023-10-05 22:26:24,195 | Config file '/home/abhiek187/github/aws-shop/microservices/store/test/samconfig.toml' does not exist
2023-10-05 22:26:24,198 | Using SAM Template at /home/abhiek187/github/aws-shop/microservices/store/test/template.yaml
2023-10-05 22:26:24,272 | OSError occurred while reading TOML file: [Errno 2] No such file or directory:
'/home/abhiek187/github/aws-shop/microservices/store/test/samconfig.toml'
2023-10-05 22:26:24,273 | Using config file: samconfig.toml, config environment: default
2023-10-05 22:26:24,274 | Expand command line arguments to:
2023-10-05 22:26:24,275 | --template_file=/home/abhiek187/github/aws-shop/microservices/store/test/template.yaml --host=127.0.0.1
--port=3000 --static_dir=public --layer_cache_basedir=/home/abhiek187/.aws-sam/layers-pkg --container_host=localhost
--container_host_interface=127.0.0.1
2023-10-05 22:26:24,330 | local start-api command is called
2023-10-05 22:26:24,333 | No Parameters detected in the template
2023-10-05 22:26:24,351 | There is no customer defined id or cdk path defined for resource HttpApi, so we will use the resource
logical id as the resource id
2023-10-05 22:26:24,351 | There is no customer defined id or cdk path defined for resource AccessLogs, so we will use the
resource logical id as the resource id
2023-10-05 22:26:24,352 | There is no customer defined id or cdk path defined for resource LambdaFunction, so we will use the
resource logical id as the resource id
2023-10-05 22:26:24,353 | 0 stacks found in the template
2023-10-05 22:26:24,354 | No Parameters detected in the template
2023-10-05 22:26:24,364 | There is no customer defined id or cdk path defined for resource HttpApi, so we will use the resource
logical id as the resource id
2023-10-05 22:26:24,365 | There is no customer defined id or cdk path defined for resource AccessLogs, so we will use the
resource logical id as the resource id
2023-10-05 22:26:24,365 | There is no customer defined id or cdk path defined for resource LambdaFunction, so we will use the
resource logical id as the resource id
2023-10-05 22:26:24,366 | 3 resources found in the stack
2023-10-05 22:26:24,367 | Found Serverless function with name='LambdaFunction' and CodeUri='src/'
2023-10-05 22:26:24,367 | --base-dir is not presented, adjusting uri src/ relative to
/home/abhiek187/github/aws-shop/microservices/store/test/template.yaml
2023-10-05 22:26:24,396 | Reading Swagger document from local file at
/home/abhiek187/github/aws-shop/microservices/store/test/openapi.yaml
2023-10-05 22:26:24,401 | Parsing Swagger document using 3.0 specification
2023-10-05 22:26:24,403 | Telemetry endpoint configured to be
https://aws-serverless-tools-telemetry.us-west-2.amazonaws.com/metrics
2023-10-05 22:26:24,424 | Telemetry endpoint configured to be
https://aws-serverless-tools-telemetry.us-west-2.amazonaws.com/metrics
2023-10-05 22:26:24,425 | Sending Telemetry: {'metrics': [{'commandRun': {'requestId': '32f69906-a4f3-4ca8-96c8-317e66585116',
'installationId': '67932b73-c0d9-4023-859a-dec5d81d9dc4', 'sessionId': '4348de05-1537-405f-9516-780ad0f937ed',
'executionEnvironment': 'CLI', 'ci': False, 'pyversion': '3.11.3', 'samcliVersion': '1.98.0', 'awsProfileProvided': False,
'debugFlagProvided': True, 'region': '', 'commandName': 'sam local start-api', 'metricSpecificAttributes': {'projectType': 'CFN',
'gitOrigin': None, 'projectName': '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', 'initialCommit': None},
'duration': 130, 'exitReason': 'AttributeError', 'exitCode': 255}}]}
2023-10-05 22:26:24,426 | Unable to find Click Context for getting session_id.
2023-10-05 22:26:24,429 | Sending Telemetry: {'metrics': [{'events': {'requestId': '384249e2-6472-47f6-b657-5bcbdefbb72e',
'installationId': '67932b73-c0d9-4023-859a-dec5d81d9dc4', 'sessionId': '4348de05-1537-405f-9516-780ad0f937ed',
'executionEnvironment': 'CLI', 'ci': False, 'pyversion': '3.11.3', 'samcliVersion': '1.98.0', 'commandName': 'sam local
start-api', 'metricSpecificAttributes': {'events': [{'event_name': 'SamConfigFileExtension', 'event_value': '.toml', 'thread_id':
'a8071e0a9a444f24a7590c75853597b7', 'time_stamp': '2023-10-06 02:26:24.194', 'exception_name': None}, {'event_name':
'SamConfigFileExtension', 'event_value': '.toml', 'thread_id': 'df4bd182700346569a053bc7a2d93327', 'time_stamp': '2023-10-06
02:26:24.273', 'exception_name': None}]}}}]}
2023-10-05 22:26:24,931 | HTTPSConnectionPool(host='aws-serverless-tools-telemetry.us-west-2.amazonaws.com', port=443): Read
timed out. (read timeout=0.1)
2023-10-05 22:26:24,934 | HTTPSConnectionPool(host='aws-serverless-tools-telemetry.us-west-2.amazonaws.com', port=443): Read
timed out. (read timeout=0.1)
Error: 'NoneType' object has no attribute 'lower'
Traceback:
File "click/core.py", line 1078, in main
File "click/core.py", line 1688, in invoke
File "click/core.py", line 1688, in invoke
File "click/core.py", line 1434, in invoke
File "click/core.py", line 783, in invoke
File "samcli/cli/cli_config_file.py", line 297, in wrapper
File "click/decorators.py", line 92, in new_func
File "click/core.py", line 783, in invoke
File "samcli/lib/telemetry/metric.py", line 184, in wrapped
File "samcli/lib/telemetry/metric.py", line 149, in wrapped
File "samcli/lib/utils/version_checker.py", line 42, in wrapped
File "samcli/cli/main.py", line 95, in wrapper
File "samcli/commands/local/start_api/cli.py", line 122, in cli
File "samcli/commands/local/start_api/cli.py", line 220, in do_cli
File "samcli/commands/local/lib/local_api_service.py", line 37, in __init__
File "samcli/lib/providers/api_provider.py", line 37, in __init__
File "samcli/lib/providers/api_provider.py", line 64, in _extract_api
File "samcli/lib/providers/sam_api_provider.py", line 74, in extract_resources
File "samcli/lib/providers/sam_api_provider.py", line 335, in _extract_from_serverless_http
File "samcli/lib/providers/cfn_base_api_provider.py", line 87, in extract_swagger_route
File "samcli/commands/local/lib/swagger/parser.py", line 343, in get_routes
File "samcli/commands/local/lib/swagger/parser.py", line 457, in _get_integration_function_name
File "samcli/commands/local/lib/swagger/parser.py", line 432, in _get_integration
An unexpected error was encountered while executing "sam local start-api".
Search for an existing issue:
https://github.com/aws/aws-sam-cli/issues?q=is%3Aissue+is%3Aopen+Bug%3A%20sam%20local%20start-api%20-%20AttributeError
Or create a bug report:
https://github.com/aws/aws-sam-cli/issues/new?template=Bug_report.md&title=Bug%3A%20sam%20local%20start-api%20-%20AttributeError
```
### Expected result:
If I move the `$ref` block inline:
```yaml
openapi: 3.0.3
info:
title: AWS Service Store
description: An API that fetches AWS service pricing
version: 1.1.0
paths:
/health:
get:
summary: Health check for this API
responses:
"200":
description: The API is healthy
# Empty body
x-amazon-apigateway-integration:
type: aws_proxy
httpMethod: POST
# !Sub "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations"
uri: arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:701157632481:function:aws-service-handler/invocations
passthroughBehavior: when_no_templates
payloadFormatVersion: "2.0"
timeoutInMillis: 3000
```
`sam local start-api --debug` works as expected:
```
2023-10-05 22:31:42,616 | No config file found in this directory.
2023-10-05 22:31:42,618 | OSError occurred while reading TOML file: [Errno 2] No such file or directory:
'/home/abhiek187/github/aws-shop/microservices/store/test/samconfig.toml'
2023-10-05 22:31:42,619 | Config file location: /home/abhiek187/github/aws-shop/microservices/store/test/samconfig.toml
2023-10-05 22:31:42,619 | Config file '/home/abhiek187/github/aws-shop/microservices/store/test/samconfig.toml' does not exist
2023-10-05 22:31:42,622 | Using SAM Template at /home/abhiek187/github/aws-shop/microservices/store/test/template.yaml
2023-10-05 22:31:42,689 | OSError occurred while reading TOML file: [Errno 2] No such file or directory:
'/home/abhiek187/github/aws-shop/microservices/store/test/samconfig.toml'
2023-10-05 22:31:42,691 | Using config file: samconfig.toml, config environment: default
2023-10-05 22:31:42,691 | Expand command line arguments to:
2023-10-05 22:31:42,692 | --template_file=/home/abhiek187/github/aws-shop/microservices/store/test/template.yaml --host=127.0.0.1
--port=3000 --static_dir=public --layer_cache_basedir=/home/abhiek187/.aws-sam/layers-pkg --container_host=localhost
--container_host_interface=127.0.0.1
2023-10-05 22:31:42,751 | local start-api command is called
2023-10-05 22:31:42,754 | No Parameters detected in the template
2023-10-05 22:31:42,771 | There is no customer defined id or cdk path defined for resource HttpApi, so we will use the resource
logical id as the resource id
2023-10-05 22:31:42,772 | There is no customer defined id or cdk path defined for resource AccessLogs, so we will use the
resource logical id as the resource id
2023-10-05 22:31:42,773 | There is no customer defined id or cdk path defined for resource LambdaFunction, so we will use the
resource logical id as the resource id
2023-10-05 22:31:42,774 | 0 stacks found in the template
2023-10-05 22:31:42,774 | No Parameters detected in the template
2023-10-05 22:31:42,784 | There is no customer defined id or cdk path defined for resource HttpApi, so we will use the resource
logical id as the resource id
2023-10-05 22:31:42,785 | There is no customer defined id or cdk path defined for resource AccessLogs, so we will use the
resource logical id as the resource id
2023-10-05 22:31:42,786 | There is no customer defined id or cdk path defined for resource LambdaFunction, so we will use the
resource logical id as the resource id
2023-10-05 22:31:42,786 | 3 resources found in the stack
2023-10-05 22:31:42,787 | Found Serverless function with name='LambdaFunction' and CodeUri='src/'
2023-10-05 22:31:42,787 | --base-dir is not presented, adjusting uri src/ relative to
/home/abhiek187/github/aws-shop/microservices/store/test/template.yaml
2023-10-05 22:31:42,805 | Reading Swagger document from local file at
/home/abhiek187/github/aws-shop/microservices/store/test/openapi.yaml
2023-10-05 22:31:42,809 | Parsing Swagger document using 3.0 specification
2023-10-05 22:31:42,810 | Extracted Function ARN: arn:aws:lambda:us-east-1:701157632481:function:aws-service-handler
2023-10-05 22:31:42,811 | Found '1' APIs in resource 'HttpApi'
2023-10-05 22:31:42,816 | Found '0' authorizers in resource 'HttpApi'
2023-10-05 22:31:42,819 | Found '1' API Events in Serverless function with name 'LambdaFunction'
2023-10-05 22:31:42,821 | Removed duplicates from '2' Explicit APIs and '0' Implicit APIs to produce '2' APIs
2023-10-05 22:31:42,823 | 2 APIs found in the template
2023-10-05 22:31:42,830 | add catch-all route
2023-10-05 22:31:42,833 | Mounting LambdaFunction at http://127.0.0.1:3000$default [X-AMAZON-APIGATEWAY-ANY-METHOD]
2023-10-05 22:31:42,834 | Mounting aws-service-handler at http://127.0.0.1:3000/health [GET]
2023-10-05 22:31:42,834 | You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload
SAM CLI while working on your functions, changes will be reflected instantly/automatically. If you used sam build before running
local commands, you will need to re-run sam build for the changes to be picked up. You only need to restart SAM CLI if you update
your AWS SAM template
2023-10-05 22:31:42,836 | Localhost server is starting up. Multi-threading = True
2023-10-05 22:31:42 WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:3000
2023-10-05 22:31:42 Press CTRL+C to quit
```
### Additional environment details (Ex: Windows, Mac, Amazon Linux etc)
`sam --info`:
```json
{
"version": "1.98.0",
"system": {
"python": "3.11.3",
"os": "Linux-5.15.90.1-microsoft-standard-WSL2-x86_64-with-glibc2.31"
},
"additional_dependencies": {
"docker_engine": "24.0.6",
"aws_cdk": "Not available",
"terraform": "Not available"
},
"available_beta_feature_env_vars": [
"SAM_CLI_BETA_FEATURES",
"SAM_CLI_BETA_BUILD_PERFORMANCE",
"SAM_CLI_BETA_TERRAFORM_SUPPORT",
"SAM_CLI_BETA_RUST_CARGO_LAMBDA"
]
}
```
`Add --debug flag to command you are running`
Contributor guide
Assessment
This issue has not been assessed yet.