0
votes

I'm trying to come up with a CloudFormation template that includes

  • API Gateway
  • Invokes a StateMachine through the API Gateway
  • StateMachine in turn contains a lambda function

In essence what I'm try to do is the following

https://docs.aws.amazon.com/step-functions/latest/dg/tutorial-api-gateway.html

However I'm stuck in coming up with the Cloud Formation Template (.yaml) that will deploy this. So far this is what I have

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  Post:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: UserBase-fnUsers
      Handler: UsersHandler.getUsers
      Runtime: nodejs6.10
      Policies: [AmazonDynamoDBReadOnlyAccess, AmazonS3ReadOnlyAccess]
      Environment:
        Variables: 
          S3_BUCKET: UserBase-Users-bucket
          UsersTable: UserBase-Users-tblUsers
      Events:
        GetUsers:
          Type: Api
          Properties:
            Path: /UserBase/Users
            Method: post      
  Options:
    Type: AWS::Serverless::Function
    Properties:                     
      FunctionName: UserBase-fnUsers-Options
      Handler: UsersHandler.getOptions
      Runtime: nodejs6.10
      Events:
        GetOptions:
          Type: Api
          Properties:
            Path: /UserBase/Users
            Method: options                           
  UsersTable:
    Type: AWS::DynamoDB::Table
    Properties: 
      TableName: UserBase-Users-tblUsers
      AttributeDefinitions: 
        - AttributeName: Id
          AttributeType: S   
      KeySchema: 
        - AttributeName: Id
          KeyType: HASH   
      ProvisionedThroughput: 
        ReadCapacityUnits: 5
        WriteCapacityUnits: 5       
      StreamSpecification:
        StreamViewType: KEYS_ONLY                
  StatesExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - !Sub states.${AWS::Region}.amazonaws.com
            Action: "sts:AssumeRole"
      Path: "/"
      Policies:
        - PolicyName: StatesExecutionPolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "lambda:InvokeFunction"
                Resource: "*"

  UpdateShoppingPath:
    Type: "AWS::StepFunctions::StateMachine"
    Properties:
      DefinitionString:
        !Sub
          - |-
            {
              "Comment": "State machine to update the shopping path",
              "StartAt": "UpdatePath",
              "States": {
                "UpdatePath": {
                  "Type": "Task",
                  "Resource": "${lambdaArn}",
                  "End": true
                }
              }
            }
          - {lambdaArn: !GetAtt [ Post, Arn ]}
      RoleArn: !GetAtt [ StatesExecutionRole, Arn ]
  UserBaseUsers:
     Type: "AWS::ApiGateway::Resource"

I'm stuck with the last piece, basically on how to link the ApiGateway to the StateMachine. On a side note is there any way for me to generate the cloud formation template (.yaml or json) from an existing deployment in AWS?

1
site note - check out AWS Cloudformer: docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/…Taterhead
I saw this, but its still in Beta, plus when I try to access the vpc instance created as part of this, its asking for a certificate.tmp dev
Your goal in using cloudformer is not to access the vpc or the cloudformer ec2 instance. Cloud former builds a cloudformation template for you in step 3 = #10 of that guide. You end up deleting the cloudformer stack in step 4.Taterhead

1 Answers

1
votes

I'm not an expert with yaml, but I did some configuration with json CloudFormation and as far as I have read it's quite easy to translate.

In the past I've been stuck like you, and here's my post and my solution

What you need to do to start the execution of a Step Functions is to do a HTTP Post to arn:aws:apigateway:${region}:states:action/StartExecution passing as json object [docs]:

{
input: __input__,
stateMachineArn: __arn__
}

In short, in your AWS::ApiGateway::Method, you have to set an HTTP integration to arn:aws:apigateway:${region}:states:action/StartExecution and a requestTemplate that builds the json object I mentioned.

For reference, here my json cloudformation example:

"FooRequest": {
    "DependsOn": ["FooStepMachine"],
    "Type": "AWS::ApiGateway::Method",
    "Properties": {
        "HttpMethod": "POST",
        "Integration": {
            "Type": "AWS",
            "Credentials": {
                "Fn::GetAtt": ["FooRole",
                "Arn"]
            },
            "IntegrationHttpMethod": "POST",
            "Uri": {
                "Fn::Join": ["",
                ["arn:aws:apigateway:",
                {
                    "Ref": "AWS::Region"
                },
                ":states:action/StartExecution"]]
            },
            "IntegrationResponses": [{
                "StatusCode": 200
            },
            {
                "StatusCode": 401
            }],
            "RequestTemplates": {
                "application/json": {
                    "Fn::Sub": ["{\"input\": \"$util.escapeJavaScript($input.json('$'))\",\"stateMachineArn\": \"${arn}\"}",
                    {
                        "arn": {
                            "Ref": "FooStepMachine"
                        }
                    }]
                }
            }
        }
    }
}