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

6

我手动构建了一个API网关资源,它看起来像这样:

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

enter image description here

我希望能在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 资源如下所示: enter image description here 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

我应该如何操作才能使GET资源具有嵌套的路径/assets/{items}指向S3存储桶,而{proxy+}路径指向Lambda?我需要为这些路径指定单独的同级资源,例如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堆栈创建错误,状态原因为指定了无效的映射表达式:验证结果:警告:[],错误:[指定了无效的映射表达式参数:method.request.path.item](服务:AmazonApiGateway;状态代码:400;错误代码:BadRequestException;请求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创建。 - Marcin
请问您能否分享最终可用的模板给其他人,谢谢! - pho_pho
1
@pho_pho,你可以在这里找到它:https://gist.github.com/PatNeedham/5b3c4b68997b0375f27d402a056a6e1b - Pat Needham
感谢您的快速回复和分享! - pho_pho
1个回答

4
所需操作步骤如下:
  • 创建一个具有路径部分为assets的AWS::ApiGateway::Resource,它将使用您Rest API的RootResourceId属性作为ParentId
  • 创建一个具有路径部分为{item}的AWS::ApiGateway::Resource,它将使用上述资源的assets作为ParentId
  • 为上述资源的ResourceId创建一个AWS::ApiGateway::Method。这将使用HTTP_PROXY并将Uri设置为S3存储桶路径,确保在路径中包括{{ item }}变量。
  • 创建一个具有路径部分为{proxy+}的AWS::ApiGateway::Resource,它将使用您Rest API的RootResourceId属性作为ParentId
  • 为上述资源的ResourceId创建一个AWS::ApiGateway::Method。这将使用AWS_PROXY并将uri设置为引用Lambda函数。
希望能对您有所帮助。

所以我认为我通过给出 Uri: !Sub >- arn:aws:apigateway:${AWS::Region}:s3:path/${s3BucketName}/{item} 解决了 uri 部分的问题 - 现在 CF 控制台中不再有任何投诉,但是对于 RequestParameters 字段,我正在提供一个键/值对,其中键为 integration.request.path.item,值为 true,但它抱怨“指定了无效的映射表达式:true” - 还尝试将值设置为 'method.request.path.item',但是仍然出现相同的错误。 - Pat Needham
对于HTTP代理,它只需要是URL,即S3存储桶的URL,这就足够了。 - Chris Williams
1
有其他错误吗?你现在可以重新发布你的CloudFormation吗? :) - Chris Williams
嗨,所以,将RequestParameters添加到Method中,而不是集成参数,并在其中设置method.request.path.item为true,然后在集成参数中添加设置integration.request.path.item等于method.request.path.item的RequestParameters属性。 - Chris Williams
1
你能分享最终的工作模板吗?那会对我很有帮助!!! - Abhishek Patel
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接