如何使用Cloudformation在AWS API Gateway上设置代理

时间:2018-08-29 00:10:27

标签: amazon-web-services aws-lambda yaml aws-api-gateway amazon-cloudformation

我有一个lambda函数,它将使用Amazon API Gateway {proxy+}处理PUT和GET请求。 通过Amazon Console手动设置所有设置后,它可以正常工作。但是我想使用AWS Cloudformation使其自动化。

为了通知您,我将写出设置{proxy+}的步骤:

1)创建一个简单的Lambda function并将以下代码行粘贴到其中:

import boto3

def lambda_handler(event, context):
    return {
        "statusCode": 200,
        "headers": {
            "Content-Type": 'text/html',
            "Access-Control-Allow-Origin": "*"
        },
        "body": "Hello Reza Amya, Your Lambda is working..!"
    }

2)转到Amazon API Gateway,然后单击Create API

3)选择New API,填充API name,从Edge optimized的列表中选择Endpoint Type,然后单击Create API

4)然后创建您的API,您应该在其Resources页面上,否则请转到Resources页面以创建API。

5)从Actions中选择Create Resource

6)选择Configure as proxy resource(然后它应该自动更改其他字段,如果没有更改,请为proxy输入Resource Name,为{proxy+}输入Resource Path ),然后点击Create Resource

7)为Lambda Function Proxy选择Integration type,然后从Lambda Function中选择您的lambda函数,然后单击Save

8)在Add Permission to Lambda Function弹出窗口中,单击Ok

9)从Actions单击Deploy API

10)从New Stage的列表中选择Deployment stage,然后为Stage name键入一个名称(对我来说,我输入了'api'),然后单击Deploy < / p>

11)在已部署API的根页面上的stage上,您可以看到Invoke URL。单击它,它将打开链接到类似以下位置的新标签:https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/api/

12)在您的网址末尾添加一个简单的段,如下所示: https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/api/ 测试

现在您应该在浏览器页面中看到以下消息:

Hello Reza Amya, Your Lambda is working..!

现在的问题是我已经在Yaml文件中编写了所有这些步骤:

AWSTemplateFormatVersion: 2010-09-09
Description: My Lambda Function
Parameters:
  S3Bucket:
    Description: S3 Bucket where the Lambda code is
    Type: String
  S3Key:
    Description: S3 Key where the Lambda code is
    Type: String
  S3ObjectVersion:
    Description: Version of the S3 Key to use
    Type: String

Resources:
  apiGateway:
    Type: "AWS::ApiGateway::RestApi"
    Properties:
      Name: "my-api"
      Description: "My API"
      EndpointConfiguration:
        Types:
          - EDGE

  Resource: 
    Type: AWS::ApiGateway::Resource
    Properties: 
      RestApiId: 
        Ref: "apiGateway"
      ParentId: 
        Fn::GetAtt: 
          - "apiGateway"
          - "RootResourceId"
      PathPart: "{proxy+}"

  ProxyMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      HttpMethod: ANY
      ResourceId: !Ref Resource
      RestApiId: !Ref apiGateway
      AuthorizationType: NONE
      RequestParameters:
        method.request.path.proxy: true
      Integration:
        CacheKeyParameters:
          - 'method.request.path.proxy'
        RequestParameters:
          integration.request.path.proxy: 'method.request.path.proxy'
        Type: AWS_PROXY
        IntegrationHttpMethod: ANY
        Uri: !Sub
          - arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Arn}/invocations
          - Arn:
              Fn::GetAtt:
               - LambdaFunction
               - Arn
        PassthroughBehavior: WHEN_NO_MATCH
        IntegrationResponses:
          - StatusCode: 200 

  apiGatewayDeployment:
    Type: "AWS::ApiGateway::Deployment"
    DependsOn:
      - "ProxyMethod"
    Properties:
      RestApiId: !Ref "apiGateway"
      StageName: "dev"

  IAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: 'sts:AssumeRole'

      Policies:
        - PolicyName: Logging
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: 'arn:aws:logs:*:*:*'
        - PolicyName: AccessToDynamoDB
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - 'dynamodb:CreateTable'
                  - 'dynamodb:DeleteItem'
                  - 'dynamodb:DeleteTable'
                  - 'dynamodb:GetItem'
                  - 'dynamodb:GetRecords'
                  - 'dynamodb:UpdateItem'
                  - 'dynamodb:UpdateTable'
                  - 'dynamodb:PutItem'
                  - 'dynamodb:UpdateTable'
                Resource: 'arn:aws:dynamodb:*:*:*'

  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: {Ref: S3Bucket}
        S3Key: {Ref: S3Key}
        S3ObjectVersion: {Ref: S3ObjectVersion}
      Handler: main.lambda_handler
      MemorySize: 128
      Role: {'Fn::GetAtt': [IAMRole, Arn]}
      Runtime: python3.6
      Timeout: 300

  LambdaInvokePermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !GetAtt 
        - LambdaFunction
        - Arn
      Action: 'lambda:InvokeFunction'
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/*/*

Outputs:
  apiGatewayInvokeURL:
    Value: !Sub "https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/${apiGateway}"

  lambdaArn:
    Value: !GetAtt "LambdaFunction.Arn"

上面的Yaml文件将创建Lambda函数并部署API,但是当我尝试测试API时,它将显示以下错误:

{"message": "Internal server error"}

能否请您指导我哪里出了问题以及如何解决该问题?

1 个答案:

答案 0 :(得分:2)

问题与您的IntegrationHttpMethod设置有关。尽管您的APIGateway方法为ANY,但对于AWS Lambda,IntegrationHttpMethod必须始终为POST

这将导致以下方法声明。

  ProxyMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      HttpMethod: ANY
      ResourceId: !Ref Resource
      RestApiId: !Ref apiGateway
      AuthorizationType: NONE
      RequestParameters:
        method.request.path.proxy: true
      Integration:
        CacheKeyParameters:
          - 'method.request.path.proxy'
        RequestParameters:
          integration.request.path.proxy: 'method.request.path.proxy'
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Sub
          - arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Arn}/invocations
          - Arn:
              Fn::GetAtt:
               - LambdaFunction
               - Arn
        PassthroughBehavior: WHEN_NO_MATCH
        IntegrationResponses:
          - StatusCode: 200