如何使用 API Gateway POST 请求调用 AWS Step Function,并将请求的 JSON 有效负载发送到 Step Function?
2 回答
1. 创建你的阶梯函数
很明显。我想如果你正在阅读这篇文章,你就会知道如何去做。
否则,您可以在此处查看文档:什么是 AWS Step Functions?.
2. 为您的 API 创建 IAM 角色
它可以用于所有 Step Functions,也可以仅用于这一个。我们将只介绍第一种情况,如 Amazon 教程中所述:使用 API Gateway 创建 API。
创建 IAM 角色
登录 AWS Identity and Access Management 控制台。
在角色页面上,选择创建新角色。
在 Set Role Name 页面上,键入 APIGatewayToStepFunctions 作为 Role Name,然后选择 Next Step。
在选择角色类型页面的选择角色类型下,选择 Amazon API Gateway。
在附加策略页面上,选择下一步。
在 Review 页面上,记下 Role ARN,例如:
arn:aws:iam::123456789012:role/APIGatewayToStepFunctions
- 选择创建角色。
将策略附加到 IAM 角色
- 在角色页面上,按名称搜索您的角色 (APIGatewayToStepFunctions),然后选择角色。
- 在权限选项卡上,选择附加策略。
- 在附加策略页面上,搜索 AWSStepFunctionsFullAccess,选择策略,然后选择附加策略。
3. 设置
3.a 如果您没有 JSON 有效负载
正如 Ka Hou Ieong 在我如何通过 API Gateway 调用 AWS Step Functions 中所解释的那样?,您可以通过 API Gateway 控制台创建 AWS 服务集成,如下所示:
- 集成类型:AWS 服务
- AWS 服务:Step Functions
- HTTP 方法:POST
- 动作类型:使用动作名称
- 行动:开始执行
- 执行角色:开始执行的角色(我们刚刚创建的角色。只需粘贴它的ARN)
标题:
X-Amz-Target -> 'AWSStepFunctions.StartExecution'
内容类型 -> 'application/x-amz-json-1.0'正文映射模板/请求有效负载:
{ "input": "string" (optional), "name": "string" (optional), "stateMachineArn": "string" }
3.b 如果您确实有 JSON 有效负载作为输入传递
一切都与 2.a 中的相同,除了身体映射模板。你要做的就是把它变成一个字符串。使用 $util.escapeJavascript(),例如这样。它将您的整个请求的正文作为输入传递给您的 Step Function
#set($data = $util.escapeJavaScript($input.json('$')))
{
"input": "$data",
"name": "string" (optional),
"stateMachineArn": "string" (required)
}
笔记
stateMachineArn
:如果您不想将 stateMachineArn 作为请求的一部分传递给 API Gateway,您可以简单地将其硬编码在您的 Body Mapping Template 中(请参阅AWS API Gateway with Step Function)name
:省略 name 属性将使 API Gateway 在每次执行时为您生成一个不同的属性。
现在,这是我的第一个“回答你自己的问题”,所以也许不是这样,但我确实花了好几个小时试图了解我的映射模板出了什么问题。希望这将有助于节省其他人的头发和时间。
对于那些正在寻找使用 OpenApi 集成和 CloudFormation 将ApiGateway与Step Functions 状态机直接连接的方法的人,这是我如何设法使其工作的示例:
这是我设计的可视化工作流程(CloudFormation 文件中的更多详细信息)作为概念证明:
模板.yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: 'AWS::Serverless-2016-10-31'
Description: POC Lambda Examples - Step Functions
Parameters:
CorsOrigin:
Description: Header Access-Control-Allow-Origin
Default: "'http://localhost:3000'"
Type: String
CorsMethods:
Description: Header Access-Control-Allow-Headers
Default: "'*'"
Type: String
CorsHeaders:
Description: Header Access-Control-Allow-Headers
Default: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
Type: String
SwaggerS3File:
Description: 'S3 "swagger.yaml" file location'
Default: "./swagger.yaml"
Type: String
Resources:
LambdaRoleForRuleExecution:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${AWS::StackName}-lambda-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: 'sts:AssumeRole'
Principal:
Service: lambda.amazonaws.com
Policies:
- PolicyName: WriteCloudWatchLogs
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: 'arn:aws:logs:*:*:*'
ApiGatewayStepFunctionsRole:
Type: AWS::IAM::Role
Properties:
Path: !Join ["", ["/", !Ref "AWS::StackName", "/"]]
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Sid: AllowApiGatewayServiceToAssumeRole
Effect: Allow
Action:
- 'sts:AssumeRole'
Principal:
Service:
- apigateway.amazonaws.com
Policies:
- PolicyName: CallStepFunctions
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'states:StartExecution'
Resource:
- !Ref Workflow
Start:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub ${AWS::StackName}-start
Code: ../dist/src/step-functions
Handler: step-functions.start
Role: !GetAtt LambdaRoleForRuleExecution.Arn
Runtime: nodejs8.10
Timeout: 1
Wait3000:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub ${AWS::StackName}-wait3000
Code: ../dist/src/step-functions
Handler: step-functions.wait3000
Role: !GetAtt LambdaRoleForRuleExecution.Arn
Runtime: nodejs8.10
Timeout: 4
Wait500:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub ${AWS::StackName}-wait500
Code: ../dist/src/step-functions
Handler: step-functions.wait500
Role: !GetAtt LambdaRoleForRuleExecution.Arn
Runtime: nodejs8.10
Timeout: 2
End:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub ${AWS::StackName}-end
Code: ../dist/src/step-functions
Handler: step-functions.end
Role: !GetAtt LambdaRoleForRuleExecution.Arn
Runtime: nodejs8.10
Timeout: 1
StateExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- !Sub states.${AWS::Region}.amazonaws.com
Action:
- 'sts:AssumeRole'
Policies:
- PolicyName: "StatesExecutionPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action: "lambda:InvokeFunction"
Resource:
- !GetAtt Start.Arn
- !GetAtt Wait3000.Arn
- !GetAtt Wait500.Arn
- !GetAtt End.Arn
Workflow:
Type: AWS::StepFunctions::StateMachine
Properties:
StateMachineName: !Sub ${AWS::StackName}-state-machine
RoleArn: !GetAtt StateExecutionRole.Arn
DefinitionString: !Sub |
{
"Comment": "AWS Step Functions Example",
"StartAt": "Start",
"Version": "1.0",
"States": {
"Start": {
"Type": "Task",
"Resource": "${Start.Arn}",
"Next": "Parallel State"
},
"Parallel State": {
"Type": "Parallel",
"Next": "End",
"Branches": [
{
"StartAt": "Wait3000",
"States": {
"Wait3000": {
"Type": "Task",
"Resource": "${Wait3000.Arn}",
"End": true
}
}
},
{
"StartAt": "Wait500",
"States": {
"Wait500": {
"Type": "Task",
"Resource": "${Wait500.Arn}",
"End": true
}
}
}
]
},
"End": {
"Type": "Task",
"Resource": "${End.Arn}",
"End": true
}
}
}
RestApi:
Type: AWS::Serverless::Api
Properties:
StageName: !Ref Environment
Name: !Sub ${AWS::StackName}-api
DefinitionBody:
'Fn::Transform':
Name: AWS::Include
Parameters:
# s3 location of the swagger file
Location: !Ref SwaggerS3File
招摇的.yaml
openapi: 3.0.0
info:
version: '1.0'
title: "pit-jv-lambda-examples"
description: POC API
license:
name: MIT
x-amazon-apigateway-request-validators:
Validate body:
validateRequestParameters: false
validateRequestBody: true
params:
validateRequestParameters: true
validateRequestBody: false
Validate body, query string parameters, and headers:
validateRequestParameters: true
validateRequestBody: true
paths:
/execute:
options:
x-amazon-apigateway-integration:
type: mock
requestTemplates:
application/json: |
{
"statusCode" : 200
}
responses:
"default":
statusCode: "200"
responseParameters:
method.response.header.Access-Control-Allow-Headers:
Fn::Sub: ${CorsHeaders}
method.response.header.Access-Control-Allow-Methods:
Fn::Sub: ${CorsMethods}
method.response.header.Access-Control-Allow-Origin:
Fn::Sub: ${CorsOrigin}
responseTemplates:
application/json: |
{}
responses:
200:
$ref: '#/components/responses/200Cors'
post:
x-amazon-apigateway-integration:
credentials:
Fn::GetAtt: [ ApiGatewayStepFunctionsRole, Arn ]
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:states:action/StartExecution
httpMethod: POST
type: aws
responses:
default:
statusCode: 200
responseParameters:
method.response.header.Access-Control-Allow-Headers:
Fn::Sub: ${CorsHeaders}
method.response.header.Access-Control-Allow-Origin:
Fn::Sub: ${CorsOrigin}
".*CREATION_FAILED.*":
statusCode: 403
responseParameters:
method.response.header.Access-Control-Allow-Headers:
Fn::Sub: ${CorsHeaders}
method.response.header.Access-Control-Allow-Origin:
Fn::Sub: ${CorsOrigin}
responseTemplates:
application/json: $input.path('$.errorMessage')
requestTemplates:
application/json:
Fn::Sub: |-
{
"input": "$util.escapeJavaScript($input.json('$'))",
"name": "$context.requestId",
"stateMachineArn": "${Workflow}"
}
summary: Start workflow
responses:
200:
$ref: '#/components/responses/200Empty'
403:
$ref: '#/components/responses/Error'
components:
schemas:
Error:
title: Error
type: object
properties:
code:
type: string
message:
type: string
responses:
200Empty:
description: Default OK response
200Cors:
description: Default response for CORS method
headers:
Access-Control-Allow-Headers:
schema:
type: "string"
Access-Control-Allow-Methods:
schema:
type: "string"
Access-Control-Allow-Origin:
schema:
type: "string"
Error:
description: Error Response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
headers:
Access-Control-Allow-Headers:
schema:
type: "string"
Access-Control-Allow-Origin:
schema:
type: "string"
step-functions.js
exports.start = (event, context, callback) => {
console.log('start event', event);
console.log('start context', context);
callback(undefined, { function: 'start' });
};
exports.wait3000 = (event, context, callback) => {
console.log('wait3000 event', event);
console.log('wait3000 context', context);
setTimeout(() => {
callback(undefined, { function: 'wait3000' });
}, 3000);
};
exports.wait500 = (event, context, callback) => {
console.log('wait500 event', event);
console.log('wait500 context', context);
setTimeout(() => {
callback(undefined, { function: 'wait500' });
}, 500);
};
exports.end = (event, context, callback) => {
console.log('end event', event);
console.log('end context', context);
callback(undefined, { function: 'end' });
};