Passing AWS region and account ID to swagger - amazon-web-services

I am defining my API Gateway APIs using AWS SAM
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
DefinitionUri: swagger.yml
StageName: prod
Variables:
Region: !Ref AWS::Region
AccountId: !Ref AWS::AccountId
Ec2Index: !Ref Ec2Index
AuthLogin: !Ref AuthLogin
Ec2Patch: !Ref Ec2Patch
AutoScalingIndex: !Ref AutoScalingIndex
AutoScalingPatch: !Ref AutoScalingPatch
AutoScalingScale: !Ref AutoScalingScale
In my swagger file:
paths:
/auth/session:
post:
produces:
- application/json
x-amazon-apigateway-integration:
uri: arn:aws:apigateway:ap-southeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-southeast-1:598545985414:function:${stageVariables.AuthLogin}/invocations
passthroughBehavior: when_no_match
httpMethod: POST
type: aws_proxy
responses:
200:
description: App token
401:
description: 401
403:
description: 403
AWS CloudFormation errors saying
Errors found during import: Unable to put integration on 'POST' for resource at path '/auth/session': Lambda function ARN must be in same account Unable to put integration on 'GET' for resource at path '/autoscaling': Lambda function ARN must be in same account Unable to put integration on 'PATCH' for resource at path '/autoscaling/{groupName}': Lambda function ARN must be in same account Unable to put integration on 'POST' for resource at path '/autoscaling/{groupName}/scale': Lambda function ARN must be in same account Unable to put integration on 'GET' for resource at path '/ec2': Lambda function ARN must be in same account Unable to put integration on 'PATCH' for resource at path '/ec2/{id}': Lambda function ARN must be in same account
Seems like my ARN is invalid. This is resolved once I remove the variables. Whats wrong here?

As of now swagger does not allow AccountId in stage variables. It's a limitation of the API Gateway.
You can get around this by just using a stage variable for the function name only and piece the rest together like this:
//does not get passed in. This is just a placeholder for the stage variable
Parameters:
ApiFunctionName:
Type: String
Description: Function name of the api lambda function
Default: ${stageVariables.yourFunctionNameVar}
//in your gateway path
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
!Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${ApiFunctionName}/invocations"

Passing variables to swagger is not possible to do at this moment from a SAM template, but you can copy entire swagger file in the template file as DefinitionBody and reference variables the same way provided swagger definition is not huge.
SAM template is currently limited to 51.2 KB

Related

AWS SAM - Enforcing Request Validation in API Gateway Method by SAM Template

I am working on a SAM application having a lambda function with API Gateway as source of event. API Endpoint is a POST Method requiring a set of parameters in request body. API Gateway provides us the capability of validating request body by specifying a request Model using AWS Console.
Refer Screenshots below of AWS Console options:
I need to set similar options via SAM template and able to link a Model with the request body but not able to set request validator option and is not able to find any documentation or example also.
Below is my SAM Template
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM Template
Parameters:
Stage:
Type: String
Default: dev
Resources:
MyApiGateway:
Type: AWS::Serverless::Api
Properties:
Name: My AWS Serverless API
StageName: !Ref Stage
Models:
ExchangeRate:
$schema: "http://json-schema.org/draft-04/schema#"
properties:
base:
type: string
target:
type: string
required:
- base
- target
title: User
type: object
ExchangeRateFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: functions/exchange-rate/
Handler: index.handler
Runtime: nodejs12.x
Description: Function to Get Currency Exchange Rate
MemorySize: 128
Timeout: 3
Policies:
- AWSLambdaBasicExecutionRole
Events:
HelloWorld:
Type: Api
Properties:
RestApiId: !Ref MyApiGateway
Path: /exchange
Method: POST
RequestModel:
Model: ExchangeRate
Required: true
Outputs:
ExchangeRateFunction:
Description: "Exchange Rate Lambda Function ARN"
Value: !GetAtt ExchangeRateFunction.Arn
MyApiGateway:
Description: "My Seed API EndPoint"
Value: !Sub "https://${MyApiGateway}.execute-api.${AWS::Region}.amazonaws.com/${Stage}"
Documentation referred
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-api.html
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html
Please let me know how can I set 'Request Validator' to 'Validate body' option using SAM template. Will appreciate the help
Add ValidateBody: true i.e.
RequestModel:
Model: ExchangeRate
Required: true
ValidateBody: true
I've ran into the same problem, apparently this feature is lacking from SAM for a while, as you can see from this previous question:
How to add a request validator in a AWS SAM template for AWS::Serverless::Api?
Also, a few issues have been opened in GitHub, the last one being:
https://github.com/awslabs/serverless-application-model/issues/1403
I've hacked a solution that includes two additional properties in the SAM specification to solve this issue, but I wouldn't expect it to actually become a PR. I can provide further instructions if you'd like to use my forked repo to deploy from a develop branch.

Creating an API Gateway AWS Integration with S3

I would like to set up API Gateway to retrieve files from a specific bucket on S3.
The GET method for the resource in the Cloudformation template looks like this:
GetMethod:
Type: "AWS::ApiGateway::Method"
Properties:
HttpMethod: GET
ApiKeyRequired: true
AuthorizationType: NONE
RequestParameters:
'method.request.path.listId': true
RestApiId:
Ref: ApiGatewayRestApi
ResourceId:
Ref: Lists
Integration:
Type: aws
Credentials:
Ref: S3ReadAccessRole
IntegrationHttpMethod: GET
PassthroughBehavior: WHEN_NO_MATCH
RequestParameters:
'integration.request.path.key': 'method.request.path.listId'
I am having trouble specifying the S3 URI to integrate with. I've done the following with no success:
The S3 URI: arn:aws:s3:::lists/groceries/{key}
The API Gateway based uri based on this article. arn:aws:apigateway:us-west-2:s3:lists/groceries/{key}
Please help me figure out the correct URI to allow objects on S3 to be retrieved using API Gateway directly.

AWS SAM Template Fails to Create Configurations for API Gateway

I have a problem with AWS SAM and provisioning API Gateway configurations. I am trying to do a few things:
Configure the API gateway to require api-key in the headers
Create my own stage as defined in my config files.
The API gateway model defined in my file is not being created
Currently, the API gateway gets provisioned and linked to my lambda function but it fails in the two requirements above. Below are my files: template.yaml and swagger.yaml.
Template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-nfeed-s3
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 60
Api:
EndpointConfiguration: REGIONAL
Resources:
SAMnfeedS3API:
Type: AWS::Serverless::Api
Properties:
StageName: alpha
DefinitionUri: ./swagger.yaml
Resources:
SAMnfeedS3Lambda:
Type: AWS::Serverless::Function
Properties:
CodeUri: test-function-sam/
Handler: nfeed_vdp_clusters.lambda_handler
Runtime: python3.6
Role: arn:aws:iam::XXXXXXX:role/Lambda
Events:
SAMnfeedS3API:
Type: Api
Properties:
Path: /vdp_clusters
Method: GET
Environment:
Variables:
TEST: test
Outputs:
SAMnfeedS3API:
Description: "API Gateway endpoint URL for Staging env"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Staging/vdp_clusters"
SAMnfeedS3Lambda:
Description: "Lambda Function ARN"
Value: !GetAtt SAMnfeedS3Lambda.Arn
Swagger.yaml
---
swagger: '2.0'
info:
title: !Ref AWS::StackName
basePath: "/alpha"
schemes:
- "https"
x-amazon-apigateway-api-key-source : "HEADER"
paths:
"/vdp_clusters":
get:
consumes:
- application/json
produces:
- application/json
parameters:
- name: x-api-key
in: header
required: true
type: string
responses:
200:
description: "200 response"
schema:
$ref: "#/definitions/Empty"
x-amazon-apigateway-integration:
uri: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:XXXXXXXXX:function:${SAMnfeedS3Lambda.Arn}/invocations
responses:
default:
statusCode: "200"
httpMethod: "POST"
type: aws_proxy
security:
- api_key: []
securityDefinitions:
api_key:
type: "apiKey"
name: "x-api-key"
in: "header"
definitions:
Empty:
type: "object"
title: "Empty Schema"
$schema: "http://json-schema.org/draft-04/schema#"
As defined in my swagger and template files, "alpha" stage should be created for the gateway but nothing appears. The "Empty" model and api-key requirement also do not appear. Any help, would be appreciated.
The problem is you have duplicated the Resources key in the template.
I recommend always using the yamllint utility on your SAM templates, because it detects YAML formatting issues that sam validate can't always detect. Here is what I got:
▶ yamllint sam-app/template.yaml
sam-app/template.yaml
...
18:1 error duplication of key "Resources" in mapping (key-duplicates)
If you then look in the packaged.yml file that is created by the sam build step, you'll notice that the API you defined will be missing. That's because it's impossible for a dict in Python to contain duplicate keys. The second Resources block you specified just overwrites the first one when the Python YAML library reads the file in.
SAM then generates the implicit API SAMnfeedS3API based on the API you specified in Events using its own generated Swagger rather than the one you (thought you) provided.
Note also that, after you fix up the duplicate key issue, you will also need to reference your API from the Events with a line like:
Events:
SAMnfeedS3API:
Type: Api
Properties:
Path: /vdp_clusters
Method: GET
RestApiId: !Ref SAMnfeedS3API ## ADD THIS LINE
See also my earlier answer here.

AWS Cloudformation: How to get a RestAPI name

Goal
Get the name for an API GW created within Cloudformation stack. The API Name is required if trying to get an API GW metric, since they exist By Api Name
.yaml Example
TESTAPI:
Type: AWS::ApiGateway::RestApi
Properties:
Description: 'test api'
EndpointConfiguration:
Types:
- REGIONAL
Problem
If I call !Ref TESTAPI, I get the API ID, and if I call !GetAtt TESTAPI.Name the error is: "invalid resource attribute"
The docs don't show any return values.
Unless the CloudFormation RestApi resource is modified, it will not provide the Name attribute.
Workaround
Create a string Parameter to hold the string and enforce the API Name, which you can refer later with !GetAtt APIName.Value
YAML example
APIName:
Type: AWS::SSM::Parameter
Properties:
AllowedPattern: "^[-a-zA-Z0-9 ]+$"
Type: String
Value: "Some API name"

"Unable to parse API definition because of a malformed integration at path /price. (Service: AmazonApiGateway; Status Code: 400;

The following code I put for x-amazon-apigateway-integration, please let me know if I am missing something. Thanks
x-amazon-apigateway-integration:
httpMethod: post
type: aws
uri:
Fn::Sub:
- arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations
- { FunctionArn: !GetAtt PriceAPIFunction.Arn}
responses:
default:
statusCode: '200'
The ${AWS::Region} substitution is not supported - only the function name can be substituted. see https://github.com/awslabs/serverless-application-model/issues/79
Hi Mayank, Andreas
I was trying to create the CFT Deployment for the API and was getting the same error as Unable to parse API definition because of a malformed integration at path /.
I just figured out the solution as creating a AWS::Serverless-2016-10-31 Template for the deployment.
You must write the CloudFormation Template as :-
1. Add definition Transform: AWS::Serverless-2016-10-31 in the beginning of the Template.
2. For the API Definition, must refer the OpenApi as DefinitionBody: with the Transform function, which will modulate the YAML accordingly.
Type: AWS::Serverless::Api
Properties:
Name: !Sub "MyRestAPI"
StageName: !Sub "dev"
DefinitionBody:
"Fn::Transform":
Name: "AWS::Include"
Parameters:
Location: !Sub "s3://${TemporaryBucket}/openapi.yaml"