Sergii S.
Sergii S.

Reputation: 449

AWS CloudFormation. Calling synchronously Step Function from API Gateway v1

I am trying to synchronously execute AWS Step Function via API Gateway. The problem is that with API Gateway V1 I have to use OpenAPI syntax (i.e. swagger) in order to specify integrationSubtype parameter, but something just doesn't work. Here is CloudFormation template I am using:

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Parameters": {
        "restApiName": {
            "Type": "String",
            "Default": "stepApi"
        }
    },
    "Resources": {
        "MyStepFunction": {
            "Type": "AWS::StepFunctions::StateMachine",
            "Properties": {
                "StateMachineName": "HelloWorld-StateMachine",
                "StateMachineType": "EXPRESS",
                "DefinitionString": "{\"Comment\": \"A Hello World example of the Amazon States Language using Pass states\", \"StartAt\": \"Hello\", \"States\": {\"Hello\": { \"Type\": \"Pass\", \"Result\": \"Hello\", \"Next\": \"World\" }, \"World\": { \"Type\": \"Pass\", \"Result\": \"World\", \"End\": true } } }",
                "RoleArn": {
                    "Fn::GetAtt": [
                        "StepFunctionRole",
                        "Arn"
                    ]
                }
            }
        },
        "StepFuncGateway": {
            "Type": "AWS::ApiGateway::RestApi",
            "Properties": {
                "Name": {
                    "Ref": "restApiName"
                },
                "Body": {
                    "openapi": "3.0.1",
                    "info": {
                        "title": "processFormExample",
                        "version": "2020-11-06 15:32:29UTC"
                    },
                    "paths": {
                        "/step": {
                            "post": { 
                                "responses": {
                                    "200": {
                                      "description": "Pet updated.",
                                      "content": {
                                        "application/json": {},
                                        "application/xml": {}
                                      }
                                    },
                                    "405": {
                                        "description": "Method Not Allowed",
                                        "content": {
                                            "application/json": {},
                                            "application/xml": {}
                                        }
                                    }
                                },
                                "parameters": [
                                ],
                                "x-amazon-apigateway-integration": {
                                    "integrationSubtype": "StepFunctions-StartSyncExecution",
                                    "credentials": {
                                        "Fn::GetAtt": [
                                            "APIGatewayRole", 
                                            "Arn"
                                        ]
                                    },
                                    "RequestTemplates": {
                                        "application/json": {
                                            "Fn::Join": [
                                                "",
                                                [
                                                    "#set( $body = $util.escapeJavaScript($input.json('$')) ) \n\n{\"input\": \"$body\",\"name\": \"$context.requestId\",\"stateMachineArn\":\"",
                                                    {
                                                        "Ref": "MyStepFunction"
                                                    },
                                                    "\"}"
                                                ]
                                            ]
                                        }
                                    },
                                    "httpMethod": "POST",
                                    "payloadFormatVersion": "1.0",
                                    "passthroughBehavior": "NEVER",
                                    "type": "AWS_PROXY",
                                    "connectionType": "INTERNET"
                                }
                            }
                        }
                    },
                    "x-amazon-apigateway-cors": {
                        "allowMethods": [
                            "*"
                        ],
                        "maxAge": 0,
                        "allowCredentials": false,
                        "allowOrigins": [
                            "*"
                        ]
                    }
                }
            },
            "DependsOn": [
                "APIGatewayRole",
                "MyStepFunction"
            ]
        },
        "APIGatewayRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": [
                                    "apigateway.amazonaws.com"
                                ]
                            },
                            "Action": "sts:AssumeRole"
                        }
                    ]
                },
                "Path": "/",
                "ManagedPolicyArns": [
                    "arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs",
                    "arn:aws:iam::aws:policy/AWSStepFunctionsFullAccess"
                ]
            }
        },
        "StepFunctionRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Sid": "",
                            "Effect": "Allow",
                            "Principal": {
                                "Service": "states.amazonaws.com"
                            },
                            "Action": "sts:AssumeRole"
                        }
                    ]
                },
                "Path": "/",
                "ManagedPolicyArns": [
                    "arn:aws:iam::aws:policy/service-role/AWSLambdaRole"
                ]
            }
        }
    },
    "Outputs": {
        "HelloWorldApi": {
            "Description": "Sync WF API endpoint",
            "Value": {
                "Fn::Sub": "https://${StepFuncGateway}.execute-api.${AWS::Region}.amazonaws.com/step"
            }
        }
    }
}

The error I am seeing is following:

Errors found during import: Unable to put integration on 'POST' for resource at path '/step': Invalid integration URI specified (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: 0c74acf9-147f-4561-9f4f-e457096c5533; Proxy: null)

I am out of ideas. Please help me to fix it.

UPDATE:

I had to add following code into x-amazon-apigateway-integration section and change type to AWS:

"uri": {
    "Fn::Join": [
        "",
        [
            "arn:aws:apigateway:",
            {
                "Ref": "AWS::Region"
            },
            ":states:action/StartSyncExecution"
        ]
    ]
},

Another thing I had to fix is RequestTemplates, it should start with lower case r. After mentioned change the stack was deployed correctly, but now I have throttling problem to solve.

Upvotes: 0

Views: 930

Answers (1)

Software2
Software2

Reputation: 2748

x-amazon-apigateway-integration is missing the uri property.

From the Amazon Developer Guide, the URI property is defined as:

The endpoint URI of the backend. For integrations of the aws type, this is an ARN value. For the HTTP integration, this is the URL of the HTTP endpoint including the https or http scheme.

For example:

"x-amazon-apigateway-integration": {
    "type": "AWS_PROXY",
    "httpMethod": "POST",
    "uri": "http://petstore.execute-api.us-west-1.amazonaws.com/petstore/pets",
    "payloadFormatVersion": 1.0,
    "otherPropterties": "go here"
}

Amazon has additional information on URI definitions here. (Copied for convienience)

For HTTP or HTTP_PROXY integrations, the URI must be a fully formed, encoded HTTP(S) URL according to the RFC-3986 specification, for either standard integration, where connectionType is not VPC_LINK, or private integration, where connectionType is VPC_LINK. For a private HTTP integration, the URI is not used for routing.

For AWS or AWS_PROXY integrations, the URI is of the form arn:aws:apigateway:{region}:{subdomain.service|service}:path|action/{service_api}. Here, {Region} is the API Gateway region (e.g., us-east-1); {service} is the name of the integrated AWS service (e.g., s3); and {subdomain} is a designated subdomain supported by certain AWS service for fast host-name lookup. action can be used for an AWS service action-based API, using an Action={name}&{p1}={v1}&p2={v2}... query string. The ensuing {service_api} refers to a supported action {name} plus any required input parameters. Alternatively, path can be used for an AWS service path-based API. The ensuing service_api refers to the path to an AWS service resource, including the region of the integrated AWS service, if applicable. For example, for integration with the S3 API of GetObject, the uri can be either arn:aws:apigateway:us-west-2:s3:action/GetObject&Bucket={bucket}&Key={key} or arn:aws:apigateway:us-west-2:s3:path/{bucket}/{key}

Upvotes: 1

Related Questions