

這是 AWS CDK v2 開發人員指南。較舊的 CDK v1 已於 2022 年 6 月 1 日進入維護，並於 2023 年 6 月 1 日結束支援。

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

# 教學課程：建立無伺服器 Hello World 應用程式
<a name="serverless-example"></a>

在本教學課程中，您會使用 AWS 雲端開發套件 (AWS CDK) 建立簡單的無伺服器`Hello World`應用程式，實作基本 API 後端，其中包含下列項目：
+  **Amazon API Gateway REST API** – 提供 HTTP 端點，用於透過 HTTP GET 請求叫用函數。
+  ** AWS Lambda 函數** – 使用 HTTP 端點叫用時傳回`Hello World!`訊息的函數。
+  **整合和許可** – 資源的組態詳細資訊和許可可彼此互動並執行動作，例如將日誌寫入 Amazon CloudWatch。

下圖顯示此應用程式的組件：

![\[當您將 GET 請求傳送至 API Gateway 端點時調用的 Lambda 函數圖表。\]](http://docs.aws.amazon.com/zh_tw/cdk/v2/guide/images/serverless-example-01.png)


在本教學課程中，您將依照下列步驟建立應用程式並與其互動：

1. 建立 AWS CDK 專案。

1. 使用建構程式庫中的 L2 建構來定義 Lambda AWS 函數和 API Gateway REST API。

1. 將您的應用程式部署到 AWS 雲端。

1. 在 AWS 雲端中與您的應用程式互動。

1. 從 AWS 雲端刪除範例應用程式。

## 先決條件
<a name="serverless-example-pre"></a>

開始本教學課程之前，請完成下列動作：
+ 建立 AWS 帳戶，並安裝和設定 AWS 命令列界面 (AWS CLI)。
+ 安裝 Node.js 和 `npm`。
+ 使用 全域安裝 CDK Toolkit`npm install -g aws-cdk`。

如需詳細資訊，請參閱 [AWS CDK 入門](getting-started.md)。

我們也建議對以下內容有基本的了解：
+  [什麼是 AWS CDK？](home.md) AWS CDK 的基本簡介。
+  [了解 AWS CDK 核心概念](core-concepts.md)，以取得 AWS CDK 核心概念的概觀。

## 步驟 1：建立 CDK 專案
<a name="serverless-example-project"></a>

在此步驟中，您會使用 CDK CLI `cdk init`命令建立新的 AWS CDK 專案。

 **建立 CDK 專案**   

1. 從您選擇的開始目錄，建立並導覽至您電腦上名為 `cdk-hello-world`的專案目錄：

   ```
   $ mkdir cdk-hello-world && cd cdk-hello-world
   ```

1. 使用 `cdk init`命令，以您偏好的程式設計語言建立新的專案：  
**Example**  

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

   ```
   $ cdk init --language typescript
   ```

   安裝 AWS CDK 程式庫：

   ```
   $ npm install aws-cdk-lib constructs
   ```

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

   ```
   $ cdk init --language javascript
   ```

   安裝 AWS CDK 程式庫：

   ```
   $ npm install aws-cdk-lib constructs
   ```

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

   ```
   $ cdk init --language python
   ```

   啟用虛擬環境：

   ```
   $ source .venv/bin/activate # On Windows, run '.\venv\Scripts\activate' instead
   ```

   安裝 AWS CDK 程式庫和專案相依性：

   ```
   (.venv)$ python3 -m pip install -r requirements.txt
   ```

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

   ```
   $ cdk init --language java
   ```

   安裝 AWS CDK 程式庫和專案相依性：

   ```
   $ mvn package
   ```

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

   ```
   $ cdk init --language csharp
   ```

   安裝 AWS CDK 程式庫和專案相依性：

   ```
   $ dotnet restore src
   ```

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

   ```
   $ cdk init --language go
   ```

   安裝專案相依性：

   ```
   $ go get github.com/aws/aws-cdk-go/awscdk/v2
   $ go get github.com/aws/aws-cdk-go/awscdk/v2/awslambda
   $ go get github.com/aws/aws-cdk-go/awscdk/v2/awsapigateway
   $ go mod tidy
   ```

------

   CDK CLI 會建立具有下列結構的專案：  
**Example**  

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

   ```
   cdk-hello-world
   ├── .git
   ├── .gitignore
   ├── .npmignore
   ├── README.md
   ├── bin
   │   └── cdk-hello-world.ts
   ├── cdk.json
   ├── jest.config.js
   ├── lib
   │   └── cdk-hello-world-stack.ts
   ├── node_modules
   ├── package-lock.json
   ├── package.json
   ├── test
   │   └── cdk-hello-world.test.ts
   └── tsconfig.json
   ```

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

   ```
   cdk-hello-world
   ├── .git
   ├── .gitignore
   ├── .npmignore
   ├── README.md
   ├── bin
   │   └── cdk-hello-world.js
   ├── cdk.json
   ├── jest.config.js
   ├── lib
   │   └── cdk-hello-world-stack.js
   ├── node_modules
   ├── package-lock.json
   ├── package.json
   └── test
       └── cdk-hello-world.test.js
   ```

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

   ```
   cdk-hello-world
   ├── .git
   ├── .gitignore
   ├── .venv
   ├── README.md
   ├── app.py
   ├── cdk.json
   ├── cdk_hello_world
   │   ├── __init__.py
   │   └── cdk_hello_world_stack.py
   ├── requirements-dev.txt
   ├── requirements.txt
   ├── source.bat
   └── tests
   ```

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

   ```
   cdk-hello-world
   ├── .git
   ├── .gitignore
   ├── README.md
   ├── cdk.json
   ├── pom.xml
   ├── src
   │   ├── main
   │   │   └── java
   │   │       └── com
   │   │           └── myorg
   │   │               ├── CdkHelloWorldApp.java
   │   │               └── CdkHelloWorldStack.java
   └── target
   ```

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

   ```
   cdk-hello-world
   ├── .git
   ├── .gitignore
   ├── README.md
   ├── cdk.json
   └── src
       ├── CdkHelloWorld
       │   ├── CdkHelloWorld.csproj
       │   ├── CdkHelloWorldStack.cs
       │   ├── GlobalSuppressions.cs
       │   └── Program.cs
       └── CdkHelloWorld.sln
   ```

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

   ```
   cdk-hello-world
   ├── .git
   ├── .gitignore
   ├── README.md
   ├── cdk-hello-world.go
   ├── cdk-hello-world_test.go
   ├── cdk.json
   ├── go.mod
   └── go.sum
   ```

------

CDK CLI 會自動建立包含單一堆疊的 CDK 應用程式。CDK 應用程式執行個體是從 ` [App](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.App.html) `類別建立的。以下是 CDK 應用程式檔案的一部分：

**Example**  
位於 ： `bin/cdk-hello-world.ts`  

```
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { CdkHelloWorldStack } from '../lib/cdk-hello-world-stack';

const app = new cdk.App();
new CdkHelloWorldStack(app, 'CdkHelloWorldStack', {
});
```
位於 ： `bin/cdk-hello-world.js`  

```
#!/usr/bin/env node
const cdk = require('aws-cdk-lib');
const { CdkHelloWorldStack } = require('../lib/cdk-hello-world-stack');
const app = new cdk.App();
new CdkHelloWorldStack(app, 'CdkHelloWorldStack', {
});
```
位於 ： `app.py`  

```
#!/usr/bin/env python3
import os
import aws_cdk as cdk
from cdk_hello_world.cdk_hello_world_stack import CdkHelloWorldStack

app = cdk.App()
CdkHelloWorldStack(app, "CdkHelloWorldStack",)
app.synth()
```
位於 ： `src/main/java/…​/CdkHelloWorldApp.java`  

```
package com.myorg;

import software.amazon.awscdk.App;
import software.amazon.awscdk.Environment;
import software.amazon.awscdk.StackProps;

import java.util.Arrays;

public class JavaApp {
    public static void main(final String[] args) {
        App app = new App();

        new JavaStack(app, "JavaStack", StackProps.builder()
                .build());

        app.synth();
    }
}
```
位於 ： `src/CdkHelloWorld/Program.cs`  

```
using Amazon.CDK;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CdkHelloWorld
{
    sealed class Program
    {
        public static void Main(string[] args)
        {
            var app = new App();
            new CdkHelloWorldStack(app, "CdkHelloWorldStack", new StackProps
            {

            });
            app.Synth();
        }
    }
}
```
位於 ： `cdk-hello-world.go`  

```
package main
import (
    "github.com/aws/aws-cdk-go/awscdk/v2"
    "github.com/aws/constructs-go/constructs/v10"
    "github.com/aws/jsii-runtime-go"
)

// ...

func main() {
    defer jsii.Close()
    app := awscdk.NewApp(nil)
    NewCdkHelloWorldStack(app, "CdkHelloWorldStack", &CdkHelloWorldStackProps{
        awscdk.StackProps{
            Env: env(),
        },
    })
    app.Synth(nil)
}

func env() *awscdk.Environment {
    return nil
}
```

## 步驟 2：建立 Lambda 函數
<a name="serverless-example-function"></a>

在 CDK 專案中，建立包含新`hello.js`檔案的`lambda`目錄。以下是範例：

**Example**  
從專案的根目錄執行下列動作：  

```
$ mkdir lambda && cd lambda
$ touch hello.js
```
現在應該將下列項目新增至您的 CDK 專案：  

```
cdk-hello-world
└── lambda
    └── hello.js
```
從專案的根目錄執行下列動作：  

```
$ mkdir lambda && cd lambda
$ touch hello.js
```
現在應該將下列項目新增至您的 CDK 專案：  

```
cdk-hello-world
└── lambda
    └── hello.js
```
從專案的根目錄執行下列動作：  

```
$ mkdir lambda && cd lambda
$ touch hello.js
```
現在應該將下列項目新增至您的 CDK 專案：  

```
cdk-hello-world
└── lambda
    └── hello.js
```
從專案的根目錄執行下列動作：  

```
$ mkdir -p src/main/resources/lambda
$ cd src/main/resources/lambda
$ touch hello.js
```
現在應該將下列項目新增至您的 CDK 專案：  

```
cdk-hello-world
└── src
    └── main
        └──resources
            └──lambda
                └──hello.js
```
從專案的根目錄執行下列動作：  

```
$ mkdir lambda && cd lambda
$ touch hello.js
```
現在應該將下列項目新增至您的 CDK 專案：  

```
cdk-hello-world
└── lambda
    └── hello.js
```
從專案的根目錄執行下列動作：  

```
$ mkdir lambda && cd lambda
$ touch hello.js
```
現在應該將下列項目新增至您的 CDK 專案：  

```
cdk-hello-world
└── lambda
    └── hello.js
```

**注意**  
為了讓本教學課程保持簡單，我們針對所有 CDK 程式設計語言使用 JavaScript Lambda 函數。

將以下內容新增至新建立的檔案，以定義您的 Lambda 函數：

```
exports.handler = async (event) => {
    return {
        statusCode: 200,
        headers: { "Content-Type": "text/plain" },
        body: JSON.stringify({ message: "Hello, World!" }),
    };
};
```

## 步驟 3：定義您的建構
<a name="serverless-example-constructs"></a>

在此步驟中，您將使用 AWS CDK L2 建構模組定義 Lambda 和 API Gateway 資源。

開啟定義 CDK 堆疊的專案檔案。您將修改此檔案來定義您的建構。以下是啟動堆疊檔案的範例：

**Example**  
位於 ： `lib/cdk-hello-world-stack.ts`  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';

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

    // Your constructs will go here

  }
}
```
位於 ： `lib/cdk-hello-world-stack.js`  

```
const { Stack, Duration } = require('aws-cdk-lib');
const lambda = require('aws-cdk-lib/aws-lambda');
const apigateway = require('aws-cdk-lib/aws-apigateway');

class CdkHelloWorldStack extends Stack {

  constructor(scope, id, props) {
    super(scope, id, props);

    // Your constructs will go here

  }
}

module.exports = { CdkHelloWorldStack }
```
位於 ： `cdk_hello_world/cdk_hello_world_stack.py`  

```
from aws_cdk import Stack
from constructs import Construct

class CdkHelloWorldStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

          // Your constructs will go here
```
位於 ： `src/main/java/…​/CdkHelloWorldStack.java`  

```
package com.myorg;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;

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

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

        // Your constructs will go here
    }
}
```
位於 ： `src/CdkHelloWorld/CdkHelloWorldStack.cs`  

```
using Amazon.CDK;
using Constructs;

namespace CdkHelloWorld
{
    public class CdkHelloWorldStack : Stack
    {
        internal CdkHelloWorldStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            // Your constructs will go here
        }
    }
}
```
位於 `cdk-hello-world.go`：  

```
package main

import (
    "github.com/aws/aws-cdk-go/awscdk/v2"
    "github.com/aws/constructs-go/constructs/v10"
    "github.com/aws/jsii-runtime-go"
)

type CdkHelloWorldStackProps struct {
    awscdk.StackProps
}

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

    // Your constructs will go here

    return stack
}

func main() {

    // ...

}

func env() *awscdk.Environment {

    return nil

}
```

在此檔案中， AWS CDK 正在執行下列動作：
+ 您的 CDK 堆疊執行個體會從 ` [Stack](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stack.html) `類別執行個體化。
+ ` [Constructs](https://docs.aws.amazon.com/cdk/api/v2/docs/constructs-readme.html) ` 基本類別會匯入並提供為堆疊執行個體的範圍或父系。

### 定義您的 Lambda 函數資源
<a name="serverless-example-constructs-lambda"></a>

若要定義 Lambda 函數資源，您可以從 AWS 建構程式庫匯入並使用 ` [aws-lambda](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda-readme.html) ` L2 建構。

修改堆疊檔案，如下所示：

**Example**  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
// Import Lambda L2 construct
import * as lambda from 'aws-cdk-lib/aws-lambda';

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

    // Define the Lambda function resource
    const helloWorldFunction = new lambda.Function(this, 'HelloWorldFunction', {
      runtime: lambda.Runtime.NODEJS_20_X, // Choose any supported Node.js runtime
      code: lambda.Code.fromAsset('lambda'), // Points to the lambda directory
      handler: 'hello.handler', // Points to the 'hello' file in the lambda directory
    });
  }
}
```

```
const { Stack, Duration } = require('aws-cdk-lib');
// Import Lambda L2 construct
const lambda = require('aws-cdk-lib/aws-lambda');


class CdkHelloWorldStack extends Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    // Define the Lambda function resource
    const helloWorldFunction = new lambda.Function(this, 'HelloWorldFunction', {
      runtime: lambda.Runtime.NODEJS_20_X, // Choose any supported Node.js runtime
      code: lambda.Code.fromAsset('lambda'), // Points to the lambda directory
      handler: 'hello.handler', // Points to the 'hello' file in the lambda directory
    });
  }
}

module.exports = { CdkHelloWorldStack }
```

```
from aws_cdk import (
    Stack,
    # Import Lambda L2 construct
    aws_lambda as _lambda,
)
# ...

class CdkHelloWorldStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # Define the Lambda function resource
        hello_world_function = _lambda.Function(
            self,
            "HelloWorldFunction",
            runtime = _lambda.Runtime.NODEJS_20_X, # Choose any supported Node.js runtime
            code = _lambda.Code.from_asset("lambda"), # Points to the lambda directory
            handler = "hello.handler", # Points to the 'hello' file in the lambda directory
        )
```
我們將`aws_lambda`模組匯入為 ，`\_lambda`因為 `lambda` 是 Python 中的內建識別符。

```
// ...
// Import Lambda L2 construct
import software.amazon.awscdk.services.lambda.Code;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;

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

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

        // Define the Lambda function resource
        Function helloWorldFunction = Function.Builder.create(this, "HelloWorldFunction")
                .runtime(Runtime.NODEJS_20_X)  // Choose any supported Node.js runtime
                .code(Code.fromAsset("src/main/resources/lambda")) // Points to the lambda directory
                .handler("hello.handler")  // Points to the 'hello' file in the lambda directory
                .build();
    }
}
```

```
// ...
// Import Lambda L2 construct
using Amazon.CDK.AWS.Lambda;

namespace CdkHelloWorld
{
    public class CdkHelloWorldStack : Stack
    {
        internal CdkHelloWorldStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            // Define the Lambda function resource
            var helloWorldFunction = new Function(this, "HelloWorldFunction", new FunctionProps
            {
                Runtime = Runtime.NODEJS_20_X, // Choose any supported Node.js runtime
                Code = Code.FromAsset("lambda"), // Points to the lambda directory
                Handler = "hello.handler" // Points to the 'hello' file in the lambda directory
            });
        }
    }
}
```

```
package main

import (
    // ...
    // Import Lambda L2 construct
    "github.com/aws/aws-cdk-go/awscdk/v2/awslambda"
    // Import S3 assets construct
    "github.com/aws/aws-cdk-go/awscdk/v2/awss3assets"
    // ...
)

// ...

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

    // Define the Lambda function resource
    helloWorldFunction := awslambda.NewFunction(stack, jsii.String("HelloWorldFunction"), &awslambda.FunctionProps{
        Runtime: awslambda.Runtime_NODEJS_20_X(), // Choose any supported Node.js runtime
        Code:    awslambda.Code_FromAsset(jsii.String("lambda"), &awss3assets.AssetOptions{}), // Points to the lambda directory
        Handler: jsii.String("hello.handler"), // Points to the 'hello' file in the lambda directory
    })

    return stack
}

// ...
```

在這裡，您可以建立 Lambda 函數資源並定義下列屬性：
+  `runtime` – 函數執行所在的環境。在這裡，我們使用 Node.js 20.x 版。
+  `code` – 本機電腦上函數程式碼的路徑。
+  `handler` – 包含函數程式碼的特定檔案名稱。

### 定義您的 API Gateway REST API 資源
<a name="serverless-example-constructs-api"></a>

若要定義 API Gateway REST API 資源，您可以從 AWS 建構程式庫匯入並使用 ` [aws-apigateway](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway-readme.html) ` L2 建構。

修改堆疊檔案，如下所示：

**Example**  

```
// ...
//Import API Gateway L2 construct
import * as apigateway from 'aws-cdk-lib/aws-apigateway';


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

    // ...

    // Define the API Gateway resource
    const api = new apigateway.LambdaRestApi(this, 'HelloWorldApi', {
      handler: helloWorldFunction,
      proxy: false,
    });

    // Define the '/hello' resource with a GET method
    const helloResource = api.root.addResource('hello');
    helloResource.addMethod('GET');
  }
}
```

```
// ...
// Import API Gateway L2 construct
const apigateway = require('aws-cdk-lib/aws-apigateway');


class CdkHelloWorldStack extends Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    // ...

    // Define the API Gateway resource
    const api = new apigateway.LambdaRestApi(this, 'HelloWorldApi', {
      handler: helloWorldFunction,
      proxy: false,
    });

    // Define the '/hello' resource with a GET method
    const helloResource = api.root.addResource('hello');
    helloResource.addMethod('GET');
  };
};

// ...
```

```
from aws_cdk import (
    # ...
    # Import API Gateway L2 construct
    aws_apigateway as apigateway,
)
from constructs import Construct

class CdkHelloWorldStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # ...

        # Define the API Gateway resource
        api = apigateway.LambdaRestApi(
            self,
            "HelloWorldApi",
            handler = hello_world_function,
            proxy = False,
        )

        # Define the '/hello' resource with a GET method
        hello_resource = api.root.add_resource("hello")
        hello_resource.add_method("GET")
```

```
// ...
// Import API Gateway L2 construct
import software.amazon.awscdk.services.apigateway.LambdaRestApi;
import software.amazon.awscdk.services.apigateway.Resource;

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

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

        // ...

        // Define the API Gateway resource
        LambdaRestApi api = LambdaRestApi.Builder.create(this, "HelloWorldApi")
                .handler(helloWorldFunction)
                .proxy(false) // Turn off default proxy integration
                .build();

        // Define the '/hello' resource and its GET method
        Resource helloResource = api.getRoot().addResource("hello");
        helloResource.addMethod("GET");
    }
}
```

```
// ...
// Import API Gateway L2 construct
using Amazon.CDK.AWS.APIGateway;

namespace CdkHelloWorld
{
    public class CdkHelloWorldStack : Stack
    {
        internal CdkHelloWorldStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
           // ...

            // Define the API Gateway resource
            var api = new LambdaRestApi(this, "HelloWorldApi", new LambdaRestApiProps
            {
                Handler = helloWorldFunction,
                Proxy = false
            });

            // Add a '/hello' resource with a GET method
            var helloResource = api.Root.AddResource("hello");
            helloResource.AddMethod("GET");
        }
    }
}
```

```
// ...

import (
    // ...
    // Import Api Gateway L2 construct
    "github.com/aws/aws-cdk-go/awscdk/v2/awsapigateway"
    // ...
)

// ...

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

    // Define the Lambda function resource
    // ...

    // Define the API Gateway resource
    api := awsapigateway.NewLambdaRestApi(stack, jsii.String("HelloWorldApi"), &awsapigateway.LambdaRestApiProps{
        Handler: helloWorldFunction,
        Proxy: jsii.Bool(false),
    })

    // Add a '/hello' resource with a GET method
    helloResource := api.Root().AddResource(jsii.String("hello"), &awsapigateway.ResourceOptions{})
    helloResource.AddMethod(jsii.String("GET"), awsapigateway.NewLambdaIntegration(helloWorldFunction, &awsapigateway.LambdaIntegrationOptions{}), &awsapigateway.MethodOptions{})

    return stack
}

// ...
```

您可以在此建立 API Gateway REST API 資源，以及下列項目：
+ REST API 和 Lambda 函數之間的整合，允許 API 叫用您的函數。這包括建立 Lambda 許可資源。
+ 名為 的新資源或路徑`hello`，已新增至 API 端點的根目錄。這會建立新的端點，`/hello`以新增至您的基本 URL。
+ 資源的 GET 方法`hello`。當 GET 請求傳送至`/hello`端點時，會叫用 Lambda 函數並傳回其回應。

## 步驟 4：準備您的應用程式以進行部署
<a name="serverless-example-deploy-prepare"></a>

在此步驟中，您可以視需要建置應用程式以進行部署，並使用 AWS CDK CLI `cdk synth`命令執行基本驗證。

如有必要，請建置您的應用程式：

**Example**  
從專案的根目錄執行下列動作：  

```
$ npm run build
```
不需要建置。
不需要建置。
從專案的根目錄執行下列動作：  

```
$ mvn package
```
從專案的根目錄執行下列動作：  

```
$ dotnet build src
```
不需要建置。

執行 `cdk synth`以從您的 CDK 程式碼合成 an AWS CloudFormation 範本。透過使用 L2 建構， AWS CloudFormation 所需的許多組態詳細資訊，以促進 Lambda 函數和 REST API 之間的互動是由 AWS CDK 為您佈建。

從專案的根目錄執行下列動作：

```
$ cdk synth
```

**注意**  
如果您收到類似以下的錯誤，請確認您位於 `cdk-hello-world`目錄中，然後再試一次：  

```
--app is required either in command-line, in cdk.json or in ~/.cdk.json
```

如果成功， AWS CDK CLI 會在命令提示中以 `YAML` 格式輸出 AWS CloudFormation 範本。`JSON` 格式化範本也會儲存在 `cdk.out`目錄中。

以下是 AWS CloudFormation 範本的範例輸出：

### AWS CloudFormation 範本
<a name="serverless-example-deploy-cfn"></a>

```
Resources:
  HelloWorldFunctionServiceRoleunique-identifier:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
        Version: "2012-10-17"		 	 	 
      ManagedPolicyArns:
        - Fn::Join:
            - ""
            - - "arn:"
              - Ref: AWS::Partition
              - :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
    Metadata:
      aws:cdk:path: CdkHelloWorldStack/HelloWorldFunction/ServiceRole/Resource
  HelloWorldFunctionunique-identifier:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket:
          Fn::Sub: cdk-unique-identifier-assets-${AWS::AccountId}-${AWS::Region}
        S3Key: unique-identifier.zip
      Handler: hello.handler
      Role:
        Fn::GetAtt:
          - HelloWorldFunctionServiceRoleunique-identifier
          - Arn
      Runtime: nodejs20.x
    DependsOn:
      - HelloWorldFunctionServiceRoleunique-identifier
    Metadata:
      aws:cdk:path: CdkHelloWorldStack/HelloWorldFunction/Resource
      aws:asset:path: asset.unique-identifier
      aws:asset:is-bundled: false
      aws:asset:property: Code
  HelloWorldApiunique-identifier:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Name: HelloWorldApi
    Metadata:
      aws:cdk:path: CdkHelloWorldStack/HelloWorldApi/Resource
  HelloWorldApiDeploymentunique-identifier:
    Type: AWS::ApiGateway::Deployment
    Properties:
      Description: Automatically created by the RestApi construct
      RestApiId:
        Ref: HelloWorldApiunique-identifier
    DependsOn:
      - HelloWorldApihelloGETunique-identifier
      - HelloWorldApihellounique-identifier
    Metadata:
      aws:cdk:path: CdkHelloWorldStack/HelloWorldApi/Deployment/Resource
  HelloWorldApiDeploymentStageprod012345ABC:
    Type: AWS::ApiGateway::Stage
    Properties:
      DeploymentId:
        Ref: HelloWorldApiDeploymentunique-identifier
      RestApiId:
        Ref: HelloWorldApiunique-identifier
      StageName: prod
    Metadata:
      aws:cdk:path: CdkHelloWorldStack/HelloWorldApi/DeploymentStage.prod/Resource
  HelloWorldApihellounique-identifier:
    Type: AWS::ApiGateway::Resource
    Properties:
      ParentId:
        Fn::GetAtt:
          - HelloWorldApiunique-identifier
          - RootResourceId
      PathPart: hello
      RestApiId:
        Ref: HelloWorldApiunique-identifier
    Metadata:
      aws:cdk:path: CdkHelloWorldStack/HelloWorldApi/Default/hello/Resource
  HelloWorldApihelloGETApiPermissionCdkHelloWorldStackHelloWorldApiunique-identifier:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName:
        Fn::GetAtt:
          - HelloWorldFunctionunique-identifier
          - Arn
      Principal: apigateway.amazonaws.com
      SourceArn:
        Fn::Join:
          - ""
          - - "arn:"
            - Ref: AWS::Partition
            - ":execute-api:"
            - Ref: AWS::Region
            - ":"
            - Ref: AWS::AccountId
            - ":"
            - Ref: HelloWorldApi9E278160
            - /
            - Ref: HelloWorldApiDeploymentStageprodunique-identifier
            - /GET/hello
    Metadata:
      aws:cdk:path: CdkHelloWorldStack/HelloWorldApi/Default/hello/GET/ApiPermission.CdkHelloWorldStackHelloWorldApiunique-identifier.GET..hello
  HelloWorldApihelloGETApiPermissionTestCdkHelloWorldStackHelloWorldApiunique-identifier:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName:
        Fn::GetAtt:
          - HelloWorldFunctionunique-identifier
          - Arn
      Principal: apigateway.amazonaws.com
      SourceArn:
        Fn::Join:
          - ""
          - - "arn:"
            - Ref: AWS::Partition
            - ":execute-api:"
            - Ref: AWS::Region
            - ":"
            - Ref: AWS::AccountId
            - ":"
            - Ref: HelloWorldApiunique-identifier
            - /test-invoke-stage/GET/hello
    Metadata:
      aws:cdk:path: CdkHelloWorldStack/HelloWorldApi/Default/hello/GET/ApiPermission.Test.CdkHelloWorldStackHelloWorldApiunique-identifier.GET..hello
  HelloWorldApihelloGETunique-identifier:
    Type: AWS::ApiGateway::Method
    Properties:
      AuthorizationType: NONE
      HttpMethod: GET
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri:
          Fn::Join:
            - ""
            - - "arn:"
              - Ref: AWS::Partition
              - ":apigateway:"
              - Ref: AWS::Region
              - :lambda:path/2015-03-31/functions/
              - Fn::GetAtt:
                  - HelloWorldFunctionunique-identifier
                  - Arn
              - /invocations
      ResourceId:
        Ref: HelloWorldApihellounique-identifier
      RestApiId:
        Ref: HelloWorldApiunique-identifier
    Metadata:
      aws:cdk:path: CdkHelloWorldStack/HelloWorldApi/Default/hello/GET/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Analytics: v2:deflate64:unique-identifier
    Metadata:
      aws:cdk:path: CdkHelloWorldStack/CDKMetadata/Default
    Condition: CDKMetadataAvailable
Outputs:
  HelloWorldApiEndpointunique-identifier:
    Value:
      Fn::Join:
        - ""
        - - https://
          - Ref: HelloWorldApiunique-identifier
          - .execute-api.
          - Ref: AWS::Region
          - "."
          - Ref: AWS::URLSuffix
          - /
          - Ref: HelloWorldApiDeploymentStageprodunique-identifier
          - /
Conditions:
  CDKMetadataAvailable:
    Fn::Or:
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - af-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-northeast-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-northeast-2
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-southeast-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-southeast-2
          - Fn::Equals:
              - Ref: AWS::Region
              - ca-central-1
          - Fn::Equals:
              - Ref: AWS::Region
              - cn-north-1
          - Fn::Equals:
              - Ref: AWS::Region
              - cn-northwest-1
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-central-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-north-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-2
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-3
          - Fn::Equals:
              - Ref: AWS::Region
              - il-central-1
          - Fn::Equals:
              - Ref: AWS::Region
              - me-central-1
          - Fn::Equals:
              - Ref: AWS::Region
              - me-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - sa-east-1
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - us-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-east-2
          - Fn::Equals:
              - Ref: AWS::Region
              - us-west-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-west-2
Parameters:
  BootstrapVersion:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /cdk-bootstrap/hnb659fds/version
    Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Rules:
  CheckBootstrapVersion:
    Assertions:
      - Assert:
          Fn::Not:
            - Fn::Contains:
                - - "1"
                  - "2"
                  - "3"
                  - "4"
                  - "5"
                - Ref: BootstrapVersion
        AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
```

透過使用 L2 建構，您可以定義幾個屬性來設定資源，並使用協助程式方法來整合資源。 AWS CDK 會設定佈建應用程式所需的大多數 AWS CloudFormation 資源和屬性。

## 步驟 5：部署應用程式
<a name="serverless-example-deploy"></a>

在此步驟中，您可以使用 AWS CDK CLI `cdk deploy`命令來部署應用程式。 AWS CDK 可與 AWS CloudFormation 服務搭配使用來佈建您的 資源。

**重要**  
在部署 AWS 之前，您必須執行環境的一次性引導。如需說明，請參閱[引導您的環境以搭配 AWS CDK 使用](bootstrapping-env.md)。

從專案的根目錄執行下列動作。出現提示時確認變更：

```
$ cdk deploy

✨  Synthesis time: 2.44s

...

Do you wish to deploy these changes (y/n)? <y>
```

部署完成時， AWS CDK CLI 將輸出您的端點 URL。複製此 URL 以進行下一個步驟。以下是範例：

```
...
✅  HelloWorldStack

✨  Deployment time: 45.37s

Outputs:
HelloWorldStack.HelloWorldApiEndpointunique-identifier = https://<api-id>.execute-api.<region>.amazonaws.com/prod/
Stack ARN:
arn:aws:cloudformation:region:account-id:stack/HelloWorldStack/unique-identifier
...
```

## 步驟 6：與您的應用程式互動
<a name="serverless-example-interact"></a>

在此步驟中，您會對 API 端點啟動 GET 請求，並接收 Lambda 函數回應。

從上一個步驟找到您的端點 URL 並新增`/hello`路徑。然後，使用您的瀏覽器或命令提示，將 GET 請求傳送至您的端點。以下是範例：

```
$ curl https://<api-id>.execute-api.<region>.amazonaws.com/prod/hello
{"message":"Hello World!"}%
```

恭喜，您已成功使用 AWS CDK 建立、部署和與您的應用程式互動！

## 步驟 7：刪除您的應用程式
<a name="serverless-example-delete"></a>

在此步驟中，您會使用 AWS CDK CLI 從 AWS 雲端刪除應用程式。

若要刪除您的應用程式，請執行 `cdk destroy`。出現提示時，請確認您刪除應用程式的請求：

```
$ cdk destroy
Are you sure you want to delete: CdkHelloWorldStack (y/n)? y
CdkHelloWorldStack: destroying... [1/1]
...
 ✅  CdkHelloWorldStack: destroyed
```

## 故障診斷
<a name="serverless-example-troubleshooting"></a>

### 錯誤：\$1"message"： "內部伺服器錯誤"\$1%
<a name="serverless-example-trobuleshooting-error1"></a>

叫用已部署的 Lambda 函數時，您會收到此錯誤。此錯誤可能因多種原因而發生。

 **進一步疑難排解**   
使用 AWS CLI 叫用 Lambda 函數。  

1. 修改堆疊檔案，以擷取已部署 Lambda 函數名稱的輸出值。以下是範例：

   ```
   ...
   
   class CdkHelloWorldStack extends Stack {
     constructor(scope, id, props) {
       super(scope, id, props);
   
       // Define the Lambda function resource
       // ...
   
       new CfnOutput(this, 'HelloWorldFunctionName', {
         value: helloWorldFunction.functionName,
         description: 'JavaScript Lambda function'
       });
   
       // Define the API Gateway resource
       // ...
     }
   }
   ```

1. 再次部署您的應用程式。 AWS CDK CLI 將輸出已部署 Lambda 函數名稱的值：

   ```
   $ cdk deploy
   
   ✨  Synthesis time: 0.29s
   ...
    ✅  CdkHelloWorldStack
   
   ✨  Deployment time: 20.36s
   
   Outputs:
   ...
   CdkHelloWorldStack.HelloWorldFunctionName = CdkHelloWorldStack-HelloWorldFunctionunique-identifier
   ...
   ```

1. 使用 AWS CLI 在 AWS 雲端中調用 Lambda 函數，並將回應輸出至文字檔案：

   ```
   $ aws lambda invoke --function-name CdkHelloWorldStack-HelloWorldFunctionunique-identifier output.txt
   ```

1. 檢查 `output.txt`以查看結果。  
 **可能原因：堆疊檔案中的 API Gateway 資源定義不正確**   
如果 `output.txt`顯示成功的 Lambda 函數回應，問題可能是您定義 API Gateway REST API 的方式。CLI AWS 會直接叫用您的 Lambda，而不是透過您的端點。檢查您的程式碼，以確保其符合本教學課程。然後，再次部署。  
 **可能原因：堆疊檔案中的 Lambda 資源定義不正確**   
如果 `output.txt`傳回錯誤，問題可能是您定義 Lambda 函數的方式。檢查您的程式碼，以確保其符合本教學課程。然後再次部署。