

CDK AWS v2 개발자 안내서입니다. 이전 CDK v1은 2022년 6월 1일에 유지 관리에 들어갔으며 2023년 6월 1일에 지원이 종료되었습니다.

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# 자습서: 서버리스 Hello World 애플리케이션 생성
<a name="serverless-example"></a>

이 자습서에서는 AWS Cloud Development Kit(AWS CDK)를 사용하여 다음으로 구성된 기본 API 백엔드를 구현하는 간단한 서버리스 `Hello World` 애플리케이션을 생성합니다.
+  **Amazon API Gateway REST API** - HTTP GET 요청을 통해 함수를 간접적으로 호출하는 데 사용되는 HTTP 엔드포인트를 제공합니다.
+  ** AWS Lambda 함수** - HTTP 엔드포인트로 간접적으로 호출될 때 `Hello World!` 메시지를 반환하는 함수입니다.
+  **통합 및 권한** - 리소스가 서로 상호 작용하고 Amazon CloudWatch에 로그 쓰기와 같은 작업을 수행할 수 있는 구성 세부 정보 및 권한입니다.

다음 다이어그램은 이 애플리케이션의 구성 요소를 보여줍니다.

![\[API Gateway 엔드포인트에 GET 요청을 보낼 때 간접적으로 호출되는 Lambda 함수의 다이어그램입니다.\]](http://docs.aws.amazon.com/ko_kr/cdk/v2/guide/images/serverless-example-01.png)


이 자습서에서는 다음 단계에 따라 애플리케이션을 생성하고 상호 작용합니다.

1. AWS CDK 프로젝트를 생성합니다.

1. AWS Construct Library의 L2 구문을 사용하여 Lambda 함수와 API Gateway REST API를 정의합니다.

1. AWS 클라우드에 애플리케이션을 배포합니다.

1. AWS 클라우드에서 애플리케이션과 상호 작용합니다.

1. AWS 클라우드에서 샘플 애플리케이션을 삭제합니다.

## 사전 조건
<a name="serverless-example-pre"></a>

이 자습서를 시작하기 전에 다음을 완료하십시오.
+ AWS 계정을 생성하고 AWS Command Line Interface(AWS CLI)를 설치하고 구성합니다.
+ Node.js 및 `npm`을 설치합니다.
+ `npm install -g aws-cdk`를 사용하여 CDK Toolkit를 전역적으로 설치합니다.

자세한 내용은 [AWS CDK 시작하기](getting-started.md)를 참조하세요.

또한 다음 사항에 대한 기본적인 이해를 권장합니다.
+  AWS CDK의 기본 소개를 위한 [AWS CDK란 무엇입니까?](home.md).
+  AWS CDK의 핵심 개념 개요에 대한 [AWS CDK 핵심 개념을 알아보기](core-concepts.md).

## 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 앱을 자동으로 생성합니다. 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 Construct Library에서 ` [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
        )
```
`lambda`는 Python의 기본 제공 식별자이므로 `aws_lambda` 모듈을 `\_lambda`로 가져옵니다.

```
// ...
// 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 Construct Library에서 ` [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 리소스를 생성합니다.
+ API가 함수를 간접적으로 호출할 수 있도록 REST API와 Lambda 함수 간의 통합입니다. 여기에는 Lambda 권한 리소스 생성이 포함됩니다.
+ API 엔드포인트의 루트에 추가된 `hello`라는 새 리소스 또는 경로입니다. 이렇게 하면 기본 URL에 `/hello`를 추가하는 새 엔드포인트가 생성됩니다.
+ `hello` 리소스의 GET 메서드입니다. 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 코드에서 AWS CloudFormation 템플릿을 합성합니다. L2 구문을 사용하면 Lambda 함수와 REST API 간의 상호 작용을 원활하게 하기 위해 AWS CloudFormation에 필요한 많은 구성 세부 정보가 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": "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 함수를 정의한 방식과 관련된 문제일 수 있습니다. 코드를 검사하여 이 자습서와 일치하는지 확인하세요. 그런 다음 다시 배포합니다.