Trying to deploy a simple HelloWorld API using CloudFormation/SAM.
I have to defined an AWS::Serverless::Api, AWS::ApiGateway::Resource, AWS::ApiGateway::Method and a AWS::ApiGateway::Deployment. But during sam deploy I see that another AWS::ApiGateway::Deployment is implicitly created, one that is deployed before the API Method.
The API related resources deployed:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation LogicalResourceId ResourceType Replacement
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add HelloWorldAPIDeployment5332c373d4 AWS::ApiGateway::Deployment N/A
+ Add HelloWorldAPIDeployment AWS::ApiGateway::Deployment N/A
+ Add HelloWorldAPIMethod AWS::ApiGateway::Method N/A
+ Add HelloWorldAPIResource AWS::ApiGateway::Resource N/A
+ Add HelloWorldAPIStage AWS::ApiGateway::Stage N/A
+ Add HelloWorldAPI AWS::ApiGateway::RestApi N/A
How can I stop the implicit AWS::ApiGateway::Deployment(HelloWorldAPIDeployment5332c373d4) from being created?
It causes the following error:
CREATE_FAILED AWS::ApiGateway::Deployment HelloWorldAPIDeployment5332c373d4 Resource handler returned message: "The REST
API doesn't contain any methods (Service:
ApiGateway, Status Code: 400, Request ID:
02f3dcab-0126-4d16-8c19-27fb1e05c381,
Extended Request ID: null)" (RequestToken:
d75d527f-da4f-78a5-3000-be3e156ccc7a,
HandlerErrorCode: InvalidRequest)
Here's the relevant template code:
HelloWorldAPI:
Type: AWS::Serverless::Api
Properties:
Name: HelloWorldApi
StageName: !Ref StageName
HelloWorldAPIResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref HelloWorldAPI
ParentId: !GetAtt HelloWorldAPI.RootResourceId
PathPart: hello
HelloWorldAPIMethod:
Type: AWS::ApiGateway::Method
Properties:
AuthorizationType: NONE
HttpMethod: GET
ResourceId: !Ref HelloWorldAPIResource
RestApiId: !Ref HelloWorldAPI
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloWorldFunction.Arn}/invocations
# - Arn: !GetAtt HelloWorldFunction.Arn
HelloWorldAPIDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref HelloWorldAPI
StageName: !Ref StageName
DependsOn:
- HelloWorldAPIMethod
You can't switch that off. From docs:
When an AWS::Serverless::Api is specified, AWS Serverless Application Model (AWS SAM) always generates an AWS::ApiGateway::RestApi base AWS CloudFormation resource. In addition, it also always generates an AWS::ApiGateway::Stage and an AWS::ApiGateway::Deployment resource.
If you want to keep using AWS::Serverless::Api you have to use the auto-generated AWS::ApiGateway::Deployment, rather then your own. You do this by appending .Deployment to the name:
!Ref <api‑LogicalId>.Deployment
Alternatively, don't use AWS::Serverless::Api at all, as you seem you are creating everything from scratch anyway.
Related
Building a simple Hello World API using SAM(API Gateway + Lambda). I was told DependsOn is supposed to work with all resources.
The APIs were configured as :
HelloWorldAPI:
Type: AWS::Serverless::Api
# Type: AWS::ApiGateway::RestApi
Properties:
Name: HelloWorldApi
StageName: !Ref StageName
HelloWorldAPIResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref HelloWorldAPI
ParentId: !GetAtt HelloWorldAPI.RootResourceId
PathPart: hello
HelloWorldAPIMethod:
Type: AWS::ApiGateway::Method
Properties:
AuthorizationType: NONE
HttpMethod: GET
ResourceId: !Ref HelloWorldAPIResource
RestApiId: !Ref HelloWorldAPI
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: GET
Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloWorldFunction.Arn}/invocations
# - Arn: !GetAtt HelloWorldFunction.Arn
HelloWorldAPIDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref HelloWorldAPI
StageName: !Ref StageName
DependsOn:
- HelloWorldAPIMethod
But I get the following errors during deployment:
CREATE_FAILED AWS::ApiGateway::Deployment HelloWorldAPIDeployment Properties validation failed for resource
HelloWorldAPIDeployment with message: #:
extraneous key [DependsOn] is not permitted
CREATE_FAILED AWS::ApiGateway::Resource HelloWorldAPIResource Resource creation cancelled
CREATE_FAILED AWS::ApiGateway::Deployment HelloWorldAPIDeployment5332c373d4 Resource handler returned message: "The REST
API doesn't contain any methods (Service:
ApiGateway, Status Code: 400, Request ID:
634b4de5-ead7-48f5-8075-ab55d7176189,
Extended Request ID: null)" (RequestToken:
ef65a5fd-cdf4-fe14-2010-a513bca36aca,
HandlerErrorCode: InvalidRequest)
The explicitly defined AWS::ApiGateway::Deployment is unable to use DependsOn, while there is another AWS::ApiGateway::Deployment being created implicitly but unnecessarily which is being deployed before the method, which was the reason I defined one explicitly in the first place.
Any help is appreciated.
DependsOn should have one last tab less:
HelloWorldAPIDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref HelloWorldAPI
StageName: !Ref StageName
DependsOn:
- HelloWorldAPIMethod
In my CloudFormation template I create a Serverless::Api resource like so,
Resources:
RestApi:
Type: AWS::Serverless::Api
Properties:
StageName: v1
Auth:
DefaultAuthorizer: DefaultAuthorizer
Authorizers:
TokenAuthorizer:
FunctionArn: !GetAtt AuthorizerFunction.Arn
Then I want to add a custom resource to this API, to do that I add this resource to my template
Resources:
ShareResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt RestApi.RootResourceId
RestApiId: !Ref RestApi
PathPart: 'share'
When I deploy the CloudFormation template, it works and I get no errors, however, the custom ShareResource is not in the API, it doesn't exist anywhere. However, when I look at the CloudFormation event outputs, it says the resource was created.
How do I achieve this?
Just a hunch, but this potentially could be caused from not putting any methods inside the resource. try adding a child AWS::ApiGateway::Method to your resource and see if cloudformation builds correctly. E.g.
Resources:
RestApi:
Type: AWS::Serverless::Api
Properties:
StageName: v1
Auth:
DefaultAuthorizer: DefaultAuthorizer
Authorizers:
TokenAuthorizer:
FunctionArn: !GetAtt AuthorizerFunction.Arn
ShareResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt RestApi.RootResourceId
RestApiId: !Ref RestApi
PathPart: 'share'
MockMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
RestApiId: !Ref RestApi
ResourceId: !Ref ShareResource
HttpMethod: GET
AuthorizationType: NONE
Integration:
Type: MOCK
Get the following when deploying a CloudFormation stack:
The REST API doesn't contain any methods (Service: AmazonApiGateway;
Status Code: 400; Error Code: BadRequestException; Request ID:
d527f56e-a1e1-11e9-a0a4-af7563b2b15a)
The stack has a single Lambda triggered by an API with a single resource and method:
FailureReporting:
Type: "AWS::ApiGateway::RestApi"
DependsOn: "MyLambdaFunction"
Properties:
Name: "FailureReporting"
FailOnWarnings: true
FailureReportingDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId:
Ref: "FailureReporting"
Description: "Production environment supporting version-1 of the interface."
StageName: "v1"
Failures:
Type: "AWS::ApiGateway::Resource"
Properties:
RestApiId: !Ref "FailureReporting"
ParentId: !GetAtt ["FailureReporting", "RootResourceId"]
PathPart: "failures"
FailuresMethodGet:
Type: "AWS::ApiGateway::Method"
Properties:
RestApiId: !Ref "FailureReporting"
ResourceId: !Ref "Failures"
HttpMethod: "GET"
AuthorizationType: "NONE"
MethodResponses:
- StatusCode: "200"
Integration:
IntegrationHttpMethod: "POST"
Type: "AWS_PROXY"
IntegrationResponses:
- StatusCode: "200"
Credentials: !GetAtt [ 3FailureReportingExecuteAPI, Arn ]
Uri: !Sub
- "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations"
- lambdaArn: !GetAtt [ GetFailureKeysByOrderNumber, Arn ]
I'm missing where I mucked up.
Put a DependsOn the deployment resource:
FailureReportingDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn:
- "FailuresMethodGet"
Properties:
Description: "Production environment supporting version-1 of the interface."
RestApiId: !Ref "FailureReporting"
StageName: "v1"
It's not intuitive. Buried in the docs you'll find the following:
If you create an AWS::ApiGateway::RestApi resource and its methods
(using AWS::ApiGateway::Method) in the same template as your
deployment, the deployment must depend on the RestApi's methods. To
create a dependency, add a DependsOn attribute to the deployment. If
you don't, AWS CloudFormation creates the deployment right after it
creates the RestApi resource that doesn't contain any methods, and AWS
CloudFormation encounters the following error: The REST API doesn't
contain any methods.
I want to add authorization to endpoints used for lambda.
Since I can not set up this in Lambda definition, I create methods explicitly.
LambdaName:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./lambdaDir
FunctionName: LambdaName
Events:
APIEvent:
Type: Api
Properties:
RestApiId: !Ref MyApi
Path: /products
Method: POST
MyApi:
Type: AWS::Serverless::Api
Properties:
Name: MyApi
StageName: dev
ProductsResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId:
Fn::GetAtt:
- "MyApi"
- "RootResourceId"
PathPart: products
RestApiId: !Ref MyApi
ProductsCreateApiMethod:
Type: AWS::ApiGateway::Method
Properties:
AuthorizationType: NONE
AuthorizerId: !Ref Authorizer
AuthorizationScopes:
- someScope
RestApiId: !Ref MyApi
HttpMethod: POST
ResourceId: !Ref ProductsResource
Unfortunately I get error:
Another resource with the same parent already has this name: products (Service: AmazonApiGateway; Status Code: 409; Error Code: ConflictException; Request ID: 03ca26de-27be-11e9-82bb-536e557773f3)
It seems like when Cloud Formation tries to create explicitly products resource, it is already there created implicitly by lambda definition,
I have created a cloudformation template to create api gateway/resource/method/function on AWS platform, and also associated a lambda function to my api. Once I create the stack I get a url to hit my aws api. Whenever I hit this url, I get internal server error.
I am not sure what could be the reason, but if I toggle between 2 lambda functions from aws console for integration request and deploy, it starts working as expected.
I don't want to do it manually as deployment should be done at the time of stack creation.
Below is the template I used to create resources
Resources:
RestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: !Sub 'testing'
EndpointConfiguration:
Types:
- 'EDGE'
ApigwResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref RestApi
ParentId: !GetAtt RestApi.RootResourceId
# lambda function
LambdaFunction:
Type: AWS::Lambda::Function
Properties:
Role: 'lambda_role'
Handler: lambda_s3.lambda_handler
Code:
S3Bucket: { 'Fn::ImportValue': !Sub '${S3Bucket}-S3AppsBucketId' }
S3Key: 'lambda_source_code'
Runtime: python3.7
MemorySize: 128
Timeout: 60
FunctionName: !Sub 'lambda_function'
ApiGatewayMethod:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: PUT
ResourceId: !Ref ApigwResource
RestApiId: !Ref RestApi
AuthorizationType: AWS_IAM
MethodResponses:
- ResponseModels: { 'application/json' : 'Empty' }
StatusCode: 200
Integration:
Type: AWS
IntegrationHttpMethod: PUT
IntegrationResponses:
- StatusCode: 200
Uri: !Sub
- 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations'
- lambdaArn: !GetAtt LambdaFunction.Arn
ApiGatewayDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn:
- 'ApiGatewayMethod'
Properties:
RestApiId: !Ref RestApi
StageName: !Ref Environment
I found the problem, my api gateway didn't have permission to invoke lambda function. When I was toggling lambda functions manually, it used to provide necessary permissions to my api gateway thus this work around was working. I added below piece to my cloudformation template to make this work.
ConfigLambdaPermission:
Type: "AWS::Lambda::Permission"
DependsOn:
- RestApi
- LambdaFunction
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref LambdaFunction
Principal: apigateway.amazonaws.com