AWS CloudFormation 堆栈:具有嵌套路径的 API 网关资源?

Pat*_*ham 6 amazon-web-services aws-cloudformation aws-api-gateway

我有一个手动构建的 API 网关资源,如下所示:

GET
  /assets/{items} - (points to S3 bucket)
  /{proxy+} - points to Lambda function
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

我想在 Cloudformation YAML 模板中模仿此设置,但不确定如何操作。这是我正在使用的当前模板(为简洁起见,部分缩小):

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  apiGatewayStageName:
    Type: String
    AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
    Default: call
  lambdaFunctionName:
    Type: String
    AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
    Default: my-function
  s3BucketName:
    Type: String
    AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
Resources:
  apiGateway:
    Type: 'AWS::ApiGateway::RestApi'
    Properties:
      Name: my-api
      Description: My API
    Metadata:
      ...
  apiGatewayRootMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: NONE
      HttpMethod: POST
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Sub 
          - >-
            arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
          - lambdaArn: !GetAtt lambdaFunction.Arn
      ResourceId: !GetAtt apiGateway.RootResourceId
      RestApiId: !Ref apiGateway
    Metadata:
      ...
  apiGatewayDeployment:
    Type: 'AWS::ApiGateway::Deployment'
    DependsOn:
      - apiGatewayRootMethod
      - apiGatewayGETMethod
    Properties:
      RestApiId: !Ref apiGateway
      StageName: !Ref apiGatewayStageName
    Metadata:
      ...
  lambdaFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      ...
  lambdaApiGatewayInvoke:
    ...
  lambdaIAMRole:
    ...
  lambdaLogGroup:
    ...
  apiGatewayGETMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: NONE
      HttpMethod: GET
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Sub 
          - >-
            arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
          - lambdaArn: !GetAtt lambdaFunction.Arn
      ResourceId: !GetAtt apiGateway.RootResourceId
      RestApiId: !Ref apiGateway
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 1a329c4d-9d18-499e-b852-0e361af324f4
  s3Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: !Ref s3BucketName
    Metadata:
      ...
Outputs:
  apiGatewayInvokeURL:
    Value: !Sub >-
      https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/${apiGatewayStageName}
  lambdaArn:
    Value: !GetAtt lambdaFunction.Arn
Run Code Online (Sandbox Code Playgroud)

这是大量调整的结果,而且除了阅读官方文档之外,我之前没有任何 CloudFormation 知识。创建该模板背后的堆栈后,其 API 网关资源如下所示: 在此输入图像描述

POST 操作是不必要的,只能通过反复试验才能实现。GET 资源是唯一重要的资源,因为 Lambda 函数返回的应用程序尚未执行任何 post 请求。

GET 必须从堆栈的这一部分创建:

apiGatewayGETMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: NONE
      HttpMethod: GET
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Sub 
          - >-
            arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
          - lambdaArn: !GetAtt lambdaFunction.Arn
      ResourceId: !GetAtt apiGateway.RootResourceId
      RestApiId: !Ref apiGateway
Run Code Online (Sandbox Code Playgroud)

必须做什么才能使 GET 资源具有/assets/{items}指向 S3 存储桶的嵌套路径和{proxy+}指向 Lambda 的路径?我是否需要为这些路径指定单独的同级资源apiGatewayAssets,然后以某种方式apiGatewayLambdaProxy将它们连接到apiGatewayGETMethod

2020-05-17 更新

当前让我困惑的是这个资源:

apiGatewayAssetsItemsResourceMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref apiGatewayAssetsItemsResource
      RestApiId: !Ref apiGateway
      AuthorizationType: NONE
      HttpMethod: GET
      Integration:
        Type: AWS
        Credentials: arn:aws:iam::XXXXXX:role/AnExistingRole
        IntegrationHttpMethod: GET
        PassthroughBehavior: WHEN_NO_MATCH
        RequestParameters:
          integration.request.path.item: 'method.request.path.item'
          method.request.path.item: true
        Uri: !Sub >-
          arn:aws:apigateway:${AWS::Region}:s3:path/${s3BucketName}/{item}
Run Code Online (Sandbox Code Playgroud)

这会导致 CloudFormation 堆栈创建错误,状态原因为Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression parameter specified: method.request.path.item] (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: XXXXXX)

但是,如果我尝试使用完全相同的资源减去该RequestParameters条目来创建它,它就会成功创建。尽管在控制台中查看 API Gateway GET 方法时,Paths: item集成请求框中缺少该行。我目前使用的完整模板:

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  apiGatewayStageName:
    Type: String
    AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
    Default: call
  lambdaFunctionName:
    Type: String
    AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
    Default: my-function
  s3BucketName:
    Type: String
    AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
Resources:
  apiGateway:
    Type: 'AWS::ApiGateway::RestApi'
    Properties:
      Name: my-api
      Description: My API
  apiGatewayDeployment:
    Type: 'AWS::ApiGateway::Deployment'
    DependsOn:
      - apiGatewayGETMethod
    Properties:
      RestApiId: !Ref apiGateway
      StageName: !Ref apiGatewayStageName
  lambdaFunction:
    ...
  lambdaApiGatewayInvoke:
    ...
  lambdaIAMRole:
    ...
  lambdaLogGroup:
    ...
  apiGatewayGETMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: NONE
      HttpMethod: GET
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Sub 
          - >-
            arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
          - lambdaArn: !GetAtt lambdaFunction.Arn
      ResourceId: !GetAtt apiGateway.RootResourceId
      RestApiId: !Ref apiGateway
  s3Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: !Ref s3BucketName
  BucketPolicy:
    ...
  apiGatewayAssetsResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref apiGateway
      ParentId: !GetAtt 
        - apiGateway
        - RootResourceId
      PathPart: assets
  apiGatewayAssetsItemsResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref apiGateway
      PathPart: '{item}'
      ParentId: !Ref apiGatewayAssetsResource
  apiGatewayAssetsItemsResourceMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref apiGatewayAssetsItemsResource
      RestApiId: !Ref apiGateway
      AuthorizationType: NONE
      HttpMethod: GET
      Integration:
        Type: AWS
        Credentials: arn:aws:iam::XXXXXX:role/AnExistingRole
        IntegrationHttpMethod: GET
        PassthroughBehavior: WHEN_NO_MATCH
        Uri: !Sub >-
          arn:aws:apigateway:${AWS::Region}:s3:path/${s3BucketName}/{item}
  apiGatewayLambdaResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref apiGateway
      PathPart: '{proxy+}'
      ParentId: !GetAtt 
        - apiGateway
        - RootResourceId
  apiGatewayLambdaResourceMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: NONE
      RestApiId: !Ref apiGateway
      ResourceId: !Ref apiGatewayLambdaResource
      HttpMethod: ANY
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: GET
        Uri: !Sub 
          - >-
            arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
          - lambdaArn: !GetAtt lambdaFunction.Arn
Outputs:
  apiGatewayInvokeURL:
    Value: !Sub >-
      https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/${apiGatewayStageName}
  lambdaArn:
    Value: !GetAtt lambdaFunction.Arn
Run Code Online (Sandbox Code Playgroud)

Chr*_*ams 4

因此,您需要执行以下操作:

  • 创建 PathPart 为 AWS::ApiGateway::Resource assets,这将使用来自 Rest API 的 RootResourceId attr 的 ParentId
  • 创建 PathPart 为 AWS::ApiGateway::Resource 的 AWS::ApiGateway::Resource {item},这将使用上面资源资源的 ParentId。
  • 为上述资源的 ResourceId 创建一个 AWS::ApiGateway::Method。这将使用HTTP_PROXY并将 Uri 设置为 S3 存储桶路径,确保{{ item }}在路径中包含该变量。
  • 创建 PathPart 为 AWS::ApiGateway::Resource {proxy+},这将使用来自 Rest API 的 RootResourceId attr 的 ParentId
  • 为上述资源的 ResourceId 创建一个 AWS::ApiGateway::Method。这将使用AWS_PROXY并设置 uri 来引用 Lambda 函数。

希望这可以帮助