

这是 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）的配置详细信息和权限。

下图显示此应用程序的组件：

![\[向 API Gateway 端点发送 GET 请求时调用的 Lambda 函数的图表。\]](http://docs.aws.amazon.com/zh_cn/cdk/v2/guide/images/serverless-example-01.png)


在本教程中，您将按照以下步骤创建应用程序并与之交互：

1. 创建 AWS CDK 项目。

1. 使用 AWS 构造库中的 L2 构造定义 Lambda 函数和 API Gateway REST API。

1. 将应用程序部署到 AWS 云。

1. 在 AWS 云中与您的应用程序进行交互。

1. 从 AWS 云中删除示例应用程序。

## 先决条件
<a name="serverless-example-pre"></a>

开始教程前，请完成以下步骤：
+ 创建 AWS 账户，然后安装和配置 AWS 命令行界面 (AWS CLI)。
+ 安装 Node.js 和 `npm`。
+ 使用 `npm install -g aws-cdk` 全局安装 CDK Toolkit。

有关更多信息，请参阅[开始使用 AWS SDK](getting-started.md)。

我们还建议您初步了解以下内容：
+  [什么是 AWS CDK？](home.md)，获取 AWS CDK 的基本介绍。
+  [了解 AWS CDK 核心概念](core-concepts.md)，获取 AWS CDK 核心概念的概述。

## 步骤 1：创建 CDK 项目
<a name="serverless-example-project"></a>

在本步骤中，您将使用 AWS CDK CLI `cdk init` 命令创建新的 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 应用程序。根据 ` [App](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.App.html) ` 类来创建 CDK 应用程序实例。以下内容是 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 正在执行以下操作：
+ 从 ` [Stack](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stack.html) ` 类中实例化您的 CDK 堆栈实例。
+ 导入 ` [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 权限资源。
+ 添加到 API 端点根目录的名为 `hello` 的新资源或路径。这将创建一个新的端点，可将 `/hello` 添加到基本 URL。
+ `hello` 资源的 GET 方法。在向 `/hello` 端点发送 GET 请求时，会调用 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 代码合成 AWS CloudFormation 模板。使用 L2 构造，AWS CDK 可为您预置 AWS CloudFormation 所需的许多配置详细信息，以促进 Lambda 函数和 REST API 之间的交互。

在项目的根目录中运行以下命令：

```
$ 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` 路径。然后使用浏览器或命令提示符向 API 端点发送 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 Cloud 中删除应用程序。

要删除您的应用程序，请运行 `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": "Internal server error"\$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 的方式上。AWS CLI 直接调用您的 Lambda，而不是通过端点调用。检查您的代码以确保其符合本教程。然后再次部署。  
 **可能的原因：堆栈文件中对 Lambda 资源的定义不正确**。  
如果 `output.txt` 返回错误，则问题可能与您定义 Lambda 函数的方式有关。检查您的代码以确保其符合本教程。然后再次部署。