

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 在 Step Functions 中 AWS CDK 建立 Express 工作流程
<a name="tutorial-step-functions-rest-api-integration-cdk"></a>

在本教學課程中，您將了解如何使用 AWS Cloud Development Kit (AWS CDK) Infrastructure as Code (IAC) 架構，使用同步快速狀態機器建立 API Gateway REST API 做為後端整合。

您將使用 `StepFunctionsRestApi` 建構來將狀態機器連線至 API Gateway。`StepFunctionsRestApi` 建構將設定預設輸入/輸出映射和 API Gateway REST API，具有必要的許可和 HTTP "ANY" 方法。

 使用 AWS CDK 是基礎設施即程式碼 (IAC) 架構，您可以使用程式設計語言定義 AWS 基礎設施。您可以使用其中一種 CDK 支援的語言定義應用程式，將程式碼合成至 CloudFormation 範本，然後將基礎設施部署至 AWS 您的帳戶。

 您將使用 CloudFormation 定義 API Gateway REST API，該 API 與 Synchronous Express State Machine 整合為後端，然後使用 AWS 管理主控台 啟動執行。

開始本教學課程之前，請依照 [AWS CDK - 先決條件入門](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html#getting_started_prerequisites)所述來設定您的 AWS CDK 開發環境，然後 AWS CDK 透過發出以下命令來安裝 ：

```
npm install -g aws-cdk
```

## 步驟 1：設定您的 AWS CDK 專案
<a name="step-functions-rest-api-integration-cdk-step-1"></a>

首先，為您的新 AWS CDK 應用程式建立目錄並初始化專案。

------
#### [ TypeScript ]

```
mkdir stepfunctions-rest-api
cd stepfunctions-rest-api
cdk init --language typescript
```

------
#### [ JavaScript ]

```
mkdir stepfunctions-rest-api
cd stepfunctions-rest-api
cdk init --language javascript
```

------
#### [ Python ]

```
mkdir stepfunctions-rest-api
cd stepfunctions-rest-api
cdk init --language python
```

初始化專案之後，請啟用專案的虛擬環境，並安裝 AWS CDK的基準相依性。

```
source .venv/bin/activate
python -m pip install -r requirements.txt
```

------
#### [ Java ]

```
mkdir stepfunctions-rest-api
cd stepfunctions-rest-api
cdk init --language java
```

------
#### [ C\$1 ]

```
mkdir stepfunctions-rest-api
cd stepfunctions-rest-api
cdk init --language csharp
```

------
#### [ Go ]

```
mkdir stepfunctions-rest-api
cd stepfunctions-rest-api
cdk init --language go
```

------

**注意**  
請務必將目錄命名為 `stepfunctions-rest-api`。 AWS CDK 應用程式範本使用 目錄的名稱來產生來源檔案和類別的名稱。若使用不同名稱，您的應用程式將與本教學課程不相符。

現在安裝適用於 AWS Step Functions 和 Amazon API Gateway 的建構程式庫模組。

------
#### [ TypeScript ]

```
npm install @aws-cdk/aws-stepfunctions @aws-cdk/aws-apigateway
```

------
#### [ JavaScript ]

```
npm install @aws-cdk/aws-stepfunctions @aws-cdk/aws-apigateway
```

------
#### [ Python ]

```
python -m pip install aws-cdk.aws-stepfunctions
python -m pip install aws-cdk.aws-apigateway
```

------
#### [ Java ]

編輯專案的 `pom.xml`，在現有的 `<dependencies>` 容器內新增下列相依性。

```
        <dependency>
            <groupId>software.amazon.awscdk</groupId>
            <artifactId>stepfunctions</artifactId>
            <version>${cdk.version}</version>
        </dependency>
        <dependency>
            <groupId>software.amazon.awscdk</groupId>
            <artifactId>apigateway</artifactId>
            <version>${cdk.version}</version>
        </dependency>
```

Maven 會在您下次建立應用程式時自動安裝這些相依性。若要建置，發行 `mvn compile` 或使用您的 Java IDE 的 **Build** 命令。

------
#### [ C\$1 ]

```
dotnet add src/StepfunctionsRestApi package Amazon.CDK.AWS.Stepfunctions
dotnet add src/StepfunctionsRestApi package Amazon.CDK.AWS.APIGateway
```

您也可以使用 Visual Studio NuGet GUI 安裝指定的套件，可透過 **Tools** (工具) > **NuGet Package Manager** (NuGet 套件管理員) > **Manage NuGet Packages for Solution** (管理解決方案的 NuGet 套件) 獲取。

------

安裝模組後，您可以透過匯入下列套件，在 AWS CDK 應用程式中使用這些模組。

------
#### [ TypeScript ]

```
@aws-cdk/aws-stepfunctions
@aws-cdk/aws-apigateway
```

------
#### [ JavaScript ]

```
@aws-cdk/aws-stepfunctions
@aws-cdk/aws-apigateway
```

------
#### [ Python ]

```
aws_cdk.aws_stepfunctions
aws_cdk.aws_apigateway
```

------
#### [ Java ]

```
software.amazon.awscdk.services.apigateway.StepFunctionsRestApi
software.amazon.awscdk.services.stepfunctions.Pass
software.amazon.awscdk.services.stepfunctions.StateMachine
software.amazon.awscdk.services.stepfunctions.StateMachineType
```

------
#### [ C\$1 ]

```
Amazon.CDK.AWS.StepFunctions
Amazon.CDK.AWS.APIGateway
```

------
#### [ Go ]

將以下內容新增至 `import`內部`stepfunctions-rest-api.go`。

```
"github.com/aws/aws-cdk-go/awscdk/awsapigateway"
"github.com/aws/aws-cdk-go/awscdk/awsstepfunctions"
```

------

## 步驟 2：使用 AWS CDK 建立具有同步快速狀態機器後端整合的 API Gateway REST API
<a name="step-functions-rest-api-integration-cdk-step-2"></a>

首先，我們將提供定義同步快速狀態機器和 API Gateway REST API 的個別程式碼片段，然後說明如何將這些程式碼放在您的 AWS CDK 應用程式中。然後，您將了解如何合成和部署這些資源。

**注意**  
我們將在此處顯示的 狀態機器將是具有 `Pass` 狀態的簡單 狀態機器。

### 建立快速狀態機器
<a name="step-functions-rest-api-integration-cdk-create-state-machine"></a>

這是定義具有 `Pass` 狀態之簡單狀態機器的 AWS CDK 程式碼。

------
#### [ TypeScript ]

```
const machineDefinition = new stepfunctions.Pass(this, 'PassState', {
    result: {value:"Hello!"},
})

const stateMachine = new stepfunctions.StateMachine(this, 'MyStateMachine', {
    definition: machineDefinition,
    stateMachineType: stepfunctions.StateMachineType.EXPRESS,
});
```

------
#### [ JavaScript ]

```
const machineDefinition = new sfn.Pass(this, 'PassState', {
    result: {value:"Hello!"},
})

const stateMachine = new sfn.StateMachine(this, 'MyStateMachine', {
    definition: machineDefinition,
    stateMachineType: stepfunctions.StateMachineType.EXPRESS,
});
```

------
#### [ Python ]

```
machine_definition = sfn.Pass(self,"PassState", 
                        result = sfn.Result("Hello"))
    
state_machine = sfn.StateMachine(self, 'MyStateMachine', 
        definition = machine_definition, 
        state_machine_type = sfn.StateMachineType.EXPRESS)
```

------
#### [ Java ]

```
Pass machineDefinition = Pass.Builder.create(this, "PassState")
                        .result(Result.fromString("Hello"))
                        .build();

StateMachine stateMachine = StateMachine.Builder.create(this, "MyStateMachine")
                            .definition(machineDefinition)
                            .stateMachineType(StateMachineType.EXPRESS)
                            .build();
```

------
#### [ C\$1 ]

```
var machineDefinition = new Pass(this, "PassState", new PassProps
{
    Result = Result.FromString("Hello")
});

var stateMachine = new StateMachine(this, "MyStateMachine", new StateMachineProps
{
    Definition = machineDefinition,
    StateMachineType = StateMachineType.EXPRESS
});
```

------
#### [ Go ]

```
var machineDefinition = awsstepfunctions.NewPass(stack, jsii.String("PassState"), &awsstepfunctions.PassProps
{
    Result: awsstepfunctions.NewResult(jsii.String("Hello")),
})

var stateMachine = awsstepfunctions.NewStateMachine(stack, jsii.String("StateMachine"), &awsstepfunctions.StateMachineProps
{    
    Definition: machineDefinition,
    StateMachineType: awsstepfunctions.StateMachineType_EXPRESS,
})
```

------

您可以在此簡短的程式碼片段中看到：
+ 名為 的機器定義`PassState`，其為 `Pass` 狀態。
+ 狀態機器的邏輯名稱 `MyStateMachine`。
+ 機器定義會用作狀態機器定義。
+ 狀態機器類型設定為 ，`EXPRESS`因為 `StepFunctionsRestApi` 只允許同步快速狀態機器。

### 使用 `StepFunctionsRestApi` 建構建立 API Gateway REST API
<a name="step-functions-rest-api-integration-cdk-create-rest-api"></a>

我們將使用 `StepFunctionsRestApi` 建構來建立具有必要許可和預設輸入/輸出映射的 API Gateway REST API。

------
#### [ TypeScript ]

```
const api = new apigateway.StepFunctionsRestApi(this, 
  'StepFunctionsRestApi', { stateMachine: stateMachine });
```

------
#### [ JavaScript ]

```
const api = new apigateway.StepFunctionsRestApi(this, 
  'StepFunctionsRestApi', { stateMachine: stateMachine });
```

------
#### [ Python ]

```
api = apigw.StepFunctionsRestApi(self, "StepFunctionsRestApi",
                            state_machine = state_machine)
```

------
#### [ Java ]

```
StepFunctionsRestApi api = StepFunctionsRestApi.Builder.create(this, "StepFunctionsRestApi")
                           .stateMachine(stateMachine)
                           .build();
```

------
#### [ C\$1 ]

```
var api = new StepFunctionsRestApi(this, "StepFunctionsRestApi", new StepFunctionsRestApiProps
{
    StateMachine = stateMachine
});
```

------
#### [ Go ]

```
awsapigateway.NewStepFunctionsRestApi(stack, jsii.String("StepFunctionsRestApi"), &awsapigateway.StepFunctionsRestApiProps
{
    StateMachine = stateMachine,
})
```

------

### 建置和部署 AWS CDK 應用程式
<a name="step-functions-rest-api-integration-cdk-app"></a>

在您建立的 AWS CDK 專案中，編輯包含堆疊定義的檔案，使其看起來像下面的程式碼。您將從上方辨識 Step Functions 狀態機器和 API Gateway 的定義。

------
#### [ TypeScript ]

更新 ` lib/stepfunctions-rest-api-stack.ts`，讀取如下。

```
import * as cdk from 'aws-cdk-lib';
import * as stepfunctions from 'aws-cdk-lib/aws-stepfunctions' 
import * as apigateway from 'aws-cdk-lib/aws-apigateway';


export class StepfunctionsRestApiStack extends cdk.Stack {
    constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const machineDefinition = new stepfunctions.Pass(this, 'PassState', {
        result: {value:"Hello!"},
    });
    
    const stateMachine = new stepfunctions.StateMachine(this, 'MyStateMachine', {
        definition: machineDefinition,
        stateMachineType: stepfunctions.StateMachineType.EXPRESS,
    });
    
    const api = new apigateway.StepFunctionsRestApi(this, 
        'StepFunctionsRestApi', { stateMachine: stateMachine });
```

------
#### [ JavaScript ]

更新 `lib/stepfunctions-rest-api-stack.js`，讀取如下。

```
const cdk = require('@aws-cdk/core');
const stepfunctions = require('@aws-cdk/aws-stepfunctions');
const apigateway = require('@aws-cdk/aws-apigateway');


class StepfunctionsRestApiStack extends cdk.Stack {
    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const machineDefinition = new stepfunctions.Pass(this, "PassState", {
        result: {value:"Hello!"},
    })
    
    const stateMachine = new sfn.StateMachine(this, 'MyStateMachine', {
        definition: machineDefinition,
        stateMachineType: stepfunctions.StateMachineType.EXPRESS,
    });
    
    const api = new apigateway.StepFunctionsRestApi(this, 
        'StepFunctionsRestApi', { stateMachine: stateMachine });

    }
}

module.exports = { StepStack }
```

------
#### [ Python ]

更新 `stepfunctions_rest_api/stepfunctions_rest_api_stack.py`，讀取如下。

```
from aws_cdk import App, Stack
from constructs import Construct
from aws_cdk import aws_stepfunctions as sfn
from aws_cdk import aws_apigateway as apigw

class StepfunctionsRestApiStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        
        
        machine_definition = sfn.Pass(self,"PassState", 
                                result = sfn.Result("Hello"))

        state_machine = sfn.StateMachine(self, 'MyStateMachine', 
                definition = machine_definition, 
                state_machine_type = sfn.StateMachineType.EXPRESS)

        api = apigw.StepFunctionsRestApi(self, 
                    "StepFunctionsRestApi",
                    state_machine = state_machine)
```

------
#### [ Java ]

更新 `src/main/java/com.myorg/StepfunctionsRestApiStack.java`，讀取如下。

```
package com.myorg;


import software.amazon.awscdk.core.Construct;
import software.amazon.awscdk.core.Stack;
import software.amazon.awscdk.core.StackProps;
import software.amazon.awscdk.services.stepfunctions.Pass;
import software.amazon.awscdk.services.stepfunctions.StateMachine;
import software.amazon.awscdk.services.stepfunctions.StateMachineType;
import software.amazon.awscdk.services.apigateway.StepFunctionsRestApi;

public class StepfunctionsRestApiStack extends Stack {
    public StepfunctionsRestApiStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public StepfunctionsRestApiStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        Pass machineDefinition = Pass.Builder.create(this, "PassState")
                                .result(Result.fromString("Hello"))
                                .build();
        
        StateMachine stateMachine = StateMachine.Builder.create(this, "MyStateMachine")
                                    .definition(machineDefinition)
                                    .stateMachineType(StateMachineType.EXPRESS)
                                    .build();
                                    
        StepFunctionsRestApi api = StepFunctionsRestApi.Builder.create(this, "StepFunctionsRestApi")
                                   .stateMachine(stateMachine)
                                   .build();
                                   
    }
}
```

------
#### [ C\$1 ]

更新 `src/StepfunctionsRestApi/StepfunctionsRestApiStack.cs`，讀取如下。

```
using Amazon.CDK;
using Amazon.CDK.AWS.StepFunctions;
using Amazon.CDK.AWS.APIGateway;

namespace StepfunctionsRestApi
{
    public class StepfunctionsRestApiStack : Stack
    {
        internal StepfunctionsRestApi(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var machineDefinition = new Pass(this, "PassState", new PassProps
            {
                Result = Result.FromString("Hello")
            });

            var stateMachine = new StateMachine(this, "MyStateMachine", new StateMachineProps
            {
                Definition = machineDefinition,
                StateMachineType = StateMachineType.EXPRESS
            });
            
            var api = new StepFunctionsRestApi(this, "StepFunctionsRestApi", new StepFunctionsRestApiProps
            {
                StateMachine = stateMachine
            });

        }
    }
}
```

------
#### [ Go ]

更新 `stepfunctions-rest-api.go`，讀取如下。

```
package main
import (
    "github.com/aws/aws-cdk-go/awscdk"
    "github.com/aws/aws-cdk-go/awscdk/awsapigateway"
    "github.com/aws/aws-cdk-go/awscdk/awsstepfunctions"
    "github.com/aws/constructs-go/constructs/v3"
    "github.com/aws/jsii-runtime-go"
)


type StepfunctionsRestApiGoStackProps struct {
    awscdk.StackProps
}

func NewStepfunctionsRestApiGoStack(scope constructs.Construct, id string, props *StepfunctionsRestApiGoStackProps) awscdk.Stack {
    var sprops awscdk.StackProps
    if props != nil {
        sprops = props.StackProps
    }
    stack := awscdk.NewStack(scope, &id, &sprops)

    // The code that defines your stack goes here
    var machineDefinition = awsstepfunctions.NewPass(stack, jsii.String("PassState"), &awsstepfunctions.PassProps
    {
        Result: awsstepfunctions.NewResult(jsii.String("Hello")),
    })

    var stateMachine = awsstepfunctions.NewStateMachine(stack, jsii.String("StateMachine"), &awsstepfunctions.StateMachineProps{
        Definition: machineDefinition,
        StateMachineType: awsstepfunctions.StateMachineType_EXPRESS,
    });

    awsapigateway.NewStepFunctionsRestApi(stack, jsii.String("StepFunctionsRestApi"), &awsapigateway.StepFunctionsRestApiProps{
        StateMachine = stateMachine,
    })

    return stack
}

func main() {
    app := awscdk.NewApp(nil)

    NewStepfunctionsRestApiGoStack(app, "StepfunctionsRestApiGoStack", &StepfunctionsRestApiGoStackProps{
        awscdk.StackProps{
            Env: env(),
        },
    })

    app.Synth(nil)
}

// env determines the AWS environment (account+region) in which our stack is to
// be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html
func env() *awscdk.Environment {
    // If unspecified, this stack will be "environment-agnostic".
    // Account/Region-dependent features and context lookups will not work, but a
    // single synthesized template can be deployed anywhere.
    //---------------------------------------------------------------------------
    return nil

    // Uncomment if you know exactly what account and region you want to deploy
    // the stack to. This is the recommendation for production stacks.
    //---------------------------------------------------------------------------
    // return &awscdk.Environment{
    //  Account: jsii.String("account-id"),
    //  Region:  jsii.String("us-east-1"),
    // }

    // Uncomment to specialize this stack for the AWS Account and Region that are
    // implied by the current CLI configuration. This is recommended for dev
    // stacks.
    //---------------------------------------------------------------------------
    // return &awscdk.Environment{
    //  Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
    //  Region:  jsii.String(os.Getenv("CDK_DEFAULT_REGION")),
    // }
}
```

------

保存來源檔案，然後在應用程式的主目錄中發行 `cdk synth`。會 AWS CDK 執行應用程式並從中合成 CloudFormation 範本，然後顯示範本。

若要將 Amazon API Gateway 和 AWS Step Functions 狀態機器實際部署到您的 AWS 帳戶，請發出 `cdk deploy`。系統會要求您核准 AWS CDK 產生的 IAM 政策。

## 步驟 3：測試 API Gateway
<a name="step-functions-rest-api-integration-cdk-step-3"></a>

使用同步快速狀態機器建立 API Gateway REST API 做為後端整合後，您可以測試 API Gateway。

### 使用 API Gateway 主控台測試部署的 API Gateway
<a name="to-test-the-deployed-api-gateway-using-console"></a>

1. 開啟 [Amazon API Gateway 主控台](https://console.aws.amazon.com/apigateway/)並登入。

1. 選擇名為 的 REST API`StepFunctionsRestApi`。

1. 在**資源**窗格中，選擇 `ANY`方法。

1. 選擇**測試**標籤。您可能需要選擇向右箭頭按鈕才能顯示此索引標籤。

1. 針對 **Method** (方法) 選擇 **POST**。

1. 針對**請求內文**，複製下列請求參數。

   ```
   {
       "key": "Hello"
   }
   ```

1. 選擇 **Test (測試)**。下列資訊會隨即顯示：
   + **Request (請求)** 是針對方法所呼叫的資源路徑。
   + **Status (狀態)** 是回應的 HTTP 狀態碼。
   + **Latency (延遲)** 是從發起人收到請求到傳回回應之間的時間。
   + **回應內文**是 HTTP 回應內文。
   + **回應標頭**是 HTTP 回應標頭。
   + **日誌**會顯示模擬的 Amazon CloudWatch Logs 項目，如果是在 API Gateway 主控台之外呼叫此方法，則會寫入這些項目。
**注意**  
雖然 CloudWatch Logs 項目是模擬的，但方法呼叫的結果是真實的。

**回應內文**輸出應該如下：

```
"Hello"
```

**提示**  
嘗試使用不同的方法和無效的輸入來查看錯誤輸出。您可能想要變更狀態機器以尋找特定金鑰，並在測試期間提供錯誤的金鑰，讓狀態機器執行失敗，並在**回應內文**輸出中產生錯誤訊息。

### 使用 cURL 測試已部署的 API
<a name="to-test-the-deployed-api-gateway-using-curl"></a>

1. 開啟終端機視窗。

1. 複製以下 cURL 命令，並將它貼到終端機視窗，同時將 `<api-id>` 取代為您 API 的 API ID，以及將 `<region>` 取代為 API 的部署區域。

   ```
   curl -X POST\
    'https://<api-id>.execute-api.<region>.amazonaws.com/prod' \
    -d '{"key":"Hello"}' \
    -H 'Content-Type: application/json'
   ```

**回應內文**輸出應該如下所示：

```
"Hello"
```

**提示**  
嘗試使用不同的方法和無效的輸入來查看錯誤輸出。您可能想要變更狀態機器以尋找特定金鑰，並在測試期間提供錯誤的金鑰，讓狀態機器執行失敗，並在**回應內文**輸出中產生錯誤訊息。

## 步驟 4：清除
<a name="step-functions-rest-api-integration-cdk-step-4"></a>

完成嘗試 API Gateway 後，您可以使用 AWS CDK 來銷毀狀態機器和 API Gateway。在您的應用程式的主目錄中發行 `cdk destroy`。