【问题标题】:AWS CloudFormation stack: API Gateway resource with nested paths?AWS CloudFormation 堆栈:具有嵌套路径的 API Gateway 资源?
【发布时间】:2020-08-30 11:48:19
【问题描述】:

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

GET
  /assets/{items} - (points to S3 bucket)
  /{proxy+} - points to Lambda function

我想在 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

这是经过大量调整的结果,除了查看官方文档之外,我之前没有任何 CloudFormation 知识。创建该模板背后的堆栈后,其 API Gateway 资源如下所示:

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

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

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

这会导致 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

【问题讨论】:

  • 您使用不同的集成方法。在上图中,您使用 AWS,而在下图中,您使用 AWS_PROXY。所以很明显你不能开采它们。因此,要么创建为 AWS,要么创建为 AWS_PROXY。
  • 请您将最终的工作模板分享给其他人,谢谢!
  • @pho_pho 你可以在这里找到它:gist.github.com/PatNeedham/5b3c4b68997b0375f27d402a056a6e1b
  • 感谢您的快速回复和分享!

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


【解决方案1】:

所以你需要做的是:

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

希望对你有帮助

【讨论】:

  • 对于列出的第三个要点,我有一个使用 Properties.Integration.Type 设置为 HTTP_PROXY 定义的资源,对于 Properties.Integration.Uri 字段我将它设置为 arn:aws:apigateway:${AWS::Region}:s3:path/${s3BucketName}/{{item}} 但在创建过程中它失败了消息“为 URI 指定的 HTTP 端点无效(服务:AmazonApiGateway;状态代码:400;错误代码:BadRequestException;请求 ID:XXXXXX”
  • 还尝试使用以 /{item} 结尾的 Uri,结果相同
  • 在发现docs.aws.amazon.com/apigateway/latest/developerguide/… 上提到了arn:aws:apigateway:api-region:s3:path/{bucket} 之后,我还尝试为Uri 赋予arn:aws:apigateway:${AWS::Region}:s3:path/${s3BucketName} 的值,但结果仍然相同。是否有某种 Uri 验证器?在 CloudFormation Designer 页面上查看该堆栈时,单击复选标记会导致“模板有效”。
  • 有不同的错误吗?您现在可以重新发布您的 CloudFormation 吗? :)
  • 你能分享一下最终的工作模板吗,这对我有帮助!!!
猜你喜欢
  • 2021-07-06
  • 2018-10-27
  • 2017-06-26
  • 2018-06-21
  • 2020-01-17
  • 2018-05-25
  • 2019-02-27
  • 2019-06-22
  • 2018-02-24
相关资源
最近更新 更多