Search code examples
amazon-web-servicesaws-api-gatewayserverless-framework

How should we configure apigateway--> step function proxy in AWS serverless framework?


We are using serverless framewotk (AWS) to create :

This is the current code which uses the serverless-step-functions plugin :

stepFunctions:
  stateMachines:
    fetchAndCombineDataStateMachine:
      type: EXPRESS
      role: ...  
      events:
        - http:
            path: /
            method: POST 
            action: StartSyncExecution 
            request:
              template:
                application/json: |
                  #set( $body = $util.escapeJavaScript($input.json('$')) )
                  #set( $stepFunctionName = '*************************-${opt:stage}') 
                  {
                    "input": "$body", 
                    "stateMachineArn":"*************************:stateMachine:$stepFunctionName"
                  }

However , in our CICD pipeline , we can't use this plugin. So we have to configure (apigateway--> step function proxy) it without plugin.

Question:

How should we configure the YML file in order to allow Apigateway connecting to a step-function without using the plugin ?


Solution

  • To Configure AWS API Gateway integration to step function you have to follow these steps:

    1. Configure Api gateway resource
        StepFunctionApiProxy:
          Type: AWS::ApiGateway::RestApi
          Properties:
            Name: YourApiName
            EndpointConfiguration:
              Types:
                - REGIONAL
            Policy:
              Version: '2012-10-17'
              Statement:
              - Effect: Deny
                Principal: "*"
                Action:
                - execute-api:Invoke
                Resource: execute-api:/*/*/*
                Condition:
                  NotIpAddress:
                    aws:sourceIp:
                    - Whitelisted Ip address
                    - Whitelisted Ip address
              - Effect: Allow
                Principal: "*"
                Action:
                - execute-api:Invoke
                Resource: execute-api:/*/*/*   
    
    1. Configure deployment resource (it will append stage to your API deployment)
        ApiGatewayDeployment:
          Type: AWS::ApiGateway::Deployment
          Properties:
            RestApiId:
              Ref: StepFunctionApiProxy
            StageName: Int
          DependsOn:
          - ApiGatewayMethodPost 
    
    1. Configure Api Method (requests, responses and transformation templates)
        ApiGatewayMethodPost:
          Type: AWS::ApiGateway::Method
          Properties:
            HttpMethod: POST 
            AuthorizationType: NONE
            ApiKeyRequired: false
            ResourceId:
              Fn::GetAtt:
              - StepFunctionApiProxy
              - RootResourceId
            RestApiId:
              Ref: StepFunctionApiProxy
            Integration:
              IntegrationHttpMethod: POST 
              Type: AWS
              Credentials: [ApiGatewayRole, should have permission to run step function]
              Uri:
                Fn::Join:
                - ''
                - - 'arn:'
                  - Ref: AWS::Partition
                  - ":apigateway:"
                  - Ref: AWS::Region
                  - ":states:action/StartSyncExecution"  [Here you can specify action: StartSyncExecution - wait for result]                
              PassthroughBehavior: WHEN_NO_TEMPLATES 
              RequestTemplates:
                application/json: |-
                  #set( $body = $util.escapeJavaScript($input.json('$')) )
                  #set( $stepFunctionName = '[YourStepFunctionName]') 
                  {
                    "input": "$body", 
                    "stateMachineArn":"arn:aws:states:eu-west-1:[YourAmazonAccountId]:stateMachine:[stepFunctionName]"
                  } 
                application/x-www-form-urlencoded: |-
                  #set( $body = $util.escapeJavaScript($input.json('$')) )
                  #set( $stepFunctionName = '[YourStepFunctionName]') 
                  {
                    "input": "$body", 
                    "stateMachineArn":"arn:aws:states:eu-west-1:YourAmazonAccountId:stateMachine:[stepFunctionName]"
                  }
              IntegrationResponses:
              - StatusCode: 200
                SelectionPattern: 200
                ResponseParameters: {}
                ResponseTemplates:
                  application/json: |
                    #set($inputJSON = $input.json('$'))
                    #set($isSuccess = !$inputJSON.toString().contains("error") && !$inputJSON.toString().contains("Exception")) 
                    #set($xField = ($t.substring($pos1, $pos2)))   
                    {
                      "payload": { 
                          "services": $util.parseJson($inputJSON).output 
                      },      
                      "requestId": "$util.parseJson($util.parseJson($inputJSON).input).requestId",
                      "isSuccess":$isSuccess,
                      "xField":"$xField" 
                      #if($inputJSON.toString().contains("error") || $inputJSON.toString().contains("Exception"))
                      ,"error": {
                          "message": "$util.parseJson($inputJSON).error"
                      }
                      #end 
                    }
              - StatusCode: 400
                SelectionPattern: 400
                ResponseParameters: {}
                ResponseTemplates: {}
            MethodResponses:
            - ResponseParameters: {}
              ResponseModels: {}
              StatusCode: 200
            - ResponseParameters: {}
              ResponseModels: {}
              StatusCode: 400     
    
    1. Configure step function
        fetchAndCombineMapDataStateMachine:
          Type: AWS::StepFunctions::StateMachine  
          .....
          .....
          .....