11
votes

I want to split my SAM application into multiple parts.

I want to create a API ( AWS::Serverless::Api ) in the root stack.

I am creating lambda functions in my child stacks, where I want to give the reference of the API from the root stack to the API Events.

Is this feasible? I didn't find any good examples for the accessing the API from the root stack into child stack?

I tried with the below template -

parenttemplateapi:
    Type: AWS::Serverless::Application
    Properties:
      Location:
        ApplicationId: arn:aws:serverlessrepo:us-east-1:account_id:applications/parent-template
        SemanticVersion: 1.0.0



HelloWorldFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python2.7
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Method: get
            Path: /hello
            RestApiId: !GetAtt parenttemplateapi.Outputs.ServerlessGW-restApiId

When I tried to deploy this template, I got below errors -

Error: Failed to create changeset for the stack: child-template, ex: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED. Reason: Transform AWS::Serverless-2016-10-31 failed with: Internal transform failure.

Any pointers/suggestions?

I was referring to below links -

https://aws.amazon.com/blogs/compute/announcing-nested-applications-for-aws-sam-and-the-aws-serverless-application-repository/

Can the API Gateway Id ( AWS::ApiGateway::RestApi) from the root stack used here?

https://dev.to/grahamcox82/building-a-larger-serverless-application-part-3-modular-monorepos-3mon

Can this be achieved using serverless framework?

1
Did you find a solution in another place?Dante Faña Badia
This should be possible. However, I would like to know how the parent template looks like and if it contains an output which is named ServerlessGW-restApiId.Martin Löper
@MartinLöper I wonder if you and I worked together on a Visa Token Service Wallet Application once! :) If so, nice bumping into you out here in the Digital Wild West!lopezdp
@lopezdp Not that I remember. But nice to meet you anyway here in the Digital Wild West :DMartin Löper
Did you find a solution? by using SAM, not serverless framework?Green Y.

1 Answers

3
votes

The caveat here is that I do not use AWS SAM as I only use serverless.yml ServerlessFramework files to declare my resources to deploy.

In my ROOT API, I declare a series of outputs that my child lambdas depend on so that all my endpoints can have the same Rest API ID. This output declaration is nested under my resources declaration in my serverless.yml file as such:

resources:

  Resources:
    ...
    stuff here that you may need
    ...

  # API Gateway Cross Stack Reference Exports!!!!!
  # Outputs that other services will depend on!!!
  Outputs:
    ApiGatewayRestApiId:
      Value:
        Ref: ApiGatewayRestApi
      Export:
        Name: ${self:custom.stage}-ApiGatewayRestApiId

    ApiGatewayRestApiRootResourceId:
      Value:
        Fn::GetAtt:
          - ApiGatewayRestApi
          - RootResourceId
      Export:
        Name: ${self:custom.stage}-ApiGatewayRestApiRootResourceId

Once you have this implemented you then need to import the reference to this parent API resource in your child lambdas within the provider section of your serverless.yml file.



  # Cross-Stack Reference for sharing of API Gateway URI
  # created with accounting-api
  apiGateway:
    restApiId: ${cf:ROOT_API_NAME_HERE-dev.ApiGatewayRestApiId}
    #"Fn::ImportValue": ${self:custom.stage}-ApiGatewayRestApiId
    restApiRootResourceId:
      ${cf:ROOT_API_NAME_HERE-dev.ApiGatewayRestApiRootResourceId}
      #"Fn::ImportValue": ${self:custom.stage}-ApiGatewayRestApiRootResourceId

You must pay attention to the restApiId that you need to import from the CloudFormation stack from your parent API. You can review the outputs by going into the CloudFormation stack in your Parent API; click on Outputs and find your restApiId values as needed.

There is also another way that allows you to import the values using Fn::ImportValue which you can review with the example shown here:

https://github.com/serverless/examples/blob/master/aws-node-shared-gateway/users/serverless.yml

I have this method commented out in the code Ive pasted for you above for your reference.