部署到不同阶段时,无服务器共享API网关错误

时间:2018-10-03 01:49:14

标签: amazon-web-services serverless api-gateway

我正在使用无服务器版本1.29.2

我创建了一个初始cloudformation脚本,该脚本创建了一个API GateWay REST API,该API将被其他服务使用。这是负责它的cloudformation脚本。

{
   "AWSTemplateFormatVersion":"2010-09-09",
   "Description":"API",
   "Resources":{
      "APIGw":{
         "Type":"AWS::ApiGateway::RestApi",
         "Properties":{
            "Name":"API-GW"
         }
      }
   },
   "Outputs":{
      "ApiGwRestApiId":{
         "Value":{
            "Ref":"APIGw"
         },
         "Export":{
            "Name":"apigw-restApiId"
         }
      },
      "eyesApiGwRestApiRootResourceId":{
         "Value":{
            "Fn::GetAtt":[
               "APIGw",
               "RootResourceId"
            ]
         },
         "Export":{
            "Name":"apigw-rootResourceId"
         }
      }
   }
}

这里是我尝试部署的应用程序的serverless.yml。

service: template-test-service

provider:
  name: aws
  runtime: python3.6
  region: eu-central-1
  stage: ${self:custom.environment.stage}
  environment:
    stage: ${self:custom.environment.stage}
  apiGateway:
    restApiId:
      'Fn::ImportValue': apigw-restApiId
    restApiRootResourceId:
      'Fn::ImportValue': apigw-rootResourceId

当我执行sls deploy --stage dev时一切正常,但是当我执行另一次部署到sls deploy --stage prod

出现此错误。

Another resource with the same parent already has this name

2 个答案:

答案 0 :(得分:0)

我已经为这个问题苦苦了一个星期,而问题是与从资源和方法中构造API网关的方式有关。从文档中

  

在Amazon API Gateway中,您将REST API构建为称为API Gateway资源的可编程实体的集合。例如,您使用RestApi资源表示可以包含Resource实体集合的API。每个资源实体又可以具有一个或多个方法资源。在请求参数和主体中表示的方法定义了客户端访问公开资源的应用程序编程接口,并表示客户端提交的传入请求。

当具有通过http事件触发的功能时,无服务器CLI将为您创建所有资源/方法。

functions:
  GetScenesInGame:
    handler: handler.hello
    layers: arn:aws:lambda:eu-west-1:xxxxxxxxx:layer:pynamodb-layer:1
    events:
      - http:
          method: GET
          path: api/v1/game/{gameId}/scene

在上面的示例中,这将创建五个资源(api,v1,game,gameIdParam,场景),最后在最终资源上添加一个GET方法。

不幸的是,如果您有两个单独的堆栈(如您在微服务设置中可能的那样),如果它们是上述方法的一部分,则会出现错误,具有相同父级的另一个资源已经具有此名称 < / p>

本文从无服务器deploy serverless microservice on aws着重介绍了该解决方案,尽管该解决方案不是很明确,也很容易遗漏。

首先,有一个用于配置所需资源的顶级cloudformation模板。

对于要添加无服务器微服务的资源,请将该资源的ID导出为堆栈中的输出变量。

然后在serverless.yml文件中导入api网关引用和apigateway资源ID。

然后您可以部署每个服务,而不会在api结构中出现资源名称冲突。

下面的模板显示了一组顶级资源。

api/v1/game/{gameId}/page

api/v1/game/{gameId}/scene

然后将 PageService 附加到 page 资源和 SceneService 附加到 scene 资源。

api-gateway.yml

    AWSTemplateFormatVersion: "2010-09-09"
Description: "S3 template for deploying S3 to be used by ACS s3 connector."

Resources:
    TestApiGw:
            Type: AWS::ApiGateway::RestApi
            Properties:
                Name: !Sub 'test-apigw-throwaway'

    ApiResource:
        Type: AWS::ApiGateway::Resource
        Properties:
            RestApiId: !Ref TestApiGw
            ParentId: !GetAtt 
                - TestApiGw
                - RootResourceId
            PathPart: "api"

    VersionResource:
        Type: AWS::ApiGateway::Resource
        Properties:
            RestApiId: !Ref TestApiGw
            ParentId: !Ref ApiResource
            PathPart: "v1"

    GameResource:
        Type: AWS::ApiGateway::Resource
        Properties:
            RestApiId: !Ref TestApiGw
            ParentId: !Ref VersionResource
            PathPart: "game"

    GameParamResource:
        Type: AWS::ApiGateway::Resource
        Properties:
            RestApiId: !Ref TestApiGw
            ParentId: !Ref GameResource
            PathPart: "{gameId}"

    SceneResource:
        Type: AWS::ApiGateway::Resource
        Properties:
            RestApiId: !Ref TestApiGw
            ParentId: !Ref GameParamResource
            PathPart: "scene"

    PageResource:
            Type: AWS::ApiGateway::Resource
            Properties:
                RestApiId: !Ref TestApiGw
                ParentId: !Ref GameParamResource
                PathPart: "page"

Outputs:
    ApiRestApiId:
        Value: !Ref TestApiGw
        Export:
            Name: !Sub ${AWS::StackName}-TestApiId

    ApiRootResourceId:
        Value:
            Fn::GetAtt:
                - TestApiGw
                - RootResourceId
        Export:
            Name: !Sub ${AWS::StackName}-ApiRootResourceVar

    ApiSceneResourceVar:
        Value: !Ref SceneResource
        Export:
        # variable names are global so this will need more work to make it unique across stages.
            Name: !Sub ${AWS::StackName}-ApiSceneResourceVar

    ApiPageResourceVar:
        Value: !Ref PageResource
        Export:
        # variable names are global so this will need more work to make it unique across stages.
            Name: !Sub ${AWS::StackName}-ApiPageResourceVar

serverless.yml(用于页面服务的无服务器Cli文件)

service: scrap-page-service

provider:
  name: aws
  runtime: python2.7
  apiGateway:
    restApiId: 
      "Fn::ImportValue": throw-stack-1-TestApiId
    restApiRootResourceId: 
      "Fn::ImportValue": throw-stack-1-ApiPageResourceVar

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: ""
          method: get

serverless.yml(用于场景服务的无服务器Cli文件)

service: scrap-scene-service

provider:
  name: aws
  runtime: python2.7
  apiGateway:
    restApiId: 
      "Fn::ImportValue": throw-stack-1-TestApiId
    restApiRootResourceId: 
      "Fn::ImportValue": throw-stack-1-ApiSceneResourceVar

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: ""
          method: get

希望这可以帮助其他人解决此问题,如果有人有更好的解决方法,我很想知道:-)

答案 1 :(得分:-1)

看看Serverless documentation on sharing API Gateway吗?

看来您必须创建的通用资源路径组件是CloudFormed对象