lambda and api gateway defined by cloud formation - amazon-web-services

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,

Related

CloudFormation: extraneous key [DependsOn] is not permitted

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

How to add an AWS::ApiGateway::Resource to an AWS::Serverless::Api in CloudFormation template

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

Why does CloudFormation API Gateway fail stating 'The REST API doesn't contain any methods' even with DependsOn?

I have a CloudFormation template which I'm trying to deploy. This template is very similar to another template I have which works without issue however when deploying this template it keeps failing stating:
APIGatewayDeployment5332c373d4 CREATE_FAILED The REST API doesn't contain any methods (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: 02c0352f-b23b-44d5-a0af-2f3f3ecd7273)
I had this issue previously on my other template and added the DependsOn property on the deployment which fixed the issue however even with this property this template is failing.
See cut down version of my template below:
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Environment:
Variables:
FOO: bah
Api:
EndpointConfiguration: REGIONAL
Resources:
APIGateway:
Type: AWS::Serverless::Api
Properties:
Name: Some API
StageName: !Sub ${EnvironmentTagName}
ApiFooResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt APIGateway.RootResourceId
PathPart: foo
RestApiId: !Ref APIGateway
ApiFooNotificationResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !Ref ApiFooResource
PathPart: notification
RestApiId: !Ref APIGateway
ApiFooNotificationMethod:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: POST
AuthorizationType: NONE
ResourceId: !Ref ApiFooNotificationResource
RestApiId: !Ref APIGateway
MethodResponses:
- StatusCode: '200'
Integration:
Credentials: !GetAtt SQSRole.Arn
IntegrationHttpMethod: POST
IntegrationResponses:
- StatusCode: 200
Type: AWS
Uri: !Sub arn:aws:apigateway:${AWS::Region}:sqs:action/SendMessage
RequestParameters:
integration.request.querystring.QueueUrl: !Sub '''${FooNotificationQueue}'''
integration.request.querystring.MessageBody: method.request.body
ApiTestResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt APIGateway.RootResourceId
PathPart: test
RestApiId: !Ref APIGateway
ApiTestMethod:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: POST
AuthorizationType: NONE
ResourceId: !Ref ApiTestResource
RestApiId: !Ref APIGateway
MethodResponses:
- StatusCode: '200'
Integration:
Credentials: !GetAtt SQSRole.Arn
IntegrationHttpMethod: POST
IntegrationResponses:
- StatusCode: 200
Type: AWS
Uri: !Sub arn:aws:apigateway:${AWS::Region}:sqs:action/SendMessage
RequestParameters:
integration.request.querystring.QueueUrl: !Sub '''${TestQueue}'''
integration.request.querystring.MessageBody: method.request.body
ApiDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn: ApiTestMethod
Properties:
RestApiId: !Ref APIGateway
Description: !Sub Api Deployment for ${EnvironmentTagName}
StageName: !Sub ${EnvironmentTagName}
...**Removed the rest for brevity**...
Parameters:
StackTagName:
Type: String
Description: Stack Name (injected by Stackery at deployment time)
EnvironmentTagName:
Type: String
Description: Environment Name (injected by Stackery at deployment time)

Adding an additional resource on serverless for AWS API Gateway

I have a serverless app with a http event. I need to create a child resource to the endpoint created by serverless.
How can I accomplish this with serverless?
The template looks like this so far:
provider:
name: aws
runtime: nodejs8.10
region: <REGION>
functions:
myFunc:
timeout: 30
handler: "index.handler"
name: "myFunc"
events:
- http:
path: /myFunc
method: post
cors: true
resources:
Resources:
saysResource:
Type: "AWS::ApiGateway::Resource"
Properties:
RestApiId:
Ref: ApiGatewayRestApi
ParentId:
Ref: <NEED_/myFunc_RESOURCE_ID_HERE>
PathPart: "{says}"
GetMethod:
Type: "AWS::ApiGateway::Method"
Properties:
HttpMethod: GET
RequestParameters:
'method.request.path.says': true
RestApiId:
Ref: ApiGatewayRestApi
ResourceId:
Ref: saysResource
Integration:
Type: aws
Credentials:
Ref: S3ReadAccessRole
IntegrationHttpMethod: GET
PassthroughBehavior: WHEN_NO_MATCH
RequestParameters:
'integration.request.path.key': 'method.request.path.says'
Uri: 'arn:aws:s3:::my-bucket/users/{key}'
As an attempt to get it working, I re-declaration of the resource for /myFunc was performed(hoping that CFN would not create already created resources):
myFuncResource:
Type: "AWS::ApiGateway::Resource"
Properties:
RestApiId:
Ref: ApiGatewayRestApi
ParentId:
Fn::GetAtt:
- ApiGatewayRestApi
- RootResourceId
PathPart: "/myFunc"
This failed with the error:
An error occurred: myFuncResource - Another resource with the same parent
already has this name: my-func (Service: AmazonApiGateway; Status Code:
409; Error Code: ConflictException; Request ID: <Request_Id>).

AWS API Deployment

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