

# Amazon API Gateway 자습서 및 워크숍
<a name="api-gateway-tutorials"></a>

다음 자습서 및 워크숍에는 API Gateway에 대해 알아보는 데 도움이 되는 실습용 과제가 나와 있습니다. 시작하려면 [자습서: Lambda 프록시 통합을 통해 REST API 생성](api-gateway-create-api-as-simple-proxy-for-lambda.md)를 완료하는 것이 좋습니다.

**REST API 자습서**
+ [AWS Lambda 통합 튜토리얼 선택](getting-started-with-lambda-integration.md)
+ [자습서: 예제를 가져와 REST API 생성](api-gateway-create-api-from-example.md)
+ [HTTP 통합 튜토리얼 선택](getting-started-http-integrations.md)
+ [자습서: 프라이빗 통합을 통해 REST API 생성](getting-started-with-private-integration.md)
+ [자습서: AWS 통합을 통해 REST API 생성](getting-started-aws-proxy.md)
+ [튜토리얼: 두 개의 AWS 서비스 통합과 하나의 Lambda 비프록시 통합으로 REST API 생성](integrating-api-with-aws-services-lambda.md)
+ [자습서: Amazon Kinesis 프록시로 REST API 생성](integrating-api-with-aws-services-s3.md)
+ [자습서: REST API를 Amazon Kinesis 프록시로 생성](integrating-api-with-aws-services-kinesis.md)
+ [자습서: AWS SDK 또는 AWS CLI를 사용하여 REST API 생성](api-gateway-create-api-cli-sdk.md)
+ [자습서: 프라이빗 REST API 생성](private-api-tutorial.md)

**HTTP API 자습서**
+ [자습서: Lambda 및 DynamoDB를 사용한 CRUD HTTP API 생성](http-api-dynamo-db.md)
+ [자습서: Amazon ECS 서비스에 대한 프라이빗 통합을 통해 HTTP API 생성](http-api-private-integration.md)

**WebSocket API 자습서**
+ [자습서: WebSocket API, Lambda 및 DynamoDB를 사용하여 WebSocket 채팅 앱 생성](websocket-api-chat-app.md)

**워크숍**
+ [서버리스 웹 애플리케이션 구축](https://webapp.serverlessworkshops.io)
+ [서버리스 애플리케이션을 위한 CI/CD](https://cicd.serverlessworkshops.io)
+ [서버리스 보안 워크숍](https://github.com/aws-samples/aws-serverless-security-workshop)
+ [서버리스 ID 관리, 인증 및 권한 부여](https://auth.serverlessworkshops.io)
+ [Amazon API Gateway Workshop](https://catalog.workshops.aws/apigateway/en-US)

# Amazon API Gateway REST API 자습서
<a name="api-gateway-rest-tutorials"></a>

다음 자습서에는 API Gateway REST API에 대해 알아보는 데 도움이 되는 실습용 과제가 나와 있습니다.

**Topics**
+ [AWS Lambda 통합 튜토리얼 선택](getting-started-with-lambda-integration.md)
+ [자습서: 예제를 가져와 REST API 생성](api-gateway-create-api-from-example.md)
+ [HTTP 통합 튜토리얼 선택](getting-started-http-integrations.md)
+ [자습서: 프라이빗 통합을 통해 REST API 생성](getting-started-with-private-integration.md)
+ [자습서: AWS 통합을 통해 REST API 생성](getting-started-aws-proxy.md)
+ [튜토리얼: 두 개의 AWS 서비스 통합과 하나의 Lambda 비프록시 통합으로 REST API 생성](integrating-api-with-aws-services-lambda.md)
+ [자습서: Amazon Kinesis 프록시로 REST API 생성](integrating-api-with-aws-services-s3.md)
+ [자습서: REST API를 Amazon Kinesis 프록시로 생성](integrating-api-with-aws-services-kinesis.md)
+ [자습서: AWS SDK 또는 AWS CLI를 사용하여 REST API 생성](api-gateway-create-api-cli-sdk.md)
+ [자습서: 프라이빗 REST API 생성](private-api-tutorial.md)

# AWS Lambda 통합 튜토리얼 선택
<a name="getting-started-with-lambda-integration"></a>

 Lambda 통합을 사용하여 API를 구축하기 위해 Lambda 프록시 통합 또는 Lambda 비 프록시 통합을 사용할 수 있습니다.

Lambda 프록시 통합에서는 Lambda 함수에 대한 입력을 요청 헤더, 경로 변수, 쿼리 문자열 파라미터, 본문 및 API 구성 데이터의 조합으로 표현할 수 있습니다. Lambda 함수를 선택하기만 하면 됩니다. API Gateway는 통합 요청 및 통합 응답을 구성합니다. 설정을 완료하면 API 메서드는 기존 설정을 수정하지 않고 진화할 수 있습니다. 이는 백엔드 Lambda 함수가 수신되는 요청 데이터를 구문 분석하고 클라이언트에 응답하기 때문에 가능합니다.

Lambda 비 프록시 통합에서는 Lambda 함수에 대한 입력이 통합 요청 페이로드로 제공되는지 확인해야 합니다. 클라이언트에서 요청 파라미터로 제공한 모든 입력 데이터를 적절한 통합 요청 본문에 매핑해야 합니다. 클라이언트가 제공한 요청 본문을 Lambda 함수가 인식하는 형식으로 변환해야 할 수도 있습니다.

Lambda 프록시 통합이든 Lambda 비프록시 통합이든, API를 생성한 계정과 다른 계정에서 Lambda 함수를 사용할 수 있습니다.

**Topics**
+ [자습서: Lambda 프록시 통합을 통해 REST API 생성](api-gateway-create-api-as-simple-proxy-for-lambda.md)
+ [자습서: Lambda 비 프록시 통합을 통해 REST API 생성](getting-started-lambda-non-proxy-integration.md)
+ [자습서: 교차 계정 Lambda 프록시 통합을 통해 REST API 생성](apigateway-cross-account-lambda-integrations.md)

# 자습서: Lambda 프록시 통합을 통해 REST API 생성
<a name="api-gateway-create-api-as-simple-proxy-for-lambda"></a>

[Lambda 프록시 통합](set-up-lambda-proxy-integrations.md)은 API 메서드나 전체 API를 Lambda 함수와 통합할 수 있는 유연하고 간단한 API Gateway API 통합 유형입니다. Lambda 함수는 [Lambda가 지원하는 어떤 언어](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html)로도 작성할 수 있습니다. 이것은 프록시 통합이기 때문에 API를 다시 배포할 필요 없어 언제든지 Lambda 함수 구현을 변경할 수 있습니다.

이 자습서에서는 다음 작업을 수행합니다.
+ "Hello, World\$1" 만들기 API의 백엔드가 될 Lambda 함수를 만듭니다.
+ "Hello, World\$1" 만들기 및 테스트 Lambda 프록시 통합을 사용하여 API를 만들고 테스트합니다.

**Topics**
+ ["Hello, World\$1" 만들기 Lambda 함수](#api-gateway-proxy-integration-create-lambda-backend)
+ ["Hello, World\$1" 만들기 API](#api-gateway-create-api-as-simple-proxy-for-lambda-build)
+ [API 배포 및 테스트](#api-gateway-create-api-as-simple-proxy-for-lambda-test)

## "Hello, World\$1" 만들기 Lambda 함수
<a name="api-gateway-proxy-integration-create-lambda-backend"></a>

**“Hello, World\$1”를 생성하려면 Lambda 콘솔의 Lambda 함수**

1. [https://console.aws.amazon.com/lambda](https://console.aws.amazon.com/lambda)에서 Lambda 콘솔에 로그인합니다.

1. AWS 탐색 모음에서 [AWS 리전](https://docs.aws.amazon.com/general/latest/gr/apigateway.html)을 선택합니다.
**참고**  
Lambda 함수를 생성한 리전을 적어 둡니다. 이 리전은 API를 생성할 때 필요합니다.

1. 탐색 창에서 **함수**를 선택합니다.

1. **함수 생성**을 선택합니다.

1. **새로 작성**을 선택합니다.

1. **기본 정보**에서 다음과 같이 합니다.

   1. **함수 이름**에 **GetStartedLambdaProxyIntegration**을 입력합니다.

   1. **런타임**에서 지원되는 최신 **Node.js** 또는 **Python** 런타임을 선택합니다.

   1. **아키텍처**의 경우 기본 설정을 유지합니다.

   1. **권한(Permissions)**에서 **기본 실행 역할 변경(Change default execution role)**을 확장합니다. **실행 역할** 드롭다운 목록에서 **AWS 정책 템플릿에서 새 역할 생성**을 선택합니다.

   1. **역할 이름**에 **GetStartedLambdaBasicExecutionRole**을 입력합니다.

   1. [**Policy templates**] 필드를 비워둡니다.

   1. **함수 생성**을 선택합니다.

1. 다음 코드를 복사하여 인라인 코드 편집기의 **함수 코드**에 붙여 넣습니다.

------
#### [ Node.js ]

   ```
   export const handler = async(event, context) => {
       console.log('Received event:', JSON.stringify(event, null, 2));
       var res ={
           "statusCode": 200,
           "headers": {
               "Content-Type": "*/*"
           }
       };
       var greeter = 'World';
       if (event.greeter && event.greeter!=="") {
           greeter =  event.greeter;
       } else if (event.body && event.body !== "") {
           var body = JSON.parse(event.body);
           if (body.greeter && body.greeter !== "") {
               greeter = body.greeter;
           }
       } else if (event.queryStringParameters && event.queryStringParameters.greeter && event.queryStringParameters.greeter !== "") {
           greeter = event.queryStringParameters.greeter;
       } else if (event.multiValueHeaders && event.multiValueHeaders.greeter && event.multiValueHeaders.greeter != "") {
           greeter = event.multiValueHeaders.greeter.join(" and ");
       } else if (event.headers && event.headers.greeter && event.headers.greeter != "") {
           greeter = event.headers.greeter;
       } 
       res.body = "Hello, " + greeter + "!";
       return res
   };
   ```

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

   ```
   import json
   
   
   def lambda_handler(event, context):
       print(event)
   
       greeter = 'World'
   
       try:
           if (event['queryStringParameters']) and (event['queryStringParameters']['greeter']) and (
                   event['queryStringParameters']['greeter'] is not None):
               greeter = event['queryStringParameters']['greeter']
       except KeyError:
           print('No greeter')
   
       try:
           if (event['multiValueHeaders']) and (event['multiValueHeaders']['greeter']) and (
                   event['multiValueHeaders']['greeter'] is not None):
               greeter = " and ".join(event['multiValueHeaders']['greeter'])
       except KeyError:
           print('No greeter')
   
       try:
           if (event['headers']) and (event['headers']['greeter']) and (
                   event['headers']['greeter'] is not None):
               greeter = event['headers']['greeter']
       except KeyError:
           print('No greeter')
   
       if (event['body']) and (event['body'] is not None):
           body = json.loads(event['body'])
           try:
               if (body['greeter']) and (body['greeter'] is not None):
                   greeter = body['greeter']
           except KeyError:
               print('No greeter')
   
       res = {
           "statusCode": 200,
           "headers": {
               "Content-Type": "*/*"
           },
           "body": "Hello, " + greeter + "!"
       }
   
       return res
   ```

------

1. [**Deploy**]를 선택합니다.

## "Hello, World\$1" 만들기 API
<a name="api-gateway-create-api-as-simple-proxy-for-lambda-build"></a>

이제 API Gateway 콘솔을 사용하여 “Hello, World\$1” Lambda 함수에 대한 API를 만듭니다.

**“Hello, World\$1”를 생성하려면 API**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API Gateway를 처음 사용하는 경우, 서비스의 기능을 소개하는 페이지가 나타납니다. **REST API**에서 **빌드**를 선택합니다. **예제 API 생성** 팝업이 나타나면 **확인**을 선택합니다.

   API Gateway를 처음 사용하는 것이 아닌 경우 **API 생성**을 선택합니다. **REST API**에서 **빌드**를 선택합니다.

1.  **API 이름**에서 **LambdaProxyAPI**을 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **API 엔드포인트 유형** 설정을 **지역**으로 유지합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **API 생성**을 선택합니다.

API를 생성한 후에는 리소스를 생성합니다. 일반적으로 API 리소스는 애플리케이션 로직에 따른 리소스 트리로 정리되어 있습니다. 이 예시에서는 **/helloworld** 리소스를 생성합니다.

**리소스를 생성하려면**

1. **리소스 생성**을 선택합니다.

1. **프록시 리소스**는 꺼진 상태로 둡니다.

1. **리소스 경로**를 `/`로 유지합니다.

1. **리소스 이름**에 **helloworld**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

 프록시 통합에서는 전체 요청이 HTTP 메서드를 나타내는 catch-all `ANY` 메서드를 통해 백엔드 Lambda 함수로 그대로 전송됩니다. 실제 HTTP 메서드는 실행 시 클라이언트가 지정합니다. `ANY` 메서드를 통해 지원되는 모든 HTTP 메서드인 `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, `PUT`에 대해 단일 API 메서드 설정을 사용할 수 있습니다.

**`ANY` 메서드를 생성하려면**

1. **/helloworld** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **ANY**를 선택합니다.

1. **통합 유형**에서 **Lambda 함수**를 선택합니다.

1. **Lambda 프록시 통합**을 켭니다.

1. **Lambda 함수**에서 Lambda 함수를 생성한 AWS 리전을 선택하고 함수 이름을 입력합니다.

1. 기본 제한 시간 값인 29초를 사용하려면 **기본 제한 시간**을 활성화된 상태로 유지합니다. 사용자 지정 제한 시간을 설정하려면 **기본 제한 시간**을 선택하고 `50` \$1 `29000`밀리초 사이의 제한 시간 값을 입력합니다.

1. **메서드 생성**을 선택합니다.

## API 배포 및 테스트
<a name="api-gateway-create-api-as-simple-proxy-for-lambda-test"></a>

**API를 배포하려면**

1. **Deploy API(API 배포)**를 선택합니다.

1. **스테이지**에서 **새 스테이지**를 선택합니다.

1. **단계 이름**에 **test**를 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **배포(Deploy)**를 선택합니다.

1. **스테이지 세부 정보**에서 복사 아이콘을 선택하여 API의 호출 URL을 복사합니다.

### 브라우저와 cURL을 사용하여 API의 Lambda 프록시 통합 테스트
<a name="api-gateway-create-api-as-simple-proxy-for-lambda-test-curl"></a>

브라우저 또는 [cURL](https://curl.se/)을 사용하여 API를 테스트할 수 있습니다.

쿼리 문자열 파라미터를 사용하여 `GET` 요청을 테스트하려면, API의 `helloworld` 리소스에 대한 URL을 브라우저 주소 표시줄에 입력합니다.

API `helloworld` 리소스의 URL을 만들려면 `helloworld` 리소스와 쿼리 문자열 파라미터 `?greeter=John`을 간접 호출 URL에 추가합니다. URL은 다음과 같이 표시되어야 합니다.

```
https://r275xc9bmd.execute-api.us-east-1.amazonaws.com/test/helloworld?greeter=John
```

다른 메서드의 경우 [POSTMAN](https://www.postman.com/) 또는 [cURL](https://curl.se/) 등의 고급 REST API 테스트 유틸리티를 사용해야 합니다. 이 자습서에서는 cURL을 사용합니다. 아래의 cURL 명령 예제는 컴퓨터에 cURL이 설치되어 있다고 전제합니다.

**cURL을 사용하여 배포된 API를 테스트하려면 다음과 같이 합니다.**

1. 터미널 창을 엽니다.

1. 다음 cURL 명령을 복사하여 터미널 창에 붙여 넣습니다. 호출 URL을 이전 단계에서 복사한 것으로 바꾸고 URL 끝에 **/helloworld**를 추가합니다.
**참고**  
Windows에서 이 명령을 실행할 경우 다음 구문을 사용하십시오.  

   ```
   curl -v -X POST "https://r275xc9bmd.execute-api.us-east-1.amazonaws.com/test/helloworld" -H "content-type: application/json" -d "{ \"greeter\": \"John\" }"
   ```

   1. `?greeter=John`이라는 쿼리 문자열 파라미터와 함께 API를 직접적으로 호출하려면 다음과 같이 합니다.

      ```
      curl -X GET 'https://r275xc9bmd.execute-api.us-east-1.amazonaws.com/test/helloworld?greeter=John'
      ```

   1. `greeter:John`이라는 헤더 파라미터와 함께 API를 직접적으로 호출하려면 다음과 같이 합니다.

      ```
      curl -X GET https://r275xc9bmd.execute-api.us-east-1.amazonaws.com/test/helloworld \
        -H 'content-type: application/json' \
        -H 'greeter: John'
      ```

   1. `{"greeter":"John"}`이라는 본문과 함께 API를 직접적으로 호출하려면 다음과 같이 합니다.

      ```
      curl -X POST https://r275xc9bmd.execute-api.us-east-1.amazonaws.com/test/helloworld \
        -H 'content-type: application/json' \
        -d '{ "greeter": "John" }'
      ```

   이 모든 경우에 출력되는 것은 다음과 같은 응답 본문이 있는 200 응답입니다.

   ```
   Hello, John!
   ```

# 자습서: Lambda 비 프록시 통합을 통해 REST API 생성
<a name="getting-started-lambda-non-proxy-integration"></a>

이 연습에서는 API Gateway 콘솔을 사용하여 클라이언트가 Lambda 비 프록시 통합(사용자 지정 통합이라고도 함)을 통해 Lambda 함수를 호출할 수 있도록 하는 API를 빌드합니다. AWS Lambda 및 Lambda 함수에 대한 자세한 내용은 [AWS Lambda 개발자 안내서](https://docs.aws.amazon.com/lambda/latest/dg/)를 참조하세요.

원활한 학습을 위해 최소 API 설정으로 간단한 Lambda 함수를 선택하여 Lambda 사용자 지정 통합을 통해 API Gateway API를 구축하는 단계를 안내합니다. 필요한 경우 일부 로직에 대해 설명합니다. Lambda 사용자 지정 통합에 대한 자세한 예제는 [튜토리얼: 두 개의 AWS 서비스 통합과 하나의 Lambda 비프록시 통합으로 REST API 생성](integrating-api-with-aws-services-lambda.md)을 참조하십시오.

API를 생성하기 전에 다음에 설명한 대로 AWS Lambda에서 Lambda 함수를 생성하여 Lambda 백엔드를 설정합니다.

**Topics**
+ [Lambda 비 프록시 통합을 위한 Lambda 함수 만들기](#getting-started-new-lambda)
+ [Lambda 비 프록시 통합을 통해 API 생성](#getting-started-new-api)
+ [API 메서드 호출 테스트](#getting-started-new-get)
+ [API 배포](#getting-started-deploy-api)
+ [배포 단계에서 API 테스트](#getting-started-test)
+ [정리](#getting-started-clean-up)

## Lambda 비 프록시 통합을 위한 Lambda 함수 만들기
<a name="getting-started-new-lambda"></a>

**참고**  
Lambda 함수를 생성하면 AWS 계정에 요금이 발생할 수 있습니다.

 이 단계에서는, "Hello, World\$1"와 같은 Lambda 사용자 지정 통합에 대한 Lambda 함수를 생성해 봅니다. 이 연습에서는 `GetStartedLambdaIntegration`이라는 함수가 사용됩니다.

 이 `GetStartedLambdaIntegration` Lambda 함수의 구현은 다음과 같습니다.

------
#### [ Node.js ]

```
'use strict';
var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];            
var times = ['morning', 'afternoon', 'evening', 'night', 'day'];

export const handler = async(event) => {
  console.log(event);
  // Parse the input for the name, city, time and day property values
  let name = event.name === null || event.name === undefined || event.name === "" ? 'you' : event.name;
  let city = event.city === undefined ? 'World' : event.city;
  let time = times.indexOf(event.time)<0 ? 'day' : event.time;
  let day = days.indexOf(event.day)<0 ? null : event.day;

  // Generate a greeting
  let greeting = 'Good ' + time + ', ' + name + ' of ' + city + '. ';
  if (day) greeting += 'Happy ' + day + '!';
  
  // Log the greeting to CloudWatch
  console.log('Hello: ', greeting);
  
  // Return a greeting to the caller
  return {"greeting": greeting}
};
```

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

```
import json

days = {
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday'}
times = {'morning', 'afternoon', 'evening', 'night', 'day'}


def lambda_handler(event, context):
    print(event)
    # parse the input for the name, city, time, and day property values
    name = event.get("name") or 'you'
    city = event.get("city") or 'World'
    try:
        if event['time'] in times:
            time = event['time']
        else:
            time = 'day'
    except KeyError:
        time = 'day'
    try:
        if event['day'] in days:
            day = event['day']
        else:
            day = ''
    except KeyError:
        day = ''
    # Generate a greeting
    greeting = 'Good ' + time + ', ' + name + ' of ' + \
        city + '.' + ['', ' Happy ' + day + '!'][day != '']
    # Log the greeting to CloudWatch
    print(greeting)

    # Return a greeting to the caller
    return {"greeting": greeting}
```

------

Lambda 사용자 지정 통합의 경우 API Gateway에서 입력을 통합 요청 본문으로 클라이언트의 Lambda 함수에 전달합니다. Lambda 함수 핸들러의 `event` 객체는 입력입니다.

Lambda 함수는 간단합니다. `event`, `name`, `city`, `time` 속성에 대한 입력 `day` 객체를 구문 분석합니다. 그런 다음 인사말을 `{"message":greeting}`의 JSON 객체로 호출자에게 반환합니다. 메시지는 `"Good [morning|afternoon|day], [name|you] in [city|World]. Happy day!"` 패턴입니다. Lambda 함수에 대한 입력이 다음 JSON 객체라고 가정합니다.

```
{
  "city": "...",
  "time": "...",
  "day": "...",
  "name" : "..."
}
```

자세한 내용은 [AWS Lambda 개발자 안내서](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html)를 참조하십시오.

또한 이 함수는 `console.log(...)`를 호출하여 실행을 Amazon CloudWatch에 기록합니다. 이는 함수를 디버깅할 때 호출 트레이스에 유용합니다. `GetStartedLambdaIntegration` 함수가 호출을 기록하도록 허용하려면 Lambda 함수가 CloudWatch 스트림을 생성하고 로그 항목을 스트림에 추가할 수 있도록 적절한 정책을 사용하여 IAM 역할을 설정합니다. Lambda 콘솔은 필요한 IAM 역할과 정책을 생성하도록 안내합니다.

API Gateway 콘솔을 사용하지 않고 API를 설정할 경우(예: [OpenAPI 파일에서 API를 가져오는 경우](https://github.com/aws-samples/api-gateway-secure-pet-store/blob/master/src/main/resources/swagger.yaml#L39)) 필요에 따라 API Gateway에서 Lambda 함수를 호출하기 위한 호출 역할 및 정책을 명시적으로 생성하고 설정해야 합니다. API Gateway API에 대한 Lambda 호출 및 실행 역할을 설정하는 방법에 대한 자세한 내용은 [IAM 권한을 사용하여 REST API에 대한 액세스 제어](permissions.md) 단원을 참조하십시오.

 Lambda 프록시 통합에 대한 Lambda 함수인 `GetStartedLambdaProxyIntegration`과 달리 Lambda 사용자 지정 통합에 대한 `GetStartedLambdaIntegration` Lambda 함수는 API Gateway API 통합 요청 본문에서 입력만 가져옵니다. 함수는 JSON 객체, 문자열, 숫자, 부울 또는 심지어 이진 BLOB의 출력을 반환할 수 있습니다. 반대로 Lambda 프록시 통합에 대한 Lambda 함수는 모든 요청 데이터에서 입력을 가져올 수 있지만 특정 JSON 객체의 출력을 반환해야 합니다. API Gateway에서 클라이언트 요청을 백엔드로 전달하기 전에 필요한 API 요청 파라미터를 통합 요청 본문에 매핑하는 경우 Lambda 사용자 지정 통합에 대한 `GetStartedLambdaIntegration` 함수는 API 요청 파라미터를 입력으로 가질 수 있습니다. 이를 위해 API 개발자는 API를 생성할 때 매핑 템플릿을 생성하여 API 메서드에서 구성해야 합니다.

이제 `GetStartedLambdaIntegration` Lambda 함수를 생성합니다.

**Lambda 사용자 지정 통합을 위한 `GetStartedLambdaIntegration` Lambda 함수를 생성하려면**

1. AWS Lambdahttps://console.aws.amazon.com/lambda/[에서 ](https://console.aws.amazon.com/lambda/) 콘솔을 엽니다.

1. 다음 중 하나를 수행하십시오.
   + 시작 페이지가 나타나면 **지금 시작**을 선택한 다음 **함수 만들기**를 선택합니다.
   + **Lambda > 함수(Lambda > Functions)** 목록 페이지가 나타나면 **함수 만들기(Create function)**를 선택합니다.

1. **새로 작성**을 선택합니다.

1. **새로 작성** 창에서 다음과 같이 합니다.

   1. **이름(Name)**에 Lambda 함수 이름으로 **GetStartedLambdaIntegration**을 입력합니다.

   1. **런타임**에서 지원되는 최신 **Node.js** 또는 **Python** 런타임을 선택합니다.

   1. **아키텍처**의 경우 기본 설정을 유지합니다.

   1. **권한(Permissions)**에서 **기본 실행 역할 변경(Change default execution role)**을 확장합니다. **실행 역할** 드롭다운 목록에서 **AWS 정책 템플릿에서 새 역할 생성**을 선택합니다.

   1. **역할 이름**에 역할의 이름을 입력합니다(예: **GetStartedLambdaIntegrationRole**).

   1. **정책 템플릿**에서 **단순 마이크로서비스 권한**을 선택합니다.

   1. **함수 생성**을 선택합니다.

1. **함수 구성** 창의 **Function code(함수 코드)**에서, 다음 필드들을 설정하십시오.

   1. 이 섹션의 시작 부분에 나열된 Lambda 함수 코드를 복사하여 인라인 코드 편집기에 붙여 넣습니다.

   1. 이 섹션의 다른 필드를 모두 기본값으로 그대로 둡니다.

   1. [**Deploy**]를 선택합니다.

1. 새로 생성된 함수를 테스트하려면 **테스트** 탭을 선택합니다.

   1. **이벤트 이름**에 **HelloWorldTest**를 입력합니다.

   1. **이벤트 JSON**에서 기본 코드를 다음과 같이 바꾸십시오.

      ```
      {
        "name": "Jonny",
        "city": "Seattle",
        "time": "morning",
        "day": "Wednesday"
      }
      ```

   1.  **테스트**를 선택하여 함수를 호출합니다. **실행 결과: 성공** 섹션이 표시됩니다. **세부 정보**를 확장하면 다음 출력이 표시됩니다.

      ```
      {
          "greeting": "Good morning, Jonny of Seattle. Happy Wednesday!"
      }
      ```

      출력은 CloudWatch Logs에도 기록됩니다.

 측면 연습으로 IAM 콘솔을 사용하여 Lambda 함수 생성의 일부로 생성된 IAM 역할(`GetStartedLambdaIntegrationRole`)을 볼 수 있습니다. 이 IAM 역할에는 두 개의 인라인 정책이 연결되어 있습니다. 하나는 Lambda 실행을 위해 가장 기본적인 권한을 규정합니다. 이 정책은 Lambda 함수가 생성된 리전에서 계정의 CloudWatch 리소스에 대한 CloudWatch `CreateLogGroup` 호출을 허용합니다. 또한 이 정책을 사용하면 CloudWatch 스트림을 생성하고 `GetStartedLambdaIntegration` Lambda 함수에 대한 이벤트를 기록할 수 있습니다.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:us-east-1:111111111111:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:111111111111:log-group:/aws/lambda/GetStartedLambdaIntegration:*"
            ]
        }
    ]
}
```

------

다른 정책 문서는 이 예제에서 사용되지 않은 다른 AWS 서비스를 호출하는 데 적용됩니다. 지금은 건너뛸 수 있습니다.

 IAM 역할에는 `lambda.amazonaws.com`인 신뢰할 수 있는 엔터티가 연결되어 있습니다. 다음은 신뢰 관계입니다.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

------

 이 신뢰 관계와 인라인 정책을 조합하면 Lambda 함수가 `console.log()` 함수를 호출하여 이벤트를 CloudWatch Logs에 기록할 수 있습니다.

## Lambda 비 프록시 통합을 통해 API 생성
<a name="getting-started-new-api"></a>

 Lambda 함수(`GetStartedLambdaIntegration`)가 생성 및 테스트되면 API Gateway API를 통해 함수를 공개할 준비가 된 것입니다. 설명을 위해 일반 HTTP 메서드를 사용하여 Lambda 함수를 공개합니다. 요청 본문, URL 경로 변수, 쿼리 문자열 및 헤더를 사용하여 클라이언트로부터 필수 입력 데이터를 수신합니다. API에 대한 API Gateway 요청 검사기를 설정하여 모든 필수 데이터가 올바르게 정의되고 지정되었는지 확인합니다. 백엔드 Lambda 함수에 따라 클라이언트가 제공한 요청 데이터를 유효한 형식으로 변환하도록 API Gateway에 대한 매핑 템플릿을 구성합니다.

**Lambda 비 프록시 통합을 통해 API를 생성하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API Gateway를 처음 사용하는 경우, 서비스의 기능을 소개하는 페이지가 나타납니다. **REST API**에서 **빌드**를 선택합니다. **예제 API 생성** 팝업이 나타나면 **확인**을 선택합니다.

   API Gateway를 처음 사용하는 것이 아닌 경우 **API 생성**을 선택합니다. **REST API**에서 **빌드**를 선택합니다.

1.  **API 이름**에서 **LambdaNonProxyAPI**을 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **API 엔드포인트 유형** 설정을 **지역**으로 유지합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **API 생성**을 선택합니다.

API를 생성한 후에는 **/\$1city\$1** 리소스를 생성합니다. 이는 클라이언트에서 입력을 가져오는 경로 변수를 포함하는 리소스의 예입니다. 나중에 이 경로 변수를 매핑 템플릿을 사용하여 Lambda 함수 입력에 매핑합니다.

**리소스를 생성하려면**

1. **리소스 생성**을 선택합니다.

1. **프록시 리소스**는 꺼진 상태로 둡니다.

1. **리소스 경로**를 `/`로 유지합니다.

1. **리소스 이름**에 **\$1city\$1**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

**/\$1city\$1** 리소스를 생성한 후에는 `ANY` 메서드를 생성합니다. `ANY` HTTP 동사는 클라이언트가 런타임에 제출하는 유효한 HTTP 메서드의 자리 표시자입니다. 이 예제에서는 Lambda 사용자 지정 통합뿐만 아니라 Lambda 프록시 통합에 사용할 수 있는 `ANY` 메서드를 보여줍니다.

**`ANY` 메서드를 생성하려면**

1. **/\$1city\$1** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **ANY**를 선택합니다.

1. **통합 유형**에서 **Lambda 함수**를 선택합니다.

1. **Lambda 프록시 통합**을 비활성화된 상태로 유지합니다.

1. **Lambda 함수**에서 Lambda 함수를 생성한 AWS 리전을 선택하고 함수 이름을 입력합니다.

1. **메서드 요청 설정**을 선택합니다.

   이제 URL 경로 변수, 쿼리 문자열 파라미터 및 헤더에 대한 요청 유효성 검사기를 켜서 필요한 모든 데이터가 정의되었는지 확인합니다. 이 예시에서는 `time` 쿼리 문자열 파라미터와 `day` 헤더를 생성합니다.

1. **요청 검사기**에서 **쿼리 문자열 파라미터 및 헤더 검사**를 선택합니다.

1. **URL 쿼리 문자열 파라미터**를 선택하고 다음을 수행합니다.

   1. **쿼리 문자열 추가(Add query string)**를 선택합니다.

   1. **이름**에 **time**를 입력합니다.

   1. **필수**를 끕니다.

   1. **캐싱**을 꺼진 상태로 둡니다.

1. **HTTP 요청 헤더**를 선택하고 다음을 수행합니다.

   1. **헤더 추가(Add header)**를 선택합니다.

   1. **이름**에 **day**를 입력합니다.

   1. **필수**를 끕니다.

   1. **캐싱**을 꺼진 상태로 둡니다.

1. **메서드 생성**을 선택합니다.

요청 검사기를 활성화한 후에는 백엔드 Lambda 함수에 필요한 대로 수신된 요청을 JSON 페이로드로 변환하는 본문 매핑 템플릿을 추가하여 `ANY` 메서드에 대한 통합 요청을 구성합니다.

**통합 요청을 구성하려면**

1. **통합 요청** 탭의 **통합 요청 설정**에서 **편집**을 선택합니다.

1. **요청 본문 패스스루**에서 **정의된 템플릿이 없는 경우(권장)**를 선택합니다.

1. **매핑 템플릿**을 선택합니다.

1. **매핑 템플릿 추가(Add mapping template)**를 선택합니다.

1. **콘텐츠 유형**에 **application/json**을 입력합니다.

1. **템플릿 본문**에 다음 코드를 입력합니다.

   ```
   #set($inputRoot = $input.path('$'))
   {
     "city": "$input.params('city')",
     "time": "$input.params('time')",
     "day":  "$input.params('day')",
     "name": "$inputRoot.callerName"
   }
   ```

1. **저장**을 선택합니다.

## API 메서드 호출 테스트
<a name="getting-started-new-get"></a>

 API Gateway 콘솔은 배포되기 전에 API 호출을 테스트할 수 있는 테스트 기능을 제공합니다. 콘솔의 테스트 기능을 사용하여 다음 요청을 제출하는 방식으로 API를 테스트합니다.

```
POST /Seattle?time=morning
day:Wednesday

{
    "callerName": "John"
}
```

 이 테스트 요청에서는 `ANY`를 `POST`로 설정하고 `{city}`를 `Seattle`로 설정하며 `Wednesday`를 `day` 헤더 값으로 할당하고 `"John"`을 `callerName` 값으로 할당합니다.

**`ANY` 메서드를 테스트하는 방법**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **메서드 유형**에서 `POST`를 선택합니다.

1. **경로**의 **city**에 **Seattle**을 입력합니다.

1. **쿼리 문자열**에 **time=morning**를 입력합니다.

1. **헤더**에 **day:Wednesday**를 입력합니다.

1. **요청 본문**에 **\$1 "callerName": "John" \$1**을 입력합니다.

1. **테스트**를 선택합니다.

반환된 응답 페이로드가 다음과 같은지 확인합니다.

```
{
  "greeting": "Good morning, John of Seattle. Happy Wednesday!"
}
```

로그를 보고 API Gateway에서 요청 및 응답을 처리하는 방식을 알아볼 수도 있습니다.

```
Execution log for request test-request
Thu Aug 31 01:07:25 UTC 2017 : Starting execution for request: test-invoke-request
Thu Aug 31 01:07:25 UTC 2017 : HTTP Method: POST, Resource Path: /Seattle
Thu Aug 31 01:07:25 UTC 2017 : Method request path: {city=Seattle}
Thu Aug 31 01:07:25 UTC 2017 : Method request query string: {time=morning}
Thu Aug 31 01:07:25 UTC 2017 : Method request headers: {day=Wednesday}
Thu Aug 31 01:07:25 UTC 2017 : Method request body before transformations: { "callerName": "John" }
Thu Aug 31 01:07:25 UTC 2017 : Request validation succeeded for content type application/json
Thu Aug 31 01:07:25 UTC 2017 : Endpoint request URI: https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:GetStartedLambdaIntegration/invocations
Thu Aug 31 01:07:25 UTC 2017 : Endpoint request headers: {x-amzn-lambda-integration-tag=test-request, Authorization=****************************************************************************************************************************************************************************************************************************************************************************************************************************************338c72, X-Amz-Date=20170831T010725Z, x-amzn-apigateway-api-id=beags1mnid, X-Amz-Source-Arn=arn:aws:execute-api:us-west-2:123456789012:beags1mnid/null/POST/{city}, Accept=application/json, User-Agent=AmazonAPIGateway_beags1mnid, X-Amz-Security-Token=FQoDYXdzELL//////////wEaDMHGzEdEOT/VvGhabiK3AzgKrJw+3zLqJZG4PhOq12K6W21+QotY2rrZyOzqhLoiuRg3CAYNQ2eqgL5D54+63ey9bIdtwHGoyBdq8ecWxJK/YUnT2Rau0L9HCG5p7FC05h3IvwlFfvcidQNXeYvsKJTLXI05/yEnY3ttIAnpNYLOezD9Es8rBfyruHfJfOqextKlsC8DymCcqlGkig8qLKcZ0hWJWVwiPJiFgL7laabXs++ZhCa4hdZo4iqlG729DE4gaV1mJVdoAagIUwLMo+y4NxFDu0r7I0/EO5nYcCrppGVVBYiGk7H4T6sXuhTkbNNqVmXtV3ch5bOlh7 [TRUNCATED]
Thu Aug 31 01:07:25 UTC 2017 : Endpoint request body after transformations: {
  "city": "Seattle",
  "time": "morning",
  "day": "Wednesday",
  "name" : "John"
}
Thu Aug 31 01:07:25 UTC 2017 : Sending request to https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:GetStartedLambdaIntegration/invocations
Thu Aug 31 01:07:25 UTC 2017 : Received response. Integration latency: 328 ms
Thu Aug 31 01:07:25 UTC 2017 : Endpoint response body before transformations: {"greeting":"Good morning, John of Seattle. Happy Wednesday!"}
Thu Aug 31 01:07:25 UTC 2017 : Endpoint response headers: {x-amzn-Remapped-Content-Length=0, x-amzn-RequestId=c0475a28-8de8-11e7-8d3f-4183da788f0f, Connection=keep-alive, Content-Length=62, Date=Thu, 31 Aug 2017 01:07:25 GMT, X-Amzn-Trace-Id=root=1-59a7614d-373151b01b0713127e646635;sampled=0, Content-Type=application/json}
Thu Aug 31 01:07:25 UTC 2017 : Method response body after transformations: {"greeting":"Good morning, John of Seattle. Happy Wednesday!"}
Thu Aug 31 01:07:25 UTC 2017 : Method response headers: {X-Amzn-Trace-Id=sampled=0;root=1-59a7614d-373151b01b0713127e646635, Content-Type=application/json}
Thu Aug 31 01:07:25 UTC 2017 : Successfully completed execution
Thu Aug 31 01:07:25 UTC 2017 : Method completed with status: 200
```

로그는 매핑 전에 수신되는 요청과 매핑 후 통합 요청을 보여줍니다. 테스트가 실패하면 로그는 원래 입력이 올바르거나 매핑 템플릿이 올바르게 작동하는지 여부를 평가하는 데 유용합니다.

## API 배포
<a name="getting-started-deploy-api"></a>

 테스트 호출은 시뮬레이션이며 제한이 있습니다. 예를 들어 테스트 호출은 API에서 제정된 권한 부여 메커니즘을 우회합니다. 실시간으로 API 실행을 테스트하려면 먼저 API를 배포해야 합니다. API를 배포하려면 그 시점에 API의 스냅샷을 생성하는 단계를 생성합니다. 단계 이름은 API의 기본 호스트 이름 뒤에 기본 경로도 정의합니다. API의 루트 리소스는 단계 이름 뒤에 추가됩니다. API를 수정할 경우 변경 사항이 적용되기 전에 API를 새 단계 또는 기존 단계에 다시 배포해야 합니다.

**API를 단계에 배포하려면**

1. **Deploy API(API 배포)**를 선택합니다.

1. **스테이지**에서 **새 스테이지**를 선택합니다.

1. **단계 이름**에 **test**를 입력합니다.
**참고**  
입력은 UTF-8로 인코딩된(현지화되지 않은) 텍스트여야 합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **배포(Deploy)**를 선택합니다.

**스테이지 세부 정보**에서 복사 아이콘을 선택하여 API의 호출 URL을 복사합니다. API 기본 URL의 일반적인 패턴은 `https://api-id.region.amazonaws.com/stageName`입니다. 예를 들어 `beags1mnid` 리전에서 생성되고 `us-west-2` 단계에 배포된 API(`test`)의 기본 URL은 `https://beags1mnid.execute-api.us-west-2.amazonaws.com/test`입니다.

## 배포 단계에서 API 테스트
<a name="getting-started-test"></a>

배포된 API를 테스트할 수 있는 방법에는 여러 가지가 있습니다. URL 경로 변수 또는 쿼리 문자열 파라미터만 사용하는 GET 요청의 경우 브라우저에 API 리소스 URL을 입력할 수 있습니다. 다른 메서드의 경우 [POSTMAN](https://www.postman.com/) 또는 [cURL](https://curl.se/) 등의 고급 REST API 테스트 유틸리티를 사용해야 합니다.

**cURL을 사용하여 API를 테스트하려면**

1. 인터넷에 연결된 로컬 컴퓨터에서 터미널 창을 엽니다.

1. `POST /Seattle?time=evening`을 테스트하려면 다음을 수행합니다.

   다음 cURL 명령을 복사하여 터미널 창에 붙여 넣습니다.

   ```
   curl -v -X POST \
     'https://beags1mnid.execute-api.us-west-2.amazonaws.com/test/Seattle?time=evening' \
     -H 'content-type: application/json' \
     -H 'day: Thursday' \
     -H 'x-amz-docs-region: us-west-2' \
     -d '{
   	"callerName": "John"
   }'
   ```

   다음 페이로드와 함께 성공적인 응답을 받아야 합니다.

   ```
   {"greeting":"Good evening, John of Seattle. Happy Thursday!"}
   ```

   이 메서드 요청에서 `POST`를 `PUT`으로 변경할 경우 동일한 응답을 받습니다.

## 정리
<a name="getting-started-clean-up"></a>

이제 이 연습을 위해 생성한 Lambda 함수가 더 이상 필요하지 않은 경우 해당 함수를 삭제할 수 있습니다. 함께 제공되는 IAM 리소스도 삭제할 수 있습니다.

**주의**  
이 시리즈의 다른 연습을 완료하려면 Lambda 실행 역할 또는 Lambda 호출 역할을 삭제하지 마십시오. API가 의존하는 Lambda 함수를 삭제할 경우 해당 API가 더 이상 작동하지 않습니다. Lambda 함수 삭제는 실행 취소할 수 없습니다. Lambda 함수를 다시 사용하려면 함수를 재생성해야 합니다.  
Lambda 함수가 의존하는 IAM 리소스를 삭제할 경우 Lambda 함수가 더 이상 작동하지 않습니다. 따라서 해당 함수에 의존하는 모든 API가 더 이상 작동하지 않게 됩니다. IAM 리소스 삭제는 실행 취소할 수 없습니다. IAM 리소스를 다시 사용하려면 리소스를 재생성해야 합니다.

**Lambda 함수를 삭제하려면**

1. AWS Management Console에 로그인하고 AWS Lambdahttps://console.aws.amazon.com/lambda/[에서 ](https://console.aws.amazon.com/lambda/) 콘솔을 엽니다.

1. 함수 목록에서 **GetStartedLambdaIntegration**을 선택하고 **작업**을 선택한 다음 **함수 삭제**를 선택합니다. 확인 메시지가 나타나면 **삭제**를 다시 선택합니다.

**연결된 IAM 리소스를 삭제하려면**

1. [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)에서 IAM 콘솔을 엽니다.

1. **세부 정보**에서 **역할**을 선택합니다.

1. 역할 목록에서 **GetStartedLambdaIntegrationRole**을 선택하고 **역할 작업**을 선택한 다음 **역할 삭제**를 선택합니다. 콘솔의 단계에 따라 역할을 삭제합니다.

# 자습서: 교차 계정 Lambda 프록시 통합을 통해 REST API 생성
<a name="apigateway-cross-account-lambda-integrations"></a>

이제는 다른 AWS Lambda 계정의 AWS 함수도 API 통합 백엔드로 사용할 수 있습니다. 각 계정은 Amazon API Gateway를 사용할 수 있는 모든 리전에 존재할 수 있습니다. 따라서 여러 API에 대해 Lambda 백엔드 함수를 중앙에서 손쉽게 관리 및 공유할 수 있습니다.

이 단원에서는 Amazon API Gateway 콘솔을 사용하여 교차 계정 Lambda 프록시 통합을 구성하는 방법을 보여줍니다.

## API Gateway 교차 계정 Lambda 통합을 위한 API 생성
<a name="apigateway-cross-account-lambda-integrations-create-api"></a>

**API를 생성하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API Gateway를 처음 사용하는 경우, 서비스의 기능을 소개하는 페이지가 나타납니다. **REST API**에서 **빌드**를 선택합니다. **예제 API 생성** 팝업이 나타나면 **확인**을 선택합니다.

   API Gateway를 처음 사용하는 것이 아닌 경우 **API 생성**을 선택합니다. **REST API**에서 **빌드**를 선택합니다.

1.  **API 이름**에서 **CrossAccountLambdaAPI**을 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **API 엔드포인트 유형** 설정을 **지역**으로 유지합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **API 생성**을 선택합니다.

## 다른 계정으로 Lambda 통합 함수 생성
<a name="apigateway-cross-account-lambda-integrations-create-lambda-function"></a>

이제, 예제 API를 생성한 환경에서 다른 계정으로 Lambda 함수를 만들어 보겠습니다.

**다른 계정으로 Lambda 함수 생성**

1. API Gateway API를 생성한 환경에서 다른 계정으로 Lambda 콘솔에 로그인합니다.

1. **함수 생성**을 선택합니다.

1. **새로 작성**을 선택합니다.

1. **새로 작성**에서 다음 작업을 수행합니다.

   1. **함수 이름**에 이름을 입력합니다.

   1. **런타임** 드롭다운 목록에서 지원되는 Node.js 런타임을 선택합니다.

   1. **아키텍처**의 경우 기본 설정을 유지합니다.

   1. **권한**에서 **실행 역할 선택 또는 생성**을 확장합니다. 역할을 만들거나 기존 역할을 선택할 수 있습니다.

   1. **함수 생성**을 선택하여 계속 진행합니다.

1. 아래로 스크롤하여 **함수 코드(Function code)** 창을 찾습니다.

1. [자습서: Lambda 프록시 통합을 통해 REST API 생성](api-gateway-create-api-as-simple-proxy-for-lambda.md)에서 Node.js 함수 구현을 입력합니다.

1. [**Deploy**]를 선택합니다.

1. 함수의 정식 ARN을 기록해 둡니다(Lambda 함수 창의 오른쪽 위에). 이것은 나중에 교차 계정 Lambda 통합을 생성할 때 필요합니다.

## 교차 계정 Lambda 통합 구성
<a name="apigateway-cross-account-lambda-integrations-create-integration2"></a>

다른 계정으로 Lambda 통합 함수를 생성하면 API Gateway 콘솔을 사용하여 이를 첫 번째 계정의 API에 추가할 수 있습니다.

**참고**  
교차 리전, 교차 계정 권한 부여자를 구성할 때 대상 함수에 추가된 `sourceArn`은 API의 리전이 아닌 함수에 포함된 리전을 사용합니다.

API를 생성한 후에는 리소스를 생성합니다. 일반적으로 API 리소스는 애플리케이션 로직에 따른 리소스 트리로 정리되어 있습니다. 이 예시에서는 **/helloworld** 리소스를 생성합니다.

**리소스를 생성하려면**

1. **리소스 생성**을 선택합니다.

1. **프록시 리소스**는 꺼진 상태로 둡니다.

1. **리소스 경로**를 `/`로 유지합니다.

1. **리소스 이름**에 **helloworld**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

리소스를 생성한 후 `GET` 메서드를 생성합니다. 다른 계정으로 Lambda 함수와 `GET` 메서드를 통합합니다.

**`GET` 메서드를 생성하는 방법**

1. **/helloworld** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **GET**을 선택합니다.

1. **통합 유형**에서 **Lambda 함수**를 선택합니다.

1. **Lambda 프록시 통합**을 켭니다.

1. **Lambda** 함수에, 1단계에서 입력한 Lambda 함수의 전체 ARN을 입력합니다.

   Lambda 콘솔 창의 오른쪽 위 모서리에서 함수의 ARN을 찾을 수 있습니다.

1. ARN을 입력하면 `aws lambda add-permission` 명령 문자열이 나타납니다. 이 정책은 첫 번째 계정이 두 번째 계정의 Lambda 함수에 액세스할 수 있는 권한을 부여합니다. `aws lambda add-permission` 명령 문자열을 복사해 두 번째 계정에 대해 구성된 AWS CLI 창에 붙여 넣습니다.

1. **메서드 생성**을 선택합니다.

Lambda 콘솔에서 함수에 대해 업데이트된 정책을 확인할 수 있습니다.

**(선택 사항) 업데이트된 정책을 보려면**

1. AWS Management Console에 로그인하고 [https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)에서 AWS Lambda 콘솔을 엽니다.

1. Lambda 함수를 선택합니다.

1. **Permissions**를 선택합니다.

   `Allow`이 API `Condition` 메서드에 대한 ARN인 `AWS:SourceArn` 절이 포함된 `GET` 정책이 표시되어야 합니다.

# 자습서: 예제를 가져와 REST API 생성
<a name="api-gateway-create-api-from-example"></a>

Amazon API Gateway 콘솔을 사용하여 PetStore 웹 사이트에 대한 HTTP 통합으로 간단한 REST API를 생성 및 테스트할 수 있습니다. API 정의는 OpenAPI 2.0 파일로 미리 구성되어 있습니다. API 정의를 API Gateway로 로드한 후 API Gateway 콘솔을 사용하여 API의 기본 구조를 검사하거나 API를 간단히 배포 및 테스트할 수 있습니다.

 PetStore 예제 API는 클라이언트가 HTTP 백엔드 웹 사이트 `http://petstore-demo-endpoint.execute-api.com/petstore/pets`에 액세스할 수 있도록 다음 메서드를 지원합니다.

**참고**  
이 튜토리얼에서는 HTTP 엔드포인트를 예로 사용합니다. 자체 API를 생성할 때는 HTTP 통합에 HTTPS 엔드포인트를 사용하는 것이 좋습니다.
+ `GET /`: 백엔드 엔드포인트와 통합되지 않은 API의 루트 리소스에 대한 읽기 액세스용입니다. API Gateway는 PetStore 웹 사이트의 개요로 응답합니다. 이는 `MOCK` 통합 유형의 예제입니다.
+ `GET /pets`: 비슷한 이름의 백엔드 `/pets` 리소스와 통합된 API의 `/pets` 리소스에 대한 읽기 액세스용입니다. 백엔드는 PetStore에서 사용 가능한 반려 동물의 페이지를 반환합니다. 이는 `HTTP` 통합 유형의 예제입니다. 통합 엔드포인트의 URL은 `http://petstore-demo-endpoint.execute-api.com/petstore/pets`입니다.
+ `POST /pets`: 백엔드 `/pets` 리소스와 통합된 API의 `/petstore/pets` 리소스에 대한 쓰기 액세스용입니다. 올바른 요청을 수신하면 백엔드는 지정된 반려 동물을 PetStore에 추가하고 결과를 호출자에게 반환합니다. 통합은 `HTTP`이기도 합니다.
+ `GET /pets/{petId}`: 수신되는 요청 URL의 경로 변수로 지정된 `petId` 값으로 식별되는 반려 동물에 대한 읽기 액세스용입니다. 이 메서드에는 `HTTP` 통합 유형도 있습니다. 백엔드는 PetStore에 있는 지정된 반려 동물을 반환합니다. 백엔드 HTTP 엔드포인트의 URL은 `http://petstore-demo-endpoint.execute-api.com/petstore/pets/n`이며 여기서 `n`은 쿼리된 반려 동물의 식별자로서 정수입니다.

 API는 `OPTIONS` 통합 유형의 `MOCK` 메서드를 통해 CORS 액세스를 지원합니다. API Gateway는 CORS 액세스를 지원하는 필수 헤더를 반환합니다.

다음 절차에서는 API Gateway 콘솔을 사용하여 예제 API를 생성하고 테스트하는 단계를 안내합니다.

**예제 API를 가져와서 구축 및 테스트하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. 다음 중 하나를 수행합니다.
   + 첫 번째 API를 생성하려면 **REST API**에서 **빌드**를 선택합니다.
   + 이전에 API를 생성한 경우 **API 생성**을 선택한 다음 **REST API**에서 **빌드**를 선택합니다.

1.  **REST API 생성**에서 **예제 API**를 선택한 다음 **API 생성**을 선택하여 예제 API를 생성합니다.

      
![\[API Gateway 콘솔의 예시 REST API입니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-new-console.png)

    **API 생성**을 선택하기 전에 OpenAPI 정의를 아래로 스크롤하여 이 예제 API의 세부 정보를 확인할 수 있습니다.

1. 기본 탐색 창에서 **리소스**를 선택합니다. 새로 생성한 API는 다음과 같이 표시됩니다.

      
![\[API Gateway 콘솔로 가져온 후의 예시 API입니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-result-new-console.png)

    **리소스** 창은 생성된 API의 구조를 노드 트리 형태로 보여 줍니다. 각 리소스에 정의된 API 메서드가 트리의 엣지입니다. 리소스를 선택하면 모든 메서드가 우측의 **방법** 테이블에 나열됩니다. 각 메서드와 함께 메서드 유형, 통합 유형, 권한 부여 유형 및 API 키 요구 사항이 표시됩니다.

1.  메서드의 세부 정보를 보거나 메서드 설정을 수정하거나 메서드 호출을 테스트하려면, 메서드 목록이나 리소스 트리에서 메서드 이름을 선택합니다. 여기에서는 그림과 같이 `POST /pets` 메서드를 선택합니다.

      
![\[API Gateway 콘솔의 예시 API에 대한 POST/pets 메서드입니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-post-method-execution-new-console.png)

    결과로 나타나는 **메서드 실행** 창은 선택된 (`POST /pets`) 메서드의 구조 및 동작에 대한 논리적인 뷰를 보여줍니다.

   **메서드 요청** 및 **메서드 응답**은 API와 프런트엔드 간의 인터페이스를 나타내며, **통합 요청** 및 **통합 응답**은 API와 백엔드 간의 인터페이스를 나타냅니다.

    클라이언트는 API를 사용하여 **메서드 요청**을 통해 백엔드 기능에 액세스합니다. 필요할 경우 수신되는 요청을 백엔드에 전달하기 전에 API Gateway가 **통합 요청**에서 클라이언트 요청을 백엔드가 수용할 수 있는 형태로 변환합니다. 변환된 요청을 통합 요청이라고 합니다. 마찬가지로 백엔드는 **통합 응답**에서 응답을 API Gateway로 반환합니다. 그런 다음 API Gateway가 **메서드 응답**을 라우팅한 후에 클라이언트로 전송합니다. 필요한 경우 API Gateway는 백엔드 응답 데이터를 클라이언트가 기대하는 형태로 변환할 수 있습니다.

    API 리소스에서의 `POST` 메서드의 경우, 메서드 요청의 페이로드가 통합 요청의 페이로드와 같은 형식인 경우 메서드 요청 페이로드를 수정 없이 통합 요청에 전달할 수 있습니다.

   `GET /` 메서드 요청은 `MOCK` 통합 유형을 사용하며 실제 백엔드 엔드포인트에 연동되지 않습니다. 해당 **통합 응답**을 설정하여 정적인 HTML 페이지를 반환합니다. 메서드가 호출되면 API Gateway가 요청을 단순히 수용하고 구성된 통합 요청을 **메서드 응답** 방식으로 클라이언트에 즉시 반환합니다. 모의 통합을 사용하여 백엔드 엔드포인트를 요구하지 않고 API를 테스트할 수 있습니다. 응답 본문 매핑 템플릿에서 생성된 로컬 응답도 모의 통합을 사용하여 제공할 수 있습니다.

   API 개발자는 메서드 요청 및 메서드 응답을 구성하여 API의 프런트엔드 상호 작용의 동작을 제어합니다. API의 백엔드 상호 작용 동작은 통합 요청 및 통합 응답을 설정하여 제어합니다. 여기에는 메서드와 해당 통합 간의 데이터 매핑 작업이 수반됩니다. 지금은 API의 종단 간 사용자 경험을 테스트하는 데 중점을 두겠습니다.

1.  **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1.  예를 들어, `POST /pets` 메서드를 테스트하려면 다음의 **\$1"type": "dog","price": 249.99\$1** 페이로드를 **요청 본문**에 입력한 후 **테스트**를 선택합니다.

      
![\[API Gateway 콘솔에서 POST 메서드를 테스트합니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-post-method-test-new-console.png)

    이 입력은 PetStore 웹 사이트 상의 반려 동물 목록에 추가하려는 반려 동물의 속성을 지정합니다.

1. 결과는 다음과 같습니다.

      
![\[API Gateway 콘솔에서 POST 메서드를 테스트한 결과입니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-post-method-test-result-new-console.png)

    출력의 **로그** 항목은 메서드 요청에서 통합 요청으로, 그리고 통합 응답에서 메서드 응답으로의 상태 변화를 나타냅니다. 이는 요청 실패를 야기하는 매핑 오류 문제를 해결하는 데 유용할 수 있습니다. 이 예제에서는 어떤 매핑도 적용되지 않습니다. 즉, 메서드 요청 페이로드가 통합 요청을 통해 백엔드로 전달되고, 마찬가지로 백엔드 응답은 통합 응답을 통해 메서드 응답으로 전달됩니다.

    API Gateway의 테스트-호출-요청 기능 이외의 클라이언트를 사용하여 API를 테스트하려면 우선 API를 단계에 배포해야 합니다.

1.  샘플 API를 배포하려면 **API 배포**를 선택합니다.

      
![\[API 호출자가 API를 간접적으로 호출할 수 있도록 배포 버튼을 사용하여 API를 배포합니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/api-gateway-create-api-by-importing-example-deploy-api-new-console.png)

1. **스테이지**에서 **새 스테이지**를 선택한 다음 **test**를 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **배포(Deploy)**를 선택합니다.

1.  그 결과 표시되는 **스테이지** 창의 **스테이지 세부 정보** 아래 **URL 호출**에 API의 `GET /` 메서드 요청을 호출하는 URL이 표시됩니다.  
![\[REST API를 생성하면 콘솔에 API의 호출 URL이 표시됩니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/getting-started-rest-invoke-url.png)

1. 복사 아이콘을 선택해 API의 호출 URL을 복사하여 웹 브라우저에 입력합니다. 올바른 응답은 통합 응답에서 매핑 템플릿에 의해 생성된 결과를 반환합니다.

1.  **Stages(단계)** 탐색 창에서 **테스트** 단계를 확장하고 `/pets/{petId}`에 대한 **GET**을 선택한 다음, `https://api-id.execute-api.region.amazonaws.com/test/pets/{petId}`의 **Invoke URL(URL 호출)** 값을 복사합니다. `{petId}`는 경로 변수를 나타냅니다.

    **URL 호출(Invoke URL)** 값(이전 단계에서 복사한 값)을 브라우저의 주소 표시줄에 붙여 넣어 `{petId}`을 `1`(예)로 대체한 다음 엔터 키를 눌러 요청을 제출합니다. 200 OK 응답이 다음의 JSON 페이로드와 함께 반환되어야 합니다.

   ```
   {
     "id": 1,
     "type": "dog",
     "price": 249.99
   }
   ```

    그림에서와 같이 API 메서드 호출이 가능한데, **권한 부여(Authorization)** 유형이 `NONE`으로 설정되어 있기 때문입니다. `AWS_IAM` 권한 부여가 사용되었다면 [Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html)(SigV4) 또는 [Signature Version 4a](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html#how-sigv4a-works)(SigV4a) 프로토콜을 사용하여 요청에 서명해야 합니다. 이러한 요청의 예는 [자습서: HTTP 비 프록시 통합을 통해 REST API 생성](api-gateway-create-api-step-by-step.md)을 참조하십시오.

# HTTP 통합 튜토리얼 선택
<a name="getting-started-http-integrations"></a>

 HTTP 통합을 사용하여 API를 구축하기 위해 HTTP 프록시 통합 또는 HTTP 사용자 지정 통합을 사용할 수 있습니다.

HTTP 프록시 통합에서는 백엔드 요구 사항에 따라 HTTP 메서드 및 HTTP 엔드포인트 URI를 설정하기만 하면 됩니다. 간소화된 API 설정을 활용할 수 있도록 가능하면 HTTP 프록시 통합을 사용하는 것이 좋습니다.

백엔드에 대한 클라이언트 요청 데이터를 변환하거나 클라이언트에 대한 백엔드 응답 데이터를 변환해야 하는 경우 HTTP 사용자 지정 통합을 사용할 수 있습니다.

**Topics**
+ [자습서: HTTP 프록시 통합을 통해 REST API 생성](api-gateway-create-api-as-simple-proxy-for-http.md)
+ [자습서: HTTP 비 프록시 통합을 통해 REST API 생성](api-gateway-create-api-step-by-step.md)

# 자습서: HTTP 프록시 통합을 통해 REST API 생성
<a name="api-gateway-create-api-as-simple-proxy-for-http"></a>

HTTP 프록시 통합은 웹 애플리케이션이 단일 HTTP 메서드의 간소화된 설정을 통해 전체 웹 사이트와 같은 통합된 HTTP 엔드포인트의 여러 리소스 또는 기능에 액세스할 수 있도록 하는 API를 구축하기 위한 간단하고 강력한 다목적 메커니즘입니다. HTTP 프록시 통합에서 API Gateway는 클라이언트가 제출한 메서드 요청을 백엔드로 전달합니다. 전달된 요청 데이터에는 요청 헤더, 쿼리 문자열 파라미터, URL 경로 변수 및 페이로드가 포함되어 있습니다. 백엔드 HTTP 엔드포인트 또는 웹 서버는 수신되는 요청 데이터를 구문 분석하여 반환하는 응답을 결정합니다. HTTP 프록시 통합을 통해 클라이언트 및 백엔드가 API 메서드가 설정된 후 API Gateway의 개입 없이 직접 상호 작용할 수 있습니다. 단, [Amazon API Gateway 중요 정보](api-gateway-known-issues.md)에 나열된 지원되지 않는 문자 등 알려진 문제점의 경우는 예외입니다.

포괄적인 프록시 리소스 `{proxy+}` 및 HTTP 메서드에 대한 catch-all `ANY` 동사를 사용하면 HTTP 프록시 통합을 통해 단일 API 메서드의 API를 생성할 수 있습니다. 메서드는 공개적으로 액세스 가능한 HTTP 리소스의 전체 집합 및 웹 사이트의 작업을 공개합니다. 백엔드 웹 서버가 퍼블릭 액세스를 위해 더 많은 리소스를 열면 클라이언트는 동일한 API 설정으로 이러한 새 리소스를 사용할 수 있습니다. 이렇게 하려면 웹 사이트 개발자는 새 리소스와 각 리소스에 적용 가능한 작업을 클라이언트 개발자에게 정확히 알려야 합니다.



다음 자습서에서는 HTTP 프록시 통합을 간략하게 소개합니다. 자습서에서는 API Gateway 콘솔을 사용해 API를 생성하여 일반 프록시 리소스 `{proxy+}`를 통해 PetStore 웹 사이트와 통합하고 `ANY`의 HTTP 메서드 자리 표시자를 생성합니다.

**Topics**
+ [API Gateway 콘솔을 사용하여 HTTP 프록시 통합을 통해 API 생성](#api-gateway-create-api-as-simple-proxy-for-http-build)
+ [HTTP 프록시 통합을 사용하여 API 테스트](#api-gateway-create-api-as-simple-proxy-for-http-test)

## API Gateway 콘솔을 사용하여 HTTP 프록시 통합을 통해 API 생성
<a name="api-gateway-create-api-as-simple-proxy-for-http-build"></a>

 다음 절차에서는 API Gateway 콘솔을 사용하여 프록시 리소스를 통해 HTTP 백엔드에 대한 API를 생성한 후 테스트하는 단계를 안내합니다. HTTP 백엔드는 `PetStore`의 `http://petstore-demo-endpoint.execute-api.com/petstore/pets` 웹 사이트([자습서: HTTP 비 프록시 통합을 통해 REST API 생성](api-gateway-create-api-step-by-step.md))이며 스크린샷은 API Gateway UI 요소를 보여주기 위한 시각적 보조 도구로 사용됩니다. 처음으로 API Gateway 콘솔을 사용하여 API를 생성하는 경우 먼저 해당 섹션을 따를 수 있습니다.

**API를 생성하는 방법**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API Gateway를 처음 사용하는 경우, 서비스의 기능을 소개하는 페이지가 나타납니다. **REST API**에서 **빌드**를 선택합니다. **예제 API 생성** 팝업이 나타나면 **확인**을 선택합니다.

   API Gateway를 처음 사용하는 것이 아닌 경우 **API 생성**을 선택합니다. **REST API**에서 [**빌드**]를 선택합니다.

1.  **API 이름**에서 **HTTPProxyAPI**을 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **API 엔드포인트 유형** 설정을 **지역**으로 유지합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **API 생성**을 선택합니다.

이 단계에서는 `{proxy+}`의 프록시 리소스 경로를 생성합니다. 이는 `http://petstore-demo-endpoint.execute-api.com/` 아래 백엔드 엔드포인트의 자리 표시자입니다. 예를 들어 `petstore`, `petstore/pets`, `petstore/pets/{petId}` 등일 수 있습니다. API Gateway는 `{proxy+}` 리소스 생성 시 `ANY` 메서드를 생성하며 런타임에 지원되는 HTTP 동사에 대한 자리 표시자 역할을 합니다.

****/\$1proxy\$1\$1** 리소스를 생성하려면**

1. API를 선택합니다.

1. 기본 탐색 창에서 **리소스**를 선택합니다.

1. **리소스 생성**을 선택합니다.

1. **프록시 리소스**를 켭니다.

1. **리소스 경로**를 `/`로 유지합니다.

1. **리소스 이름**에 **\$1proxy\$1\$1**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.  
![\[하위 리소스를 생성합니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/api-gateway-simple-proxy-create-proxy-resource-new-console.png)

이 단계에서는 프록시 통합을 사용하여 `ANY` 메서드를 백엔드 HTTP 엔드포인트와 통합합니다. 프록시 통합에서 API Gateway는 API Gateway의 개입 없이 클라이언트가 제출한 메서드 요청을 백엔드로 전달합니다.

**`ANY` 메서드를 생성하려면**

1. **/\$1proxy\$1\$1** 리소스를 선택합니다.

1. **ANY** 메서드를 선택합니다.

1. 경고 기호 아래에서 **통합 편집**을 선택합니다. 통합 없이는 메서드가 있는 API를 배포할 수 없습니다.

1. **통합 유형**에서 **HTTP**를 선택합니다.

1. **HTTP 프록시 통합**을 켭니다.

1. **HTTP 메서드**에서 **ANY**를 선택합니다.

1. **엔드포인트 URL**에 **http://petstore-demo-endpoint.execute-api.com/\$1proxy\$1**를 입력합니다.

1. **저장**을 선택합니다.

## HTTP 프록시 통합을 사용하여 API 테스트
<a name="api-gateway-create-api-as-simple-proxy-for-http-test"></a>

 특정 클라이언트 요청의 성공 여부는 다음 사항에 따라 달라집니다.
+  백엔드가 해당 백엔드 엔드포인트를 사용할 수 있도록 하고 (그러한 경우) 필수 액세스 권한을 부여한 경우.
+ 클라이언트가 올바른 입력을 제공하는 경우.

예를 들어 여기에서 사용된 PetStore API는 `/petstore` 리소스를 공개하지 않습니다. 따라서 `404 Resource Not Found` 오류 메시지가 포함된 `Cannot GET /petstore` 응답이 표시됩니다.

또한 클라이언트는 결과를 올바르게 구문 분석하기 위해 백엔드의 출력 형식을 처리할 수 있어야 합니다. API Gateway는 클라이언트와 백엔드 간의 상호 작용을 원활하게 하기 위해 조정하지 않습니다.

**프록시 리소스를 통해 HTTP 프록시 통합을 사용하여 PetStore 웹사이트와 통합된 API를 테스트하려면**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **메서드 유형**에서 `GET`를 선택합니다.

1. **경로**의 **proxy**에 **petstore/pets**를 입력합니다.

1. **쿼리 문자열**에 **type=fish**를 입력합니다.

1. **테스트**를 선택합니다.

     
![\[테스트 기능을 사용하여 메서드를 테스트합니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/api-gateway-simple-proxy-petstore-call-proxy-resource-new-console.png)

   백엔드 웹 사이트가 `GET /petstore/pets?type=fish` 요청을 지원하므로 다음과 비슷한 성공적인 응답을 반환합니다.

   ```
   [
     {
       "id": 1,
       "type": "fish",
       "price": 249.99
     },
     {
       "id": 2,
       "type": "fish",
       "price": 124.99
     },
     {
       "id": 3,
       "type": "fish",
       "price": 0.99
     }
   ]
   ```

   `GET /petstore` 호출을 시도하면 `404` 오류 메시지와 함께 `Cannot GET /petstore` 응답이 표시됩니다. 백엔드가 지정된 작업을 지원하지 않기 때문입니다. `GET /petstore/pets/1`을 호출하면 요청이 PetStore 웹 사이트에서 지원되므로 다음 페이로드와 함께 `200 OK` 응답이 표시됩니다.

   ```
   {
     "id": 1,
     "type": "dog",
     "price": 249.99
   }
   ```

브라우저를 사용하여 API를 테스트할 수 있습니다. API를 배포하고 스테이지에 연결하여 API의 호출 URL을 생성합니다.

**API를 배포하려면**

1. **Deploy API(API 배포)**를 선택합니다.

1. **스테이지**에서 **새 스테이지**를 선택합니다.

1. **단계 이름**에 **test**를 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **배포(Deploy)**를 선택합니다.

이제 클라이언트가 API를 호출할 수 있습니다.

**API를 호출하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. 기본 탐색 창에서 **스테이지**를 선택합니다.

1. **스테이지 세부 정보**에서 복사 아이콘을 선택하여 API의 호출 URL을 복사합니다.

   API의 호출 URL을 웹 브라우저에 입력합니다.

   전체 URL은 `https://abcdef123.execute-api.us-east-2.amazonaws.com/test/petstore/pets?type=fish`와(과) 같아야 합니다.

   브라우저가 API에 `GET` 요청을 보냅니다.

1. 결과는 API Gateway 콘솔에서 **테스트**를 사용할 때 반환되는 결과와 같아야 합니다.

# 자습서: HTTP 비 프록시 통합을 통해 REST API 생성
<a name="api-gateway-create-api-step-by-step"></a>

 이 자습서에서는 Amazon API Gateway 콘솔을 사용하여 API를 완전히 새로 생성합니다. 콘솔을 API 설계 스튜디오로 간주해 이를 사용하여 API 기능의 범위를 정하고, 동작을 시험하고, API를 구축하고, 단계별로 API를 배포합니다.

**Topics**
+ [HTTP 사용자 지정 통합을 사용하여 API 만들기](#api-gateway-create-resource-and-methods)
+ [(선택 사항) 요청 파라미터 매핑](#api-gateway-create-resources-and-methods-next-steps)

## HTTP 사용자 지정 통합을 사용하여 API 만들기
<a name="api-gateway-create-resource-and-methods"></a>

 이 단원에서는 리소스 생성, 리소스에서 메서드 노출, 원하는 API 동작을 위한 메서드 구성, API 테스트 및 배포 등을 단계별로 살펴봅니다.

이 단계에서는 빈 API를 생성합니다. 다음 단계에서는 비프록시 HTTP 통합을 사용하여 API를 `http://petstore-demo-endpoint.execute-api.com/petstore/pets` 엔드포인트에 연결하는 리소스와 메서드를 생성합니다.

**API를 생성하는 방법**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API Gateway를 처음 사용하는 경우, 서비스의 기능을 소개하는 페이지가 나타납니다. **REST API**에서 **빌드**를 선택합니다. **예제 API 생성** 팝업이 나타나면 **확인**을 선택합니다.

   API Gateway를 처음 사용하는 것이 아닌 경우 **API 생성**을 선택합니다. **REST API**에서 [**빌드**]를 선택합니다.

1.  **API 이름**에서 **HTTPNonProxyAPI**을 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **API 엔드포인트 유형** 설정을 **지역**으로 유지합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **API 생성**을 선택합니다.

**리소스** 트리에 메서드 없는 루트 리소스(`/`)가 표시됩니다. 이 연습에서는 PetStore 웹 사이트(http://petstore-demo-endpoint.execute-api.com/petstore/pets)의 HTTP 사용자 지정 통합을 사용하여 API를 구축합니다. 설명을 돕기 위해, 루트의 하위 항목으로 `/pets` 리소스를 생성하고, 이 리소스의 GET 메서드를 클라이언트에 공개하여 PetStore 웹사이트에서 판매 중인 Pets 품목의 목록을 가져오겠습니다.

**/pets 리소스를 생성하려면**

1. **리소스 생성**을 선택합니다.

1. **프록시 리소스**는 꺼진 상태로 둡니다.

1. **리소스 경로**를 `/`로 유지합니다.

1. **리소스 이름**에 **pets**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

이 단계에서는 **/pets** 리소스의 `GET` 메서드를 생성합니다. `GET` 메서드는 `http://petstore-demo-endpoint.execute-api.com/petstore/pets` 웹 사이트와 통합되어 있습니다. API 메서드의 다른 옵션에는 다음이 포함됩니다.
+ **POST**는 주로 하위 리소스를 생성하는 데 사용됩니다.
+ **PUT**은 주로 기존 리소스를 업데이트하는 데 사용되며, 권장되지는 않지만 하위 리소스를 생성하는 데에도 사용될 수 있습니다.
+ **DELETE**는 리소스를 삭제하는 데 사용됩니다.
+ **PATCH**는 리소스를 업데이트하는 데 사용됩니다.
+ **HEAD**는 주로 시나리오를 테스트하는 데 사용됩니다. GET와 동일하지만 리소스 표현을 반환하지 않습니다.
+ **OPTIONS**는 호출자가 타겟 서비스에 사용 가능한 통신 옵션에 대한 정보를 가져오는 데 사용할 수 있습니다.

 통합 요청의 **HTTP 메서드(HTTP method)**에 백엔드에서 지원하는 항목을 선택해야 합니다. `HTTP` 또는 `Mock integration`의 경우, 메서드 요청과 통합 요청이 동일한 HTTP 동사를 사용하는 것이 합리적입니다. 다른 통합 유형 및 메서드 요청의 경우, 통합 요청과 다른 HTTP 동사를 사용할 가능성이 높습니다. 예를 들어 Lambda 함수를 호출하기 위해 통합 요청은 `POST`를 이용해 함수를 호출해야 하는 반면, 메서드 요청은 Lambda 함수의 로직에 따라 임의의 HTTP 동사를 사용할 수 있습니다.

****/pets** 리소스에 `GET` 메서드를 생성하려면**

1. **/pets** 리소스를 선택합니다.

1. **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **GET**을 선택합니다.

1. **통합 유형**에서 **HTTP 통합**을 선택합니다.

1. **HTTP 프록시 통합**을 꺼진 상태로 둡니다.

1. **HTTP 메서드**에서 **GET**을 선택합니다.

1. **엔드포인트 URL**에 **http://petstore-demo-endpoint.execute-api.com/petstore/pets**를 입력합니다.

   PetStore 웹사이트 페이지에서 반려 동물 유형별로(예: ‘Dog’ 또는 ‘Cat’) `Pet` 항목의 목록을 가져올 수 있습니다.

1. **콘텐츠 처리**에서 **패스스루**를 선택합니다.

1. **URL 쿼리 문자열 파라미터**를 선택합니다.

   PetStore 웹사이트는 `type` 및 `page` 쿼리 문자열 파라미터를 사용해 이러한 입력을 수락합니다. 메서드 요청에 쿼리 문자열 파라미터를 추가하고 이를 연동 요청의 해당 쿼리 문자열 파라미터에 매핑합니다.

1. 쿼리 문자열 파라미터를 추가하려면 다음을 따라합니다:

   1. **쿼리 문자열 추가(Add query string)**를 선택합니다.

   1. **이름**에 **type**을 입력합니다.

   1. **필수** 상태로 유지하고 **캐싱**을 해제합니다.

   이전 단계를 반복하여 이름이 **page**인 추가 쿼리 문자열을 생성합니다.

1. **메서드 생성**을 선택합니다.

이제 클라이언트는 요청을 제출할 때 반려 동물 유형과 페이지 번호를 쿼리 문자열 파라미터로 제공할 수 있습니다. 이러한 입력 파라미터를 통합의 쿼리 문자열 파라미터에 매핑하여 백엔드에서 PetStore 웹사이트에 입력 값을 전달해야 합니다.

**입력 파라미터를 통합 요청에 매핑하려면**

1. **통합 요청** 탭의 **통합 요청 설정**에서 **편집**을 선택합니다.

1. **URL 쿼리 문자열 파라미터**를 선택하고 다음을 수행합니다.

   1. **쿼리 문자열 파라미터 추가**를 선택합니다.

   1. **이름**에 **type**을 입력합니다.

   1. **다음에서 매핑됨**에 **method.request.querystring.type**을 입력합니다.

   1. **캐싱**을 꺼진 상태로 둡니다.

   1. **쿼리 문자열 파라미터 추가**를 선택합니다.

   1. **이름**에 **page**을 입력합니다.

   1. **다음에서 매핑됨**에 **method.request.querystring.page**을 입력합니다.

   1. **캐싱**을 꺼진 상태로 둡니다.

1. **저장**을 선택합니다.

**API를 테스트하려면**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **쿼리 문자열**에 **type=Dog&page=2**를 입력합니다.

1. **테스트**를 선택합니다.

    그 결과는 다음과 비슷합니다.

      
![\[pets 메서드 결과에 GET 호출 테스트\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/api-gateway-create-api-step-by-step-test-invoke-get-on-pets-result-new-console.png)

    테스트에 성공했으므로, API를 배포해 공개적으로 사용 가능하도록 할 수 있습니다.

1. **Deploy API(API 배포)**를 선택합니다.

1. **스테이지**에서 **새 스테이지**를 선택합니다.

1. **단계 이름**에 **Prod**를 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **배포(Deploy)**를 선택합니다.

1.  (선택 사항) **스테이지 세부 정보**의 **URL 호출**에서 복사 아이콘을 선택하여 API의 호출 URL을 복사합니다. 이 URL을 [Postman](https://www.postman.com) 및 [cURL](https://curl.se/)과 같은 도구에서 사용하여 API를 테스트할 수 있습니다.

 SDK를 이용해 클라이언트를 생성하면 SDK가 공개한 메서드를 호출하여 요청을 보낼 수 있습니다. 구현 세부 정보는 선택한 [AWS SDK](https://aws.amazon.com/developer/tools/)를 참조하세요.

**참고**  
 API가 변경되면 API를 다시 배포하여 새 기능 또는 업데이트된 기능을 사용할 수 있도록 한 후 요청 URL을 다시 호출해야 합니다.

## (선택 사항) 요청 파라미터 매핑
<a name="api-gateway-create-resources-and-methods-next-steps"></a>

### API Gateway API에 대한 요청 파라미터 매핑
<a name="getting-started-mappings"></a>

 이 자습서에서는 항목 ID를 지정하고, 이를 통합 요청 URL의 `{petId}` 경로 파라미터에 매핑하고, 요청을 HTTP 엔드포인트로 보내기 위해 API의 메서드 요청에서 `{id}`의 경로 파라미터를 생성하는 방법을 보여줍니다.

**참고**  
 대문자 대신 소문자를 입력하거나 그 반대로 입력하면 연습 뒷부분에서 오류가 발생할 수 있습니다.

#### 1단계: 리소스 생성
<a name="getting-started-mappings-add-resources"></a>

이 단계에서는 경로 파라미터 \$1petid\$1를 사용하여 리소스를 생성합니다.

**\$1petId\$1 리소스를 생성하려면**

1. **/pets** 리소스를 선택한 다음 **리소스 생성**을 선택합니다.

1. **프록시 리소스**는 꺼진 상태로 둡니다.

1. **리소스 경로**에서 **/pets/**를 선택합니다.

1. **리소스 이름**에 **\$1petId\$1**을 입력합니다.

    **/pets/\$1petId\$1**가 표시되도록 `petId`에 중괄호(`{ }`)를 사용합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

#### 2단계: 메서드 생성 및 테스트
<a name="getting-started-mappings-set-methods"></a>

 이 단계에서는 `{petId}` 경로 파라미터를 사용하여 `GET` 메서드를 생성합니다.

**GET 메서드를 설정하려면**

1. **/\$1petId\$1** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **GET**을 선택합니다.

1. **통합 유형**에서 **HTTP 통합**을 선택합니다.

1. **HTTP 프록시 통합**을 꺼진 상태로 둡니다.

1. **HTTP 메서드**에서 **GET**을 선택합니다.

1. **엔드포인트 URL**에 **http://petstore-demo-endpoint.execute-api.com/petstore/pets/\$1id\$1**를 입력합니다.

1. **콘텐츠 처리**에서 **패스스루**를 선택합니다.

1. **기본 제한 시간**을 켜진 상태로 둡니다.

1. **메서드 생성**을 선택합니다.

이제 방금 생성한 `{petId}` 경로 파라미터를 통합 요청의 HTTP 엔드포인트 URL에 있는 `{id}` 경로 파라미터에 매핑합니다. HTTP 엔드포인트 URL은 **http://petstore-demo-endpoint.execute-api.com/petstore/pets/\$1id\$1**였습니다.

**`{petId}` 경로 파라미터를 매핑하려면**

1. **통합 요청** 탭의 **통합 요청 설정**에서 **편집**을 선택합니다.

1. **URL 경로 파라미터**를 선택합니다.

1.  API Gateway는 **petId**라는 이름의 통합 요청에 대한 경로 파라미터를 생성하지만 이 경로 파라미터는 백엔드 통합으로 설정한 HTTP 엔드포인트 URL에는 유효하지 않습니다. HTTP 엔드포인트는 경로 파라미터로 `{id}`를 사용합니다. **이름**에서 **petId**를 삭제하고 **id**를 입력합니다.

   그렇게 하면 `petId`의 메서드 요청 경로 파리미터가 `id`의 통합 요청 경로 파라미터로 매핑됩니다.

1. **저장**을 선택합니다.

이제 메서드를 테스트합니다.

** 메서드를 테스트하는 방법**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **petId**의 **경로**에 **4**를 입력합니다.

1. **테스트**를 선택합니다.

   올바르게 수행했다면 **응답 본문**에 다음이 표시됩니다.

   ```
   {
     "id": 4,
     "type": "bird",
     "price": 999.99
   }
   ```

#### 3단계: API 배포
<a name="getting-started-mappings-deploy"></a>

이 단계에서는 API를 API Gateway 콘솔 외부에서 호출을 시작할 수 있도록 배포합니다.

**API를 배포하려면**

1. **Deploy API(API 배포)**를 선택합니다.

1. **스테이지**에서 **Prod**를 선택합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. [**Deploy**]를 선택합니다.

#### 4단계: API 테스트
<a name="getting-started-mappings-test"></a>

이 단계에서는 API Gateway 콘솔 외부로 이동하고 API를 사용하여 HTTP 엔드포인트에 액세스합니다.

1. 기본 탐색 창에서 **스테이지**를 선택합니다.

1. **스테이지 세부 정보**에서 복사 아이콘을 선택하여 API의 호출 URL을 복사합니다.

   다음과 같아야 합니다.

   ```
   https://my-api-id.execute-api.region-id.amazonaws.com/prod
   ```

1. 이 URL을 새 브라우저 탭의 주소 표시줄에 입력하고 URL에 `/pets/4`를 추가한 다음 요청을 제출합니다.

1. 브라우저에서 다음을 반환합니다.

   ```
   {
     "id": 4,
     "type": "bird",
     "price": 999.99
   }
   ```

#### 다음 단계
<a name="api-gateway-create-resources-and-methods-next-steps"></a>

요청 검사를 켜거나, 데이터를 변환하거나, 사용자 지정 게이트웨이 응답을 생성하여 API를 추가로 사용자 지정할 수 있습니다.

API를 사용자 지정하는 더 많은 방법은 다음 자습서를 참조하세요.
+ 요청 검증에 대한 자세한 내용은 [API Gateway의 기본 요청 확인 설정](api-gateway-request-validation-set-up.md)를 참조하십시오.
+ 요청 및 응답 페이로드를 변환하는 방법에 대한 자세한 내용은 [자습서: AWS 서비스에 대한 통합의 통합 요청 및 응답 수정](set-up-data-transformations-in-api-gateway.md) 섹션을 참조하세요.
+ 사용자 지정 게이트웨이 응답을 생성하는 방법에 대한 자세한 내용은 [API Gateway 콘솔을 사용하여 REST API에 대한 게이트웨이 응답 설정](set-up-gateway-response-using-the-console.md) 섹션을 참조하세요.

# 자습서: 프라이빗 통합을 통해 REST API 생성
<a name="getting-started-with-private-integration"></a>

이 자습서에서는 Amazon VPC에서 실행되는 Amazon ECS 서비스에 연결하는 REST API를 생성합니다. Amazon VPC 외부의 클라이언트는 API를 사용하여 Amazon ECS 서비스에 액세스할 수 있습니다.

이 자습서는 완료하는데 약 1시간이 걸립니다. 먼저 CloudFormation 템플릿을 사용하여 Amazon VPC 및 Amazon ECS 서비스를 생성합니다. 그런 다음 API Gateway 콘솔을 사용하여 VPC 링크 V2를 생성합니다. VPC 링크를 통해 API Gateway는 Amazon VPC에서 실행되는 Amazon ECS 서비스에 액세스할 수 있습니다. 그런 다음 VPC 링크 V2를 사용하여 Amazon ECS 서비스에 연결하는 REST API를 생성합니다. 마지막으로 API를 테스트합니다.

REST API를 간접적으로 호출하면 API Gateway는 VPC 링크 V2를 통해 요청을 Amazon ECS 서비스로 라우팅한 다음 서비스에서 응답을 반환합니다.

**참고**  
이 자습서는 이전에 HTTP API에 대해 지원되었으며, 이제 VPC 링크 V2를 사용하는 REST API에 대해 지원됩니다.

![\[이 튜토리얼에서 생성하는 REST API의 개요입니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/private-integration-rest.png)


이 자습서를 완료하려면 AWS 계정과 콘솔 액세스 권한이 있는 AWS Identity and Access Management 사용자가 있어야 합니다. 자세한 내용은 [API Gateway를 사용하도록 설정](setting-up.md) 섹션을 참조하세요.

**Topics**
+ [1단계: Amazon ECS 서비스 생성](#rest-api-private-integration-create-ecs-service)
+ [2단계: VPC 링크 생성](#http-api-private-integration-vpc-link)
+ [3단계: REST API 생성](#http-api-private-integration-create-api)
+ [4단계: API 테스트](#rest-api-private-integration-test-api)
+ [5 단계: API 배포](#rest-api-private-integration-deploy-api)
+ [6단계: API 직접 호출](#rest-api-private-integration-call)
+ [7단계: 정리](#rest-api-private-integration-cleanup)

## 1단계: Amazon ECS 서비스 생성
<a name="rest-api-private-integration-create-ecs-service"></a>

Amazon ECS는 클러스터에서 Docker 컨테이너를 손쉽게 실행, 중지 및 관리할 수 있게 해 주는 컨테이너 관리 서비스입니다. 이 자습서에서는 Amazon ECS에서 관리하는 서버리스 인프라에서 클러스터를 실행합니다.

Amazon VPC를 포함하여 서비스에 대한 모든 종속성을 생성하는 [이 CloudFormation 템플릿](samples/rest-private-integration-tutorial.zip)을 다운로드하고 압축을 풉니다. 이 템플릿을 사용하여 Application Load Balancer를 사용하는 Amazon ECS 서비스를 생성합니다.

**CloudFormation 스택을 생성하려면**

1. CloudFormation 콘솔([https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/))을 엽니다.

1. **스택 생성**을 선택한 다음 **새 리소스 사용(표준)**을 선택합니다.

1. **템플릿 지정**에서 **템플릿 파일 업로드**를 선택합니다.

1. 다운로드한 템플릿을 선택합니다.

1. **다음**을 선택합니다.

1. **스택 이름**에 **rest-api-private-integrations-tutorial**을 입력하고 **다음**을 선택합니다.

1. **스택 옵션 구성**에서 **다음**을 선택합니다.

1. **기능**의 경우 CloudFormation이 계정에 IAM 리소스를 생성할 수 있음을 확인합니다.

1. **다음**을 선택한 후 **제출**을 선택합니다.

CloudFormation는 ECS 서비스를 프로비저닝하며 이 작업은 몇 분 정도 걸릴 수 있습니다. CloudFormation 스택 상태가 **CREATE\$1COMPLETE**인 경우 다음 단계로 넘어갈 준비가 된 것입니다.

## 2단계: VPC 링크 생성
<a name="http-api-private-integration-vpc-link"></a>

VPC 링크를 사용하면 API Gateway가 Amazon VPC의 프라이빗 리소스에 액세스할 수 있습니다. VPC 링크를 사용하면 클라이언트가 REST API를 통해 Amazon ECS 서비스에 액세스할 수 있습니다.

**VPC 링크 생성**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. 주요 탐색 창에서 **VPC 링크**를 선택한 후 **생성**을 선택합니다.

   메뉴 아이콘을 선택하여 기본 탐색 창을 열어야 할 수도 있습니다.

1. **VPC 링크 버전 선택**에서 **VPC 링크 V2**를 선택합니다.

1. **이름**에 **private-integrations-tutorial**를 입력합니다.

1. **VPC**에서 1단계에서 생성한 VPC를 선택합니다. 이름은 **RestApiStack**으로 시작해야 합니다.

1. **서브넷**(Subnets)의 경우 VPC에 있는 두 개의 프라이빗 서브넷을 선택합니다. 이름은 `PrivateSubnet`(으)롤 끝납니다.

1. **보안 그룹**의 경우 `private-integrations-tutorial`로 시작하고 `RestApiStack/RestApiTutorialService/Service/SecurityGroup`의 설명이 있는 그룹 ID를 선택합니다.

1. **생성(Create)**을 선택합니다.

VPC 링크 V2를 생성한 후 API Gateway는 탄력적 네트워크 인터페이스를 프로비저닝하여 VPC에 액세스합니다. 이 프로세스는 몇 분 정도 걸릴 수 있습니다. 그동안 API를 생성할 수 있습니다.

## 3단계: REST API 생성
<a name="http-api-private-integration-create-api"></a>

REST API는 Amazon ECS 서비스에 대한 HTTP 엔드포인트를 제공합니다.



**REST API를 생성하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **API 생성**(Create API)을 선택한 다음 **REST API**에 대해 **빌드**(Build)를 선택합니다.

1. **이름**에 **private-integration-api**를 입력합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **API 생성**을 선택합니다.

   API를 생성한 후 메서드를 생성합니다.

1. **메서드 생성**을 선택하고 다음을 수행합니다.

   1. **메서드 유형**에서 `GET`를 선택합니다.

   1. **통합 유형**에서 **VPC 링크**를 선택합니다.

   1. **VPC 프록시 통합**을 켭니다.

   1. **HTTP 메서드**에서 `GET`을 선택합니다.

   1. **VPC 링크**의 경우 이전 단계에서 생성한 VPC 링크 V2를 선택합니다.

   1. **통합 대상**에 1단계에서 CloudFormation 템플릿으로 생성한 로드 밸런서를 입력합니다. 이름은 **rest-**로 시작해야 합니다.

   1. **엔드포인트 URL**에 `http://private-integrations-tutorial.com`를 입력합니다.

      URL은 통합 요청의 `Host` 헤더를 설정하는 데 사용됩니다. 이 경우 호스트 헤더는 **private-integrations-tutorial**입니다.

   1. **메서드 생성**을 선택합니다.

      프록시 통합이 있으면 API를 테스트할 준비가 된 것입니다.

## 4단계: API 테스트
<a name="rest-api-private-integration-test-api"></a>

다음으로 API 메서드 간접 호출을 테스트합니다.

**API 테스트하기**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **테스트** 선택

   API의 응답이 앱이 Amazon ECS에서 실행 중임을 알려주는 시작 메시지인지 확인합니다.

## 5 단계: API 배포
<a name="rest-api-private-integration-deploy-api"></a>

다음으로 API를 배포합니다.

**API를 배포하려면**

1. **Deploy API(API 배포)**를 선택합니다.

1. **스테이지**에서 **새 스테이지**를 선택합니다.

1. **단계 이름**에 **Prod**를 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **배포(Deploy)**를 선택합니다.

## 6단계: API 직접 호출
<a name="rest-api-private-integration-call"></a>

API를 배포한 후 직접적으로 호출할 수 있습니다.

**API 직접 호출**

1. 웹 브라우저에 호출 URL을 입력합니다.

   전체 URL은 `https://abcd123.execute-api.us-east-2.amazonaws.com/Prod`와(과) 같아야 합니다.

   브라우저가 API에 `GET` 요청을 보냅니다.

1. API의 응답이 앱이 Amazon ECS에서 실행 중임을 알려주는 시작 메시지인지 확인합니다.

   시작 메시지가 표시되면 Amazon VPC에서 실행되는 Amazon ECS 서비스를 성공적으로 생성하고, VPC 링크 V2와 함께 API Gateway REST API를 사용하여 Amazon ECS 서비스에 액세스한 것입니다.

## 7단계: 정리
<a name="rest-api-private-integration-cleanup"></a>

불필요한 비용을 방지하려면 이 자습서의 일부로 생성한 리소스를 삭제합니다. 다음 단계에서는 VPC 링크 V2, CloudFormation 스택 및 REST API를 삭제합니다.

**REST API 삭제**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **API** 페이지에서 API를 선택합니다. **작업**(Actions)을 선택하고 **삭제**(Delete)를 선택한 다음 선택을 확인합니다.

**VPC 링크 삭제**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **VPC 링크**(VPC link)를 선택합니다.

1. VPC 링크를 선택하고 **삭제**(Delete)를 선택한 다음, 해당 선택을 확인합니다.

**CloudFormation 스택을 삭제하려면**

1. CloudFormation 콘솔([https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/))을 엽니다.

1. CloudFormation 스택을 선택합니다.

1. **삭제**를 선택한 다음 해당 선택을 확인합니다.

# 자습서: AWS 통합을 통해 REST API 생성
<a name="getting-started-aws-proxy"></a>

 [자습서: Lambda 프록시 통합을 통해 REST API 생성](api-gateway-create-api-as-simple-proxy-for-lambda.md) 및 [자습서: Lambda 비 프록시 통합을 통해 REST API 생성](getting-started-lambda-non-proxy-integration.md) 주제에서는 통합된 Lambda 함수를 공개하는 API Gateway API를 생성하는 방법에 대해 설명합니다. 또한 API Gateway API를 생성하여 Amazon SNS, Amazon S3, Amazon Kinesis, 심지어 AWS Lambda 등의 다른 AWS 서비스를 노출할 수 있습니다. 이는 `AWS` 통합을 통해 가능합니다. Lambda 통합 또는 Lambda 프록시 통합은 Lambda 함수 호출이 API Gateway API를 통해 공개되는 특수한 경우입니다.

 모든 AWS 서비스는 전용 API를 지원하여 해당 기능을 공개합니다. 그러나 애플리케이션 프로토콜 또는 프로그래밍 인터페이스는 서비스마다 다를 수 있습니다. `AWS` 통합을 사용한 API Gateway API는 클라이언트가 서로 다른 AWS 서비스에 액세스할 수 있도록 일관된 애플리케이션 프로토콜을 제공한다는 이점이 있습니다.

 이 연습에서는 Amazon SNS를 공개하는 API를 생성합니다. API와 다른 AWS 서비스를 통합하는 더 많은 예제를 보려면 [Amazon API Gateway 자습서 및 워크숍](api-gateway-tutorials.md)를 참조하십시오.

 Lambda 프록시 통합과 달리 다른 AWS 서비스에는 해당 프록시 통합이 없습니다. 따라서 API 메서드는 단일 AWS 작업과 통합됩니다. 유연성을 높이기 위해 프록시 통합과 마찬가지로 Lambda 프록시 통합을 설정할 수 있습니다. 그런 다음 Lambda 함수는 다른 AWS 작업에 대한 요청을 구문 분석하고 처리합니다.

 API Gateway는 엔드포인트 시간이 초과되어도 재시도하지 않습니다. API 호출자는 엔드포인트 시간 초과를 처리하기 위한 재시도 로직을 구현해야 합니다.

 이 연습은 [자습서: Lambda 비 프록시 통합을 통해 REST API 생성](getting-started-lambda-non-proxy-integration.md)의 지침 및 개념을 기반으로 합니다. 아직 그 연습을 완료하지 못했다면 먼저 완료하는 것이 좋습니다.



**Topics**
+ [사전 조건](#getting-started-aws-proxy-prerequisites)
+ [1단계: AWS 서비스 프록시 실행 역할 생성](#getting-started-aws-proxy-add-roles)
+ [2단계: 리소스 생성](#getting-started-aws-proxy-add-resources)
+ [3단계: GET 메서드 생성](#getting-started-aws-proxy-add-methods)
+ [4단계: 메서드 설정 지정 및 메서드 테스트](#getting-started-aws-proxy-set-methods)
+ [5단계: API 배포](#getting-started-aws-proxy-deploy)
+ [6단계: API 테스트](#getting-started-aws-proxy-test)
+ [7단계: 정리](#getting-started-aws-proxy-clean-up)

## 사전 조건
<a name="getting-started-aws-proxy-prerequisites"></a>

이 연습을 시작하기 전에 다음을 수행합니다.

1. [API Gateway를 사용하도록 설정](setting-up.md)의 단계를 수행합니다.

1.  `MyDemoAPI`라는 새 API를 생성합니다. 자세한 내용은 [자습서: HTTP 비 프록시 통합을 통해 REST API 생성](api-gateway-create-api-step-by-step.md) 단원을 참조하세요.

1. API를 `test`이라는 단계에 1회 이상 배포합니다. 자세한 내용은 [AWS Lambda 통합 튜토리얼 선택](getting-started-with-lambda-integration.md)의 [API 배포](getting-started-lambda-non-proxy-integration.md#getting-started-deploy-api)를 참조하세요.

1. 의 나머지 단계를 완료합니다[AWS Lambda 통합 튜토리얼 선택](getting-started-with-lambda-integration.md)

1. Amazon Simple Notification Service(Amazon SNS)에 하나 이상의 주제를 생성합니다. 배포된 API를 이용해 AWS 계정과 연결된 Amazon SNS에서 주제 목록을 가져옵니다. Amazon SNS에서 주제를 생성하는 방법은 [주제 생성](https://docs.aws.amazon.com/sns/latest/dg/sns-create-topic.html)을 참조하세요. (5단계에 언급한 주제 ARN을 복사할 필요가 없습니다.)

## 1단계: AWS 서비스 프록시 실행 역할 생성
<a name="getting-started-aws-proxy-add-roles"></a>

 API에서 Amazon SNS 작업을 간접적으로 호출하도록 허용하려면 적절한 IAM 정책을 IAM 역할에 연결해야 합니다. 이 단계에서는 새 IAM 역할을 생성합니다.

**AWS 서비스 프록시 실행 역할을 생성하려면**

1. AWS Management Console에 로그인하여 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 에서 IAM 콘솔을 엽니다.

1. **Roles**를 선택합니다.

1. **역할 생성**을 선택합니다.

1.  **신뢰할 수 있는 유형의 엔터티 선택**에서 **AWS 서비스**를 선택한 다음 **API Gateway**를 선택하고 **API Gateway가 로그를 CloudWatch Logs로 푸시하도록 허용**을 선택합니다.

1.  **다음**을 선택한 후 다시 **다음**을 선택합니다.

1. **역할 이름**에 **APIGatewaySNSProxyPolicy**를 입력한 다음 **역할 생성**을 선택합니다.

1. **역할** 목록에서 방금 생성한 역할을 선택합니다. 스크롤하거나 검색 창을 사용하여 역할을 찾을 수 있습니다.

1. 선택한 역할에 대해 **권한 추가** 탭을 선택합니다.

1. 드롭다운 목록에서 **정책 연결**을 선택합니다.

1. 검색 창에 **AmazonSNSReadOnlyAccess**를 입력하고 **권한 추가**를 선택합니다.
**참고**  
이 자습서에서는 단순화를 위해 관리형 정책을 사용합니다. 가장 좋은 방법은 필요한 최소 권한을 부여하는 자체 IAM 정책을 생성하는 것입니다.

1. 새로 생성된 **역할 ARN**은 나중에 사용할 수 있도록 기록해 둡니다.

## 2단계: 리소스 생성
<a name="getting-started-aws-proxy-add-resources"></a>

이 단계에서는 AWS 서비스 프록시가 AWS 서비스와 상호 작용할 수 있도록 하는 리소스를 생성합니다.

**리소스를 생성하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. 슬래시 하나(**/**)로 표현된 루트 리소스 **/**를 선택한 후 **리소스 생성**을 선택합니다.

1. **프록시 리소스**는 꺼진 상태로 둡니다.

1. **리소스 경로**를 `/`로 유지합니다.

1. **리소스 이름**에 **mydemoawsproxy**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

## 3단계: GET 메서드 생성
<a name="getting-started-aws-proxy-add-methods"></a>

이 단계에서는 AWS 서비스 프록시가 AWS 서비스와 상호 작용할 수 있도록 하는 GET 메서드를 생성합니다.

**`GET` 메서드를 생성하려면**

1. **/mydemoawsproxy** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. 메서드 유형에서 **GET**을 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Amazon SNS 주제를 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Amazon SNS**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에서 **GET**을 선택합니다.

1. **작업 유형**에서 **작업 이름 사용**을 선택합니다.

1. **함수 이름**에 **ListTopics**를 입력합니다.

1. **실행 역할**에 **APIGatewaySNSProxyPolicy**의 ARN을 입력합니다.

1. **메서드 생성**을 선택합니다.

## 4단계: 메서드 설정 지정 및 메서드 테스트
<a name="getting-started-aws-proxy-set-methods"></a>

이제 `GET` 메서드를 테스트하여 Amazon SNS 주제를 나열하도록 적절히 설정되었는지 확인할 수 있습니다.

**`GET` 메서드를 테스트하는 방법**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **테스트**를 선택합니다.

   결과로 다음과 비슷한 응답이 표시됩니다.

   ```
   {
     "ListTopicsResponse": {
       "ListTopicsResult": {
         "NextToken": null,
         "Topics": [
           {
             "TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-1"
           },
           {
             "TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-2"
           },
           ...
           {
             "TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-N"
           }
         ]
       },
       "ResponseMetadata": {
         "RequestId": "abc1de23-45fa-6789-b0c1-d2e345fa6b78"
       }
     }
   }
   ```

## 5단계: API 배포
<a name="getting-started-aws-proxy-deploy"></a>

이 단계에서는 API를 API Gateway 콘솔 외부에서 호출할 수 있도록 배포합니다.

**API를 배포하려면**

1. **Deploy API(API 배포)**를 선택합니다.

1. **스테이지**에서 **새 스테이지**를 선택합니다.

1. **단계 이름**에 **test**를 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. [**Deploy**]를 선택합니다.

## 6단계: API 테스트
<a name="getting-started-aws-proxy-test"></a>

이 단계에서는 API Gateway 콘솔 외부로 이동한 후 AWS 서비스 프록시를 사용하여 Amazon SNS 서비스와 상호 작용합니다.

1. 기본 탐색 창에서 **스테이지**를 선택합니다.

1. **스테이지 세부 정보**에서 복사 아이콘을 선택하여 API의 호출 URL을 복사합니다.

   형식은 다음과 같아야 합니다.

   ```
   https://my-api-id.execute-api.region-id.amazonaws.com/test
   ```

1. URL을 새 브라우저 탭의 주소 표시줄에 입력합니다.

1. `/mydemoawsproxy`를 추가하여 URL이 다음과 같이 되도록 합니다.

   ```
   https://my-api-id.execute-api.region-id.amazonaws.com/test/mydemoawsproxy
   ```

   해당 URL로 이동합니다. 다음과 비슷한 정보가 표시되어야 합니다.

   ```
   {"ListTopicsResponse":{"ListTopicsResult":{"NextToken": null,"Topics":[{"TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-1"},{"TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-2"},...{"TopicArn": "arn:aws:sns:us-east-1:80398EXAMPLE:MySNSTopic-N}]},"ResponseMetadata":{"RequestId":"abc1de23-45fa-6789-b0c1-d2e345fa6b78}}}
   ```

## 7단계: 정리
<a name="getting-started-aws-proxy-clean-up"></a>

AWS 서비스 프록시가 작업해야 할 IAM 리소스를 삭제할 수 있습니다.

**주의**  
AWS 서비스 프록시가 사용하는 IAM 리소스를 삭제하면 AWS 서비스 프록시 및 그것을 사용하는 모든 API는 더 이상 작동하지 않습니다. IAM 리소스 삭제는 실행 취소할 수 없습니다. IAM 리소스를 다시 사용하고 싶다면 재생성해야 합니다.

**연결된 IAM 리소스를 삭제하려면**

1. [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)에서 IAM 콘솔을 엽니다.

1. **세부 정보** 영역에서 **역할**을 선택합니다.

1. **APIGatewayAWSProxyExecRole**을 선택한 다음 **역할 작업**, **역할 삭제**를 선택합니다. 확인 메시지가 나타나면 [**Yes, Delete**]를 선택합니다.

1. **세부 정보** 영역에서 **정책**을 선택합니다.

1. **APIGatewayAWSProxyExecPolicy**를 선택한 다음 **정책 작업**, **삭제**를 선택합니다. 확인 메시지가 나타나면 **삭제**를 선택합니다.

 이 연습을 마칩니다. API를 AWS 서비스 프록시로 생성하는 방법에 대한 자세한 설명은 [자습서: Amazon Kinesis 프록시로 REST API 생성](integrating-api-with-aws-services-s3.md), [튜토리얼: 두 개의 AWS 서비스 통합과 하나의 Lambda 비프록시 통합으로 REST API 생성](integrating-api-with-aws-services-lambda.md) 또는 [자습서: REST API를 Amazon Kinesis 프록시로 생성](integrating-api-with-aws-services-kinesis.md) 단원을 참조하세요.

# 튜토리얼: 두 개의 AWS 서비스 통합과 하나의 Lambda 비프록시 통합으로 REST API 생성
<a name="integrating-api-with-aws-services-lambda"></a>

[자습서: Lambda 비 프록시 통합을 통해 REST API 생성](getting-started-lambda-non-proxy-integration.md)에서는 `Lambda Function` 통합만 사용합니다. `Lambda Function` 통합은 `AWS Service` 통합 유형의 특별한 사례로서, Lambda 함수를 간접적으로 호출하는 데 필요한 리소스 기반 권한을 자동으로 추가하는 등 대부분의 통합 설정을 수행합니다. 여기서 세 가지 통합 중 두 가지는 `AWS Service` 통합을 사용합니다. 이 통합 유형은 더 많은 제어 권한을 제공하지만, 적절한 권한이 포함된 IAM 역할 생성 및 지정과 같은 작업을 수동으로 수행해야 합니다.



이 자습서에서는 JSON 형식의 입력 및 출력을 수락 및 반환하여 기본 산술 연산을 구현하는 `Calc` Lambda 함수를 생성합니다. 그런 다음 REST API를 생성하여 다음과 같이 Lambda 함수와 통합합니다.

1. `GET` 리소스에 `/calc` 메서드를 공개하여 Lambda 함수를 호출하고, 입력을 쿼리 문자열 파라미터로 제공합니다(`AWS Service` 통합).

1. `POST` 리소스에 `/calc` 메서드를 공개하여 Lambda 함수를 호출하고, 입력을 메서드 요청 페이로드에 제공합니다(`AWS Service` 통합).

1. 중첩된 `GET` 리소스에 `/calc/{operand1}/{operand2}/{operator}`을 공개하여 Lambda 함수를 호출하고, 입력을 경로 파라미터로 제공합니다(`Lambda Function` 통합).

이 자습서 외에도, `Calc` API에 대한 [OpenAPI 정의 파일](api-as-lambda-proxy-export-swagger-with-extensions.md)을 검토할 수 있습니다. 이 파일은 [API Gateway에서 OpenAPI를 사용하여 REST API 개발](api-gateway-import-api.md)의 지침에 따라 API Gateway로 가져올 수 있습니다.

**Topics**
+ [맡을 수 있는 IAM 역할 생성](#api-as-lambda-proxy-setup-iam-role-policies)
+ [`Calc` Lambda 함수 생성](#api-as-lambda-proxy-create-lambda-function)
+ [`Calc` Lambda 함수 테스트](#api-as-lambda-proxy-test-lambda-function-)
+ [`Calc` API를 만듭니다.](#api-as-lambda-proxy-create-api-resources)
+ [통합 1: Lambda 함수를 호출하기 위해 쿼리 파라미터를 사용하여 `GET` 메서드 생성](#api-as-lambda-proxy-expose-get-method-with-query-strings-to-call-lambda-function)
+ [통합 2: Lambda 함수를 호출하기 위해 JSON 페이로드를 사용하여 `POST` 메서드 생성](#api-as-lambda-proxy-expose-post-method-with-json-body-to-call-lambda-function)
+ [통합 3: Lambda 함수를 호출하기 위해 경로 파라미터를 사용하여 `GET` 메서드 생성](#api-as-lambda-proxy-expose-get-method-with-path-parameters-to-call-lambda-function)
+ [Lambda 함수와 통합된 샘플 API의 OpenAPI 정의](api-as-lambda-proxy-export-swagger-with-extensions.md)

## 맡을 수 있는 IAM 역할 생성
<a name="api-as-lambda-proxy-setup-iam-role-policies"></a>

API가 `Calc` Lambda 함수를 호출하게 하려면 API Gateway가 맡을 수 있는 IAM 역할이 있어야 합니다. 이 역할은 다음과 같은 신뢰할 수 있는 관계를 가진 IAM 역할입니다.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

------

생성한 역할은 Lambda [InvokeFunction](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html) 권한을 가져야 합니다. 이 권한이 없으면 API 호출자가 `500 Internal Server Error` 응답을 받습니다. 역할에 이 권한을 부여하려면 다음 IAM 정책을 역할에 연결해야 합니다.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "lambda:InvokeFunction",
            "Resource": "*"
        }
    ]
}
```

------

다음은 이를 수행하는 방법입니다.

**API Gateway가 맡을 수 있는 IAM 역할 생성**

1. IAM 콘솔에 로그인합니다.

1. [**Roles**]를 선택합니다.

1. **역할 생성**을 선택합니다.

1. [**신뢰할 수 있는 유형의 엔터티 선택(Select type of trusted entity)**] 아래에서 **AWS 서비스**를 선택합니다.

1. **Choose the service that will use this role(이 역할을 사용할 서비스 선택)** 아래에서 **Lambda**를 선택합니다.

1. **Next: Permissions(다음: 권한)**를 선택합니다.

1. **정책 생성**을 선택합니다.

   새로운 **정책 생성** 콘솔 창이 열립니다. 이 창에서 다음을 수행합니다.

   1. **JSON** 탭에서 기존 정책을 다음으로 바꿉니다.

------
#### [ JSON ]

****  

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "lambda:InvokeFunction",
                  "Resource": "*"
              }
          ]
      }
      ```

------

   1. **정책 검토**(Review policy)를 선택합니다.

   1. **정책 검토**에서 다음을 수행합니다.

      1. **이름**에서 **lambda\$1execute** 같은 사용자 이름을 입력합니다.

      1. **정책 생성**을 선택합니다.

1. 원래의 **역할 만들기** 콘솔 창에서 다음을 수행하십시오.

   1. **Attach permissions policies(권한 정책 연결)**의 드롭다운 목록에서 **lambda\$1execute** 정책을 선택합니다.

      목록에 해당 정책이 표시되지 않으면 목록 상단에 있는 새로 고침 버튼을 선택합니다. (브라우저 페이지를 새로 고치지 마십시오.)

   1. **다음: 태그**를 선택합니다.

   1. **다음: 검토**를 선택합니다.

   1. **역할 이름**에 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role** 등의 이름을 입력합니다.

   1. **역할 생성**을 선택합니다.

1. 역할 목록에서 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role**을 선택합니다.

1. **신뢰 관계** 탭을 선택합니다.

1. **신뢰 관계 편집(Edit trust relationship)**을 선택합니다.

1. 기존 정책을 다음으로 바꿉니다.

------
#### [ JSON ]

****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Sid": "",
         "Effect": "Allow",
         "Principal": {
           "Service": [
             "lambda.amazonaws.com",
             "apigateway.amazonaws.com"
           ]
         },
         "Action": "sts:AssumeRole"
       }
     ]
   }
   ```

------

1. **신뢰 정책 업데이트**(Update Trust Policy)를 선택합니다.

1. 방금 생성한 역할의 역할 ARN을 기록해 둡니다. 잠시 후 필요한 정보입니다.

## `Calc` Lambda 함수 생성
<a name="api-as-lambda-proxy-create-lambda-function"></a>

다음으로 Lambda 콘솔을 사용하여 Lambda 함수를 생성합니다.

1. Lambda 콘솔에서 **함수 생성(Create function)**을 선택합니다.

1. **새로 작성**을 선택합니다.

1. **이름**에 **Calc**를 입력합니다.

1. **런타임**에서 지원되는 최신 **Node.js** 또는 **Python** 런타임을 선택합니다.

1. 다른 모든 옵션에는 기본 설정을 사용합니다.

1. **함수 생성**을 선택합니다.

1.  선호하는 런타임에 다음의 Lambda 함수를 복사한 다음, Lambda 콘솔에서 코드 편집기에 붙여 넣습니다.

------
#### [ Node.js ]

   ```
   export const handler = async function (event, context) {
     console.log("Received event:", JSON.stringify(event));
   
     if (
       event.a === undefined ||
       event.b === undefined ||
       event.op === undefined
     ) {
       return "400 Invalid Input";
     }
   
     const res = {};
     res.a = Number(event.a);
     res.b = Number(event.b);
     res.op = event.op;
     if (isNaN(event.a) || isNaN(event.b)) {
       return "400 Invalid Operand";
     }
     switch (event.op) {
       case "+":
       case "add":
         res.c = res.a + res.b;
         break;
       case "-":
       case "sub":
         res.c = res.a - res.b;
         break;
       case "*":
       case "mul":
         res.c = res.a * res.b;
         break;
       case "/":
       case "div":
         if (res.b == 0) {
           return "400 Divide by Zero";
         } else {
           res.c = res.a / res.b;
         }
         break;
       default:
         return "400 Invalid Operator";
     }
   
     return res;
   };
   ```

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

   ```
   import json
   
   
   def lambda_handler(event, context):
       print(event)
   
       try:
           (event['a']) and (event['b']) and (event['op'])
       except KeyError:
           return '400 Invalid Input'
   
       try:
           res = {
               "a": float(
                   event['a']), "b": float(
                   event['b']), "op": event['op']}
       except ValueError:
           return '400 Invalid Operand'
   
       if event['op'] == '+':
           res['c'] = res['a'] + res['b']
       elif event['op'] == '-':
           res['c'] = res['a'] - res['b']
       elif event['op'] == '*':
           res['c'] = res['a'] * res['b']
       elif event['op'] == '/':
           if res['b'] == 0:
               return '400 Divide by Zero'
           else:
               res['c'] = res['a'] / res['b']
       else:
           return '400 Invalid Operator'
   
       return res
   ```

------

1. 실행 역할에서 **기존 역할 선택(Choose an existing role)**을 선택합니다.

1. 앞에서 만든 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role** 역할의 ARN을 입력합니다.

1. [**Deploy**]를 선택합니다.

 이 함수에는 `a` 입력 파라미터의 두 피연산자(`b` 및 `op`) 및 연산자(`event`)가 필요합니다. 입력은 다음 형식의 JSON 객체입니다.

```
{
  "a": "Number" | "String",
  "b": "Number" | "String",
  "op": "String"
}
```

이 함수에서 계산된 결과(`c`) 및 입력을 반환합니다. 입력이 잘못된 경우 함수에서 널 값 또는 "Invalid op" 문자열을 결과로 반환합니다. 출력은 다음 JSON 형식입니다.

```
{
  "a": "Number",
  "b": "Number",
  "op": "String",
  "c": "Number" | "String"
}
```

다음 단계에서 함수를 API와 통합하기 전에 Lambda 콘솔에서 함수를 테스트해야 합니다.

## `Calc` Lambda 함수 테스트
<a name="api-as-lambda-proxy-test-lambda-function-"></a>

다음은 Lambda 콘솔에서 `Calc` 함수를 테스트하는 방법입니다.

1. **테스트** 탭을 선택합니다.

1. 테스트 이벤트의 이름에 **calc2plus5**를 입력합니다.

1. 테스트 이벤트 정의를 다음과 같이 바꿉니다.

   ```
   {
     "a": "2",
     "b": "5",
     "op": "+"
   }
   ```

1. **저장**을 선택합니다.

1. **테스트**를 선택합니다.

1. **실행 결과: 성공**을 확장합니다. 다음과 같은 모양이어야 합니다.

   ```
   {
     "a": 2,
     "b": 5,
     "op": "+",
     "c": 7
   }
   ```

## `Calc` API를 만듭니다.
<a name="api-as-lambda-proxy-create-api-resources"></a>

다음 절차는 방금 만든 `Calc` Lambda 함수에 대한 API를 만드는 방법을 보여줍니다. 그 다음 단원에서는 이 API에 리소스와 메서드를 추가할 것입니다.

**API를 생성하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API Gateway를 처음 사용하는 경우, 서비스의 기능을 소개하는 페이지가 나타납니다. **REST API**에서 **빌드**를 선택합니다. **예제 API 생성** 팝업이 나타나면 **확인**을 선택합니다.

   API Gateway를 처음 사용하는 것이 아닌 경우 **API 생성**을 선택합니다. **REST API**에서 **빌드**를 선택합니다.

1.  **API 이름**에서 **LambdaCalc**을 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **API 엔드포인트 유형** 설정을 **지역**으로 유지합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **API 생성(Create API)**을 선택합니다.

## 통합 1: Lambda 함수를 호출하기 위해 쿼리 파라미터를 사용하여 `GET` 메서드 생성
<a name="api-as-lambda-proxy-expose-get-method-with-query-strings-to-call-lambda-function"></a>

쿼리 문자열 파라미터를 Lambda 함수에 전달하는 `GET` 메서드를 생성하여, API가 브라우저에서 호출될 수 있도록 합니다. 이 방법은 오픈 액세스를 허용하는 API에 특히 유용합니다.

API를 생성한 후에는 리소스를 생성합니다. 일반적으로 API 리소스는 애플리케이션 로직에 따른 리소스 트리로 정리되어 있습니다. 이 단계에서는 **/calc** 리소스를 생성합니다.

****/calc** 리소스를 생성하려면**

1. **리소스 생성**을 선택합니다.

1. **프록시 리소스**는 꺼진 상태로 둡니다.

1. **리소스 경로**를 `/`로 유지합니다.

1. **리소스 이름**에 **calc**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

쿼리 문자열 파라미터를 Lambda 함수에 전달하는 `GET` 메서드를 생성하여, API가 브라우저에서 호출될 수 있도록 합니다. 이 방법은 오픈 액세스를 허용하는 API에 특히 유용합니다.

이 메서드에서 Lambda 함수의 경우 임의의 Lambda 함수를 간접적으로 호출할 때 `POST` 요청을 사용해야 합니다. 이 예제에서는 프런트엔드 메서드 요청에서의 HTTP 메서드가 백엔드에서의 통합 요청과 다를 수 있다는 것을 보여 줍니다.

**`GET` 메서드를 생성하는 방법**

1. **/calc** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **GET**을 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Lambda 함수를 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Lambda**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에서 **POST**를 선택합니다.

1. **작업 유형**에서 **경로 재정의 사용**을 선택합니다. 이 옵션을 사용하면 [호출](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html) 작업의 ARN을 지정하여 `Calc` 함수를 실행할 수 있습니다.

1. **경로 재정의**에서 **2015-03-31/functions/arn:aws:lambda:*us-east-2*:*account-id*:function:Calc/invocations**를 입력합니다. ** *account-id***에서 AWS 계정 ID를 입력합니다. ***us-east-2***에서 Lambda 함수를 생성한 AWS 리전을 입력합니다.

1. **실행 역할**에 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role**의 ARN을 입력합니다.

1. **보안 인증 캐시** 및 **기본 제한 시간** 설정을 변경하지 마세요.

1. **메서드 요청 설정**을 선택합니다.

1. **요청 검사기**에서 **쿼리 문자열 파라미터 및 헤더 검사**를 선택합니다.

   이렇게 설정하면 클라이언트가 필수 파라미터를 지정하지 않은 경우 오류 메시지가 반환됩니다.

1. **URL 쿼리 문자열 파라미터**를 선택합니다.

   이제 **/calc** 리소스에서 **GET** 메서드에 대한 쿼리 문자열 파라미터를 설정하면 백엔드 Lambda 함수를 대신하여 입력을 수신할 수 있습니다.

   쿼리 문자열 파라미터를 생성하려면 다음을 수행합니다.

   1. **쿼리 문자열 추가(Add query string)**를 선택합니다.

   1. **이름**에 **operand1**를 입력합니다.

   1. **필수**를 끕니다.

   1. **캐싱**을 꺼진 상태로 둡니다.

   같은 단계를 반복하여 **operand2**라는 쿼리 문자열과 **operator**라는 쿼리 문자열을 생성합니다.

1. **메서드 생성**을 선택합니다.

이제 `Calc` 함수에 필요한 대로 클라이언트가 제공한 쿼리 문자열을 통합 요청 페이로드로 변환하는 매핑 템플릿을 생성합니다. 이 템플릿은 **메서드 요청**에서 선언된 세 쿼리 문자열 파라미터를 백엔드 Lambda 함수에 대한 입력으로서 JSON 객체의 지정 속성 값에 매핑합니다. 변환된 JSON 객체는 통합 요청 페이로드로 포함됩니다.

**입력 파라미터를 통합 요청에 매핑하려면**

1. **통합 요청** 탭의 **통합 요청 설정**에서 **편집**을 선택합니다.

1. **요청 본문 패스스루**에서 **정의된 템플릿이 없는 경우(권장)**를 선택합니다.

1. **매핑 템플릿**을 선택합니다.

1. **매핑 템플릿 추가(Add mapping template)**를 선택합니다.

1. **콘텐츠 유형**에 **application/json**을 입력합니다.

1. **템플릿 본문**에 다음 코드를 입력합니다.

   ```
   {
       "a":  "$input.params('operand1')",
       "b":  "$input.params('operand2')", 
       "op": "$input.params('operator')"   
   }
   ```

1. **저장**을 선택합니다.

이제 `GET` 메서드를 테스트하여 Lambda 함수를 간접적으로 호출하도록 적절히 설정되었는지 확인할 수 있습니다.

**`GET` 메서드를 테스트하는 방법**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **쿼리 문자열**에 **operand1=2&operand2=3&operator=\$1**를 입력합니다.

1. **테스트**를 선택합니다.

   다음과 같은 결과가 나타납니다.  
![\[API Gateway에서 Lambda 프록시로 API 생성\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/aws_proxy_lambda_calc_get_method_test_new_console.png)

## 통합 2: Lambda 함수를 호출하기 위해 JSON 페이로드를 사용하여 `POST` 메서드 생성
<a name="api-as-lambda-proxy-expose-post-method-with-json-body-to-call-lambda-function"></a>

Lambda 함수를 호출하는 JSON 페이로드로 `POST` 메서드를 생성하면 클라이언트가 요청 본문의 백엔드 함수에 필요한 입력을 제공해야 합니다. 클라이언트가 올바른 입력 데이터를 업로드하도록 하기 위해 페이로드에서 요청 확인을 활성화합니다.

**JSON 페이로드로 `POST` 메서드를 생성하려면**

1. **/calc** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **POST**를 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Lambda 함수를 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Lambda**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에서 **POST**를 선택합니다.

1. **작업 유형**에서 **경로 재정의 사용**을 선택합니다. 이 옵션을 사용하면 [호출](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html) 작업의 ARN을 지정하여 `Calc` 함수를 실행할 수 있습니다.

1. **경로 재정의**에서 **2015-03-31/functions/arn:aws:lambda:*us-east-2*:*account-id*:function:Calc/invocations**를 입력합니다. ** *account-id***에서 AWS 계정 ID를 입력합니다. ***us-east-2***에서 Lambda 함수를 생성한 AWS 리전을 입력합니다.

1. **실행 역할**에 **lambda\$1invoke\$1function\$1assume\$1apigw\$1role**의 ARN을 입력합니다.

1. **보안 인증 캐시** 및 **기본 제한 시간** 설정을 변경하지 마세요.

1. **메서드 생성**을 선택합니다.

이제 입력 데이터 구조를 설명하고 수신되는 요청의 본문을 검사하기 위한 **입력** 모델을 생성합니다.

**입력 모델을 생성하려면**

1. 기본 탐색 창에서 **모델**을 선택합니다.

1. **Create model**(모델 생성)을 선택합니다.

1. **이름**에 **input**를 입력합니다.

1. **콘텐츠 유형**에 **application/json**을 입력합니다.

   일치하는 콘텐츠 유형이 없는 경우 요청 확인이 수행되지 않습니다. 콘텐츠 유형에 관계없이 동일한 모델을 사용하려면 **\$1default**를 입력합니다.

1. **모델 스키마**에서 다음 모델을 입력합니다.

   ```
   {
       "type":"object",
       "properties":{
           "a":{"type":"number"},
           "b":{"type":"number"},
           "op":{"type":"string"}
       },
       "title":"input"
   }
   ```

1. **Create model**(모델 생성)을 선택합니다.

이제 **출력** 모델을 생성합니다. 이 모델은 백엔드로부터 계산된 출력의 데이터 구조를 설명합니다. 통합 응답 데이터를 다른 모델에 매핑하는 데 사용할 수 있습니다. 이 자습서에서는 패스스루 동작에 의존하며 이 모델을 사용하지 않습니다.

**출력 모델을 생성하려면**

1. **Create model**(모델 생성)을 선택합니다.

1. **이름**에 **output**를 입력합니다.

1. **콘텐츠 유형**에 **application/json**을 입력합니다.

   일치하는 콘텐츠 유형이 없는 경우 요청 확인이 수행되지 않습니다. 콘텐츠 유형에 관계없이 동일한 모델을 사용하려면 **\$1default**를 입력합니다.

1. **모델 스키마**에서 다음 모델을 입력합니다.

   ```
   {
       "type":"object",
       "properties":{
           "c":{"type":"number"}
       },
       "title":"output"
   }
   ```

1. **Create model**(모델 생성)을 선택합니다.

이제 **결과** 모델을 생성합니다. 이 모델은 반환된 응답 데이터의 데이터 구조를 설명합니다. 이는 API에 정의된 **입력** 스키마와 **출력** 스키마를 모두 참조합니다.

**결과 모델을 생성하려면**

1. **Create model**(모델 생성)을 선택합니다.

1. **이름**에 **result**를 입력합니다.

1. **콘텐츠 유형**에 **application/json**을 입력합니다.

   일치하는 콘텐츠 유형이 없는 경우 요청 확인이 수행되지 않습니다. 콘텐츠 유형에 관계없이 동일한 모델을 사용하려면 **\$1default**를 입력합니다.

1. **모델 스키마**에서 *restapi-id*를 사용하여 다음 모델을 입력합니다. *resapi-id*는 다음 흐름에서 콘솔 상단에 괄호 안에 표시됩니다. `API Gateway > APIs > LambdaCalc (abc123).` 

   ```
   {
       "type":"object",
       "properties":{
           "input":{
               "$ref":"https://apigateway.amazonaws.com/restapis/restapi-id/models/input"
           },
           "output":{
               "$ref":"https://apigateway.amazonaws.com/restapis/restapi-id/models/output"
           }
       },
       "title":"result"
   }
   ```

1. **Create model**(모델 생성)을 선택합니다.

이제 수신되는 요청의 본문에서 요청 검사를 활성화하도록 POST 메서드의 메서드 요청을 구성합니다.

**POST 메서드에서 요청 검증을 활성화하려면**

1. 기본 탐색 창에서 **리소스**를 선택하고 리소스 트리에서 `POST` 메서드를 선택합니다.

1. **메서드 요청** 탭의 **메서드 요청 설정**에서 **편집**을 선택합니다.

1. **요청 검사기**에서 **본문 검사**를 선택합니다.

1. **요청 본문**을 선택한 다음 **모델 추가**를 선택합니다.

1. **콘텐츠 유형**에 **application/json**을 입력합니다.

   일치하는 콘텐츠 유형이 없는 경우 요청 확인이 수행되지 않습니다. 콘텐츠 유형에 관계없이 동일한 모델을 사용하려면 **\$1default**를 입력합니다.

1. **모델**에서 **입력**을 선택합니다.

1. **저장**을 선택합니다.

이제 `POST` 메서드를 테스트하여 Lambda 함수를 간접적으로 호출하도록 적절히 설정되었는지 확인할 수 있습니다.

**`POST` 메서드를 테스트하는 방법**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **요청 본문**에 다음 JSON 페이로드를 입력합니다.

   ```
   {
       "a": 1,
       "b": 2,
       "op": "+"
   }
   ```

1. **테스트**를 선택합니다.

   다음 결과가 표시됩니다.

   ```
   {
     "a": 1,
     "b": 2,
     "op": "+",
     "c": 3
   }
   ```

## 통합 3: Lambda 함수를 호출하기 위해 경로 파라미터를 사용하여 `GET` 메서드 생성
<a name="api-as-lambda-proxy-expose-get-method-with-path-parameters-to-call-lambda-function"></a>

이제 백엔드 Lambda 함수를 호출하는 경로 파라미터 시퀀스가 지정한 리소스에 `GET` 메서드를 만들어 보겠습니다. 경로 파라미터 값은 Lambda 함수에 대한 입력 데이터를 지정합니다. 받는 경로 파라미터 값을 필수 통합 요청 페이로드에 매핑하는 매핑 템플릿을 사용합니다.

이렇게 만들어진 API 리소스 구조는 다음과 같습니다.

![\[API Gateway에서 Lambda 프록시로 API 생성\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/aws_proxy_lambda_create_api_resources_new_console.png)


****/\$1operand1\$1/\$1operand2\$1/\$1operator\$1** 리소스를 생성하려면**

1. **리소스 생성**을 선택합니다.

1. **리소스 경로**에서 `/calc`를 선택합니다.

1. **리소스 이름**에 **\$1operand1\$1**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

1. **리소스 경로**에서 `/calc/{operand1}/`를 선택합니다.

1. **리소스 이름**에 **\$1operand2\$1**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

1. **리소스 경로**에서 `/calc/{operand1}/{operand2}/`를 선택합니다.

1. **리소스 이름**에 **\$1operator\$1**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

이번에는 API Gateway 콘솔에서 기본으로 제공하는 Lambda 통합 기능을 사용하여 메서드 통합을 설정합니다.

**메서드 통합을 설정하려면**

1. **/\$1operand1\$1/\$1operand2\$1/\$1operator\$1** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **GET**을 선택합니다.

1. **통합 유형**에서 **Lambda**를 선택합니다.

1. **Lambda 프록시 통합**을 비활성화된 상태로 유지합니다.

1. **Lambda 함수**에서 Lambda 함수를 생성한 AWS 리전을 선택하고 **Calc**를 입력합니다.

1. **기본 제한 시간**을 켜진 상태로 둡니다.

1. **메서드 생성**을 선택합니다.

이제 **/calc/\$1operand1\$1/\$1operand2\$1/\$1operator\$1** 리소스가 생성될 때 선언된 URL 경로 파라미터를 JSON 객체의 지정 속성 값에 매핑하는 매핑 템플릿을 생성합니다. URL 경로가 URL로 인코딩되어야 하므로 나눗셈 연산자는 `%2F`가 아닌 `/`로 지정해야 합니다. 이 템플릿은 `%2F`를 '`'/'`로 변환한 다음 Lambda 함수에 전달합니다.

**매핑 템플릿을 생성하려면**

1. **통합 요청** 탭의 **통합 요청 설정**에서 **편집**을 선택합니다.

1. **요청 본문 패스스루**에서 **정의된 템플릿이 없는 경우(권장)**를 선택합니다.

1. **매핑 템플릿**을 선택합니다.

1. **콘텐츠 유형**에 **application/json**을 입력합니다.

1. **템플릿 본문**에 다음 코드를 입력합니다.

   ```
   {
      "a": "$input.params('operand1')",
      "b": "$input.params('operand2')",
      "op": #if($input.params('operator')=='%2F')"/"#{else}"$input.params('operator')"#end
   }
   ```

1. **저장**을 선택합니다.

이제 Lambda 함수를 간접적으로 호출하고 매핑 없이 통합 응답을 통해 원본 출력을 전달하도록 적절히 설정되었는지 확인하기 위해 `GET` 메서드를 테스트할 수 있습니다.

**`GET` 메서드를 테스트하는 방법**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **경로**에서 다음을 수행합니다.

   1. **operand1**에 **1**을 입력합니다.

   1. **operand2**에 **1**을 입력합니다.

   1. **operator**에 **\$1**를 입력합니다.

1. **테스트**를 선택합니다.

1. 결과는 다음과 같아야 합니다.  
![\[API Gateway 콘솔에서 GET 메서드를 테스트합니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/aws_proxy_lambda_calc_get_method_test_path_parm_new_console.png)

그런 다음 `result` 스키마 이후 메서드 응답 페이로드의 데이터 구조를 모델링합니다.

기본적으로 메서드 응답 본문에는 빈 모델이 지정됩니다. 이 때문에 통합 응답 본문이 매핑되지 않고 통과합니다. 그러나 Java 또는 Objective-C와 같은 강력한 형식의 언어 중 하나에 대한 SDK를 생성하는 경우 결과적으로 SDK 사용자가 빈 객체를 수신하게 됩니다. REST 클라이언트 및 SDK 클라이언트 모두 원하는 결과를 수신하도록 하려면 사전 정의된 스키마를 사용하여 응답 데이터를 모델링해야 합니다. 여기에서는 메서드 응답 본문에 대한 모델을 정의하고 통합 응답 본문을 메서드 응답 본문으로 변환하는 매핑 템플릿을 구성하겠습니다.

**메서드 응답을 생성하려면**

1. **메서드 응답** 탭의 **응답 200**에서 **편집**을 선택합니다.

1. **요청 본문**에서 **모델 추가**를 선택합니다.

1. **콘텐츠 유형**에 **application/json**을 입력합니다.

1. **모델**에서 **결과**를 선택합니다.

1. **저장**을 선택합니다.

메서드 응답 본문에 대한 모델을 설정하여 응답 데이터가 주어진 SDK의 `result` 객체에 캐스팅되도록 합니다. 통합 응답 데이터가 적절히 매핑되게 하려면 매핑 템플릿이 필요합니다.

**매핑 템플릿을 생성하려면**

1. **통합 응답** 탭의 **기본값 - 응답**에서 **편집**을 선택합니다.

1. **매핑 템플릿**을 선택합니다.

1. **콘텐츠 유형**에 **application/json**을 입력합니다.

1. **템플릿 본문**에 다음 코드를 입력합니다.

   ```
   #set($inputRoot = $input.path('$'))
   {
     "input" : {
       "a" : $inputRoot.a,
       "b" : $inputRoot.b,
       "op" : "$inputRoot.op"
     },
     "output" : {
       "c" : $inputRoot.c
     }
   }
   ```

1. **저장**을 선택합니다.

**매핑 템플릿을 테스트하려면**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **경로**에서 다음을 수행합니다.

   1. **operand1**에 **1**을 입력합니다.

   1. **operand2**에 **2**을 입력합니다.

   1. **operator**에 **\$1**를 입력합니다.

1. **테스트**를 선택합니다.

1. 결과는 다음과 같습니다.

   ```
   {
     "input": {
       "a": 1,
       "b": 2,
       "op": "+"
     },
     "output": {
       "c": 3
     }
   }
   ```

이 시점에서는, API Gateway 콘솔에서 **테스트** 기능을 사용해서만 API를 직접적으로 호출할 수 있습니다. 클라이언트가 호출할 수 있게 하려면 API를 배포해야 합니다. 리소스 또는 메서드를 추가, 수정, 삭제하거나, 데이터 매핑을 업데이트하거나, 단계 설정을 업데이트할 때마다 항상 API를 다시 배포하십시오. 다음과 같이 다시 배포하지 않으면 API의 클라이언트가 새 기능 또는 업데이트를 사용할 수 없습니다.

**API를 배포하려면**

1. **Deploy API(API 배포)**를 선택합니다.

1. **스테이지**에서 **새 스테이지**를 선택합니다.

1. **단계 이름**에 **Prod**를 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **배포(Deploy)**를 선택합니다.

1.  (선택 사항) **스테이지 세부 정보**의 **URL 호출**에서 복사 아이콘을 선택하여 API의 호출 URL을 복사합니다. 이 URL을 [Postman](https://www.postman.com) 및 [cURL](https://curl.se/)과 같은 도구에서 사용하여 API를 테스트할 수 있습니다.

**참고**  
리소스 또는 메서드를 추가, 수정, 삭제하거나, 데이터 매핑을 업데이트하거나, 스테이지 설정을 업데이트할 때마다 항상 API를 다시 배포합니다. 다시 배포하지 않으면 API의 클라이언트가 새 기능 또는 업데이트를 사용할 수 없습니다.

# Lambda 함수와 통합된 샘플 API의 OpenAPI 정의
<a name="api-as-lambda-proxy-export-swagger-with-extensions"></a>

------
#### [ OpenAPI 2.0 ]

```
{
  "swagger": "2.0",
  "info": {
    "version": "2017-04-20T04:08:08Z",
    "title": "LambdaCalc"
  },
  "host": "uojnr9hd57.execute-api.us-east-1.amazonaws.com",
  "basePath": "/test",
  "schemes": [
    "https"
  ],
  "paths": {
    "/calc": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "operand2",
            "in": "query",
            "required": true,
            "type": "string"
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "type": "string"
          },
          {
            "name": "operand1",
            "in": "query",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            },
            "headers": {
              "operand_1": {
                "type": "string"
              },
              "operand_2": {
                "type": "string"
              },
              "operator": {
                "type": "string"
              }
            }
          }
        },
        "x-amazon-apigateway-request-validator": "Validate query string parameters and headers",
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.operator": "integration.response.body.op",
                "method.response.header.operand_2": "integration.response.body.b",
                "method.response.header.operand_1": "integration.response.body.a"
              },
              "responseTemplates": {
                "application/json": "#set($res = $input.path('$'))\n{\n    \"result\": \"$res.a, $res.b, $res.op => $res.c\",\n  \"a\" : \"$res.a\",\n  \"b\" : \"$res.b\",\n  \"op\" : \"$res.op\",\n  \"c\" : \"$res.c\"\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST",
          "requestTemplates": {
            "application/json": "{\n    \"a\":  \"$input.params('operand1')\",\n    \"b\":  \"$input.params('operand2')\", \n    \"op\": \"$input.params('operator')\"   \n}"
          },
          "type": "aws"
        }
      },
      "post": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "in": "body",
            "name": "Input",
            "required": true,
            "schema": {
              "$ref": "#/definitions/Input"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            }
          }
        },
        "x-amazon-apigateway-request-validator": "Validate body",
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "default": {
              "statusCode": "200",
              "responseTemplates": {
                "application/json": "#set($inputRoot = $input.path('$'))\n{\n  \"a\" : $inputRoot.a,\n  \"b\" : $inputRoot.b,\n  \"op\" : $inputRoot.op,\n  \"c\" : $inputRoot.c\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_templates",
          "httpMethod": "POST",
          "type": "aws"
        }
      }
    },
    "/calc/{operand1}/{operand2}/{operator}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "operand2",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "operator",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "operand1",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "default": {
              "statusCode": "200",
              "responseTemplates": {
                "application/json": "#set($inputRoot = $input.path('$'))\n{\n  \"input\" : {\n    \"a\" : $inputRoot.a,\n    \"b\" : $inputRoot.b,\n    \"op\" : \"$inputRoot.op\"\n  },\n  \"output\" : {\n    \"c\" : $inputRoot.c\n  }\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_templates",
          "httpMethod": "POST",
          "requestTemplates": {
            "application/json": "{\n   \"a\": \"$input.params('operand1')\",\n   \"b\": \"$input.params('operand2')\",\n   \"op\": #if($input.params('operator')=='%2F')\"/\"#{else}\"$input.params('operator')\"#end\n   \n}"
          },
          "contentHandling": "CONVERT_TO_TEXT",
          "type": "aws"
        }
      }
    }
  },
  "definitions": {
    "Input": {
      "type": "object",
      "required": [
        "a",
        "b",
        "op"
      ],
      "properties": {
        "a": {
          "type": "number"
        },
        "b": {
          "type": "number"
        },
        "op": {
          "type": "string",
          "description": "binary op of ['+', 'add', '-', 'sub', '*', 'mul', '%2F', 'div']"
        }
      },
      "title": "Input"
    },
    "Output": {
      "type": "object",
      "properties": {
        "c": {
          "type": "number"
        }
      },
      "title": "Output"
    },
    "Result": {
      "type": "object",
      "properties": {
        "input": {
          "$ref": "#/definitions/Input"
        },
        "output": {
          "$ref": "#/definitions/Output"
        }
      },
      "title": "Result"
    }
  },
  "x-amazon-apigateway-request-validators": {
    "Validate body": {
      "validateRequestParameters": false,
      "validateRequestBody": true
    },
    "Validate query string parameters and headers": {
      "validateRequestParameters": true,
      "validateRequestBody": false
    }
  }
}
```

------

# 자습서: Amazon Kinesis 프록시로 REST API 생성
<a name="integrating-api-with-aws-services-s3"></a>

API Gateway에서 REST API를 사용하여 Amazon S3를 프록시하는 과정을 보여주는 이 예제 단원에서는 REST API를 생성하여 다음 Amazon S3 작업을 노출하도록 구성하는 방법을 설명합니다.
+ API의 루트 리소스에서 GET을 노출하여 [호출자의 모든 Amazon S3 버킷을 나열합니다](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html).
+ 폴더 리소스에서 GET을 노출하여 [Amazon S3 버킷의 모든 객체 목록을 봅니다](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html).
+ 폴더/항목 리소스에서 GET을 노출하여 [Amazon S3 버킷에서 객체를 보거나 다운로드합니다](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html).

 [Amazon S3 프록시로 샘플 API의 OpenAPI 정의](api-as-s3-proxy-export-swagger-with-extensions.md)에 표시된 대로 샘플 API를 Amazon S3 프록시로 가져올 수 있습니다. 이 샘플에는 노출된 메서드가 더 많이 포함되어 있습니다. OpenAPI 정의를 사용하여 API를 가져오는 방법에 대한 지침은 [API Gateway에서 OpenAPI를 사용하여 REST API 개발](api-gateway-import-api.md) 단원을 참조하십시오.

**참고**  
 API Gateway API를 Amazon S3와 통합하려면 API Gateway와 Amazon S3 서비스를 모두 사용할 수 있는 리전을 선택해야 합니다. 리전 사용 가능성은 [Amazon API Gateway 엔드포인트 및 할당량](https://docs.aws.amazon.com/general/latest/gr/apigateway.html) 단원을 참조하십시오.

**Topics**
+ [API에서 Amazon S3 작업을 호출하도록 허용하는 IAM 권한 설정](#api-as-s3-proxy-iam-permissions)
+ [API 리소스를 생성하여 Amazon S3 리소스 표시](#api-as-s3-proxy-create-resources)
+ [API 메서드를 노출하여 호출자의 Amazon S3 버킷 나열](#api-root-get-as-s3-get-service)
+ [API 메서드를 노출하여 Amazon S3 버킷 액세스](#api-folder-operations-as-s3-bucket-actions)
+ [API 메서드를 노출하여 버킷에서 Amazon S3 객체 액세스](#api-items-in-folder-as-s3-objects-in-bucket)
+ [Amazon S3 프록시로 샘플 API의 OpenAPI 정의](api-as-s3-proxy-export-swagger-with-extensions.md)
+ [REST API 클라이언트를 사용하여 API 호출](api-as-s3-proxy-test-using-postman.md)

## API에서 Amazon S3 작업을 호출하도록 허용하는 IAM 권한 설정
<a name="api-as-s3-proxy-iam-permissions"></a>

 API에서 Amazon S3 작업을 간접적으로 호출하도록 허용하려면 적절한 IAM 정책을 IAM 역할에 연결해야 합니다. 이 단계에서는 새 IAM 역할을 생성합니다.

**AWS 서비스 프록시 실행 역할을 생성하려면**

1. AWS Management Console에 로그인하여 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 에서 IAM 콘솔을 엽니다.

1. **Roles**를 선택합니다.

1. **역할 생성**을 선택합니다.

1.  **신뢰할 수 있는 유형의 엔터티 선택**에서 **AWS 서비스**를 선택한 다음 **API Gateway**를 선택하고 **API Gateway가 로그를 CloudWatch Logs로 푸시하도록 허용**을 선택합니다.

1.  **다음**을 선택한 후 다시 **다음**을 선택합니다.

1. **역할 이름**에 **APIGatewayS3ProxyPolicy**를 입력한 다음 **역할 생성**을 선택합니다.

1. **역할** 목록에서 방금 생성한 역할을 선택합니다. 스크롤하거나 검색 창을 사용하여 역할을 찾을 수 있습니다.

1. 선택한 역할에 대해 **권한 추가** 탭을 선택합니다.

1. 드롭다운 목록에서 **정책 연결**을 선택합니다.

1. 검색 창에 **AmazonS3FullAccess**를 입력하고 **권한 추가**를 선택합니다.
**참고**  
이 자습서에서는 단순화를 위해 관리형 정책을 사용합니다. 가장 좋은 방법은 필요한 최소 권한을 부여하는 자체 IAM 정책을 생성하는 것입니다.

1. 새로 생성된 **역할 ARN**은 나중에 사용할 수 있도록 기록해 둡니다.

## API 리소스를 생성하여 Amazon S3 리소스 표시
<a name="api-as-s3-proxy-create-resources"></a>

API의 루트(`/`) 리소스를 인증된 호출자의 Amazon S3 버킷 컨테이너로 사용합니다. 또한 `Folder` 및 `Item` 리소스를 생성하여 각각 특정 Amazon S3 버킷과 특정 Amazon S3 객체를 표시합니다. 호출자는 요청 URL의 일부로 폴더 이름과 객체 키를 경로 파라미터 형식으로 지정합니다.

**참고**  
객체 키가 `/`나 다른 특수 문자를 포함하는 객체나에 액세스할 때 문자는 URL로 인코딩되어야 합니다. 예를 들어 `test/test.txt`는 `test%2Ftest.txt`으로 인코딩되어야 합니다.

**Amazon S3 서비스 기능을 표시하는 API 리소스를 생성하려면**

1.  Amazon S3 버킷을 생성한 AWS 리전에서 **MyS3**라는 API를 생성합니다. 이 API의 루트 리소스 **/**는 Amazon S3 서비스를 가리킵니다. 이 단계에서는**/\$1folder\$1**와 **/\$1item\$1**이라는 두 개의 추가 리소스를 생성합니다.

1. **리소스 생성**을 선택합니다.

1. **프록시 리소스**는 꺼진 상태로 둡니다.

1. **리소스 경로**에서 `/`를 선택합니다.

1. **리소스 이름**에 **\$1folder\$1**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 선택 취소된 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

1. **/\$1folder\$1** 리소스를 선택한 다음 **리소스 생성**을 선택합니다.

1. 이전 단계를 사용하여 이름이 **\$1item\$1**인 하위 리소스 **/\$1folder\$1**를 생성합니다.

   최종 API는 다음과 같아야 합니다.

      
![\[API Gateway에서 Amazon S3 프록시로 API 생성\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/aws_proxy_s3_create_api-resources_new_console.png)

## API 메서드를 노출하여 호출자의 Amazon S3 버킷 나열
<a name="api-root-get-as-s3-get-service"></a>

호출자의 Amazon S3 버킷 목록을 가져오는 중에 Amazon S3에서 [GET Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html) 작업을 호출합니다. API의 루트 리소스(**/**)에서 GET 메서드를 생성합니다. 다음과 같이 Amazon S3와 통합하도록 GET 메서드를 구성합니다.

**API의 `GET /` 메서드를 생성하고 초기화하는 방법**

1. **/** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. 메서드 유형에서 **GET**을 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Amazon S3 버킷을 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Amazon Simple Storage Service**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에서 **GET**을 선택합니다.

1. **작업 유형**에서 **경로 재정의 사용**을 선택합니다.

   경로 재정의를 사용하면 API Gateway가 클라이언트 요청을 해당하는 [Amazon S3 REST API path-style request](https://docs.aws.amazon.com/AmazonS3/latest/userguide/RESTAPI.html)로 Amazon S3로 전달합니다. 여기에서 Amazon S3 리소스가 `s3-host-name/bucket/key` 패턴의 리소스 경로에 의해 표현됩니다. API Gateway는 `s3-host-name`을 설정하고 클라이언트가 지정한 `bucket` 및 `key`를 클라이언트에서 Amazon S3로 전달합니다.

1. **경로 재정의**에서 **/**를 입력합니다.

1. **실행 역할**에 **APIGatewayS3ProxyPolicy**의 ARN을 입력합니다.

1. **메서드 요청 설정**을 선택합니다.

   메서드 요청 설정을 사용하여 API의 이 메서드를 직접 호출할 수 있는 사용자를 제어할 수 있습니다.

1. **권한 부여**의 드롭다운 메뉴에서 `AWS_IAM`을 선택합니다.

      
![\[메서드 응답 유형 선언\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/aws_proxy_s3_setup_method_request_authorization_new_console.png)

1. **메서드 생성**을 선택합니다.

이 설정은 프런트 엔드 `GET https://your-api-host/stage/` 요청을 백엔드 `GET https://your-s3-host/`와 통합합니다.

 API에서 성공적인 응답과 예외를 호출자에게 적절히 반환하도록 **메서드 응답**에서 200, 400 및 500 응답을 선언합니다. 여기에 선언되지 않은 상태 코드의 백엔드 응답은 호출자에게 200 응답으로 반환되도록 200 응답에 대한 기본 매핑을 사용합니다.

**`GET /` 메서드에 대한 응답 유형을 선언하려면**

1.  **메서드 응답** 탭의 **응답 200**에서 **편집**을 선택합니다.

1. **헤더 추가**를 선택하고 다음을 수행합니다.

   1. **헤더 이름**에 **Content-Type**을 입력합니다.

   1. **헤더 추가(Add header)**를 선택합니다.

   이 단계를 반복하여 **Timestamp** 헤더와 **Content-Length** 헤더를 생성합니다.

1. **Save**(저장)를 선택합니다.

1. **메서드 응답** 탭의 **메서드 응답**에서 **응답 생성**을 선택합니다.

1. **HTTP 상태 코드**에 **400**을 입력합니다.

   이 응답에는 헤더를 설정하지 않습니다.

1. **Save**(저장)를 선택합니다.

1. 다음 단계를 반복하여 500 응답을 생성합니다.

   이 응답에는 헤더를 설정하지 않습니다.

Amazon S3의 통합 응답이 버킷 목록을 XML 페이로드로 반환하고 API Gateway의 기본 메서드 응답이 JSON 페이로드를 반환하므로, 백엔드 Content-Type 헤더 파라미터 값을 해당 프런트엔드 값에 매핑해야 합니다. 그렇지 않으면, 응답 본문이 실제로 XML 문자열일 경우 클라이언트는 콘텐츠 유형에 대한 `application/json`을 수신하게 됩니다. 다음 절차에서는 이렇게 설정하는 방법을 보여줍니다. 또한 클라이언트에게 Date 및 Content-Length같은 다른 헤더 파라미터를 표시하고자 합니다.

**GET / 메서드에 대한 응답 헤더 매핑 설정 방법**

1. **통합 응답** 탭의 **기본값 - 응답**에서 **편집**을 선택합니다.

1. **Content-Length** 헤더에서 매핑 값으로 **integration.response.header.Content-Length**를 입력합니다.

1. **Content-Type** 헤더에서 매핑 값으로 **integration.response.header.Content-Type**을 입력합니다.

1. **Timestamp** 헤더에서 매핑 값으로 **integration.response.header.Date**를 입력합니다.

1. **Save**(저장)를 선택합니다. 결과는 다음과 같습니다.

      
![\[메서드 응답 헤더에 통합 응답 헤더 매핑\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/aws_proxy_s3_setup_integration_response_headers_new_console.png)

1. **통합 응답** 탭의 **통합 응답**에서 **응답 생성**을 선택합니다.

1. **HTTP 상태 regex**에 **4\$1d\$12\$1**를 입력합니다. 이렇게 하면 모든 4xx HTTP 응답 상태 코드가 메서드 응답에 매핑됩니다.

1. **메서드 응답 상태 코드**에서 **400**을 선택합니다.

1. **생성(Create)**을 선택합니다.

1. 다음 단계를 반복하여 500 메서드 응답의 통합 응답을 생성합니다. **HTTP 상태 regex**에 **5\$1d\$12\$1**를 입력합니다.

지금까지 구성한 API를 테스트해 보는 것도 좋은 방법입니다.

**`GET /` 메서드를 테스트하는 방법**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **테스트**를 선택합니다. 결과는 다음 이미지와 같아야 합니다.

      
![\[API 루트 GET 버킷 결과 테스트\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/aws_proxy_s3_test_root_get_result_new_console.png)

## API 메서드를 노출하여 Amazon S3 버킷 액세스
<a name="api-folder-operations-as-s3-bucket-actions"></a>

Amazon S3 버킷을 사용하려면 /\$1folder\$1 리소스에서 `GET` 메서드를 노출하여 버킷의 객체를 나열합니다. 지침은 [API 메서드를 노출하여 호출자의 Amazon S3 버킷 나열](#api-root-get-as-s3-get-service) 단원에 설명한 지침과 비슷합니다. 더 많은 메서드를 보려면 [Amazon S3 프록시로 샘플 API의 OpenAPI 정의](api-as-s3-proxy-export-swagger-with-extensions.md)에서 샘플 API를 가져올 수 있습니다.

**폴더 리소스에 GET 메서드를 노출하려면**

1. **/\$1folder\$1** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. 메서드 유형에서 **GET**을 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Amazon S3 버킷을 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Amazon Simple Storage Service**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에서 **GET**을 선택합니다.

1. **작업 유형**에서 **경로 재정의 사용**을 선택합니다.

1. **경로 재정의**에서 **\$1bucket\$1**를 입력합니다.

1. **실행 역할**에 **APIGatewayS3ProxyPolicy**의 ARN을 입력합니다.

1. **메서드 생성**을 선택합니다.

Amazon S3 엔드포인트 URL에 `{folder}` 경로 파라미터를 설정합니다. 메서드 요청의 `{folder}` 경로 파라미터를 통합 요청의 `{bucket}` 경로 파라미터에 매핑해야 합니다.

**`{folder}`를 `{bucket}`에 매핑하려면**

1.  **통합 요청** 탭의 **통합 요청 설정**에서 **편집**을 선택합니다.

1. **URL 경로 파라미터**를 선택한 다음 **경로 파라미터 추가**를 선택합니다.

1. **이름**에 **bucket**을 입력합니다.

1. **다음에서 매핑됨**에 **method.request.path.folder**을 입력합니다.

1. **Save**(저장)를 선택합니다.

이제 API를 테스트합니다.

**`/{folder} GET` 메서드를 테스트하려면**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **경로**의 **folder**에서 버킷 이름을 입력합니다.

1. **테스트**를 선택합니다.

   테스트 결과에는 버킷의 객체 목록이 포함됩니다.

      
![\[Amazon S3 버킷을 생성하는 GET 메서드를 테스트합니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/aws_proxy_s3_test_api_folder_get_new_console.png)

## API 메서드를 노출하여 버킷에서 Amazon S3 객체 액세스
<a name="api-items-in-folder-as-s3-objects-in-bucket"></a>

Amazon S3에서는 지정된 버킷에서 객체를 액세스 및 관리하는 GET, DELETE, HEAD, OPTIONS, POST 및 PUT 작업을 지원합니다. 이 자습서에서는 `{folder}/{item}` 리소스에 `GET` 메서드를 노출하여 버킷에서 이미지를 가져옵니다. `{folder}/{item}` 리소스의 더 많은 적용 사례는 샘플 API를 참조하세요. [Amazon S3 프록시로 샘플 API의 OpenAPI 정의](api-as-s3-proxy-export-swagger-with-extensions.md) 

**아이템 리소스에 GET 메서드 노출**

1. **/\$1item\$1** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. 메서드 유형에서 **GET**을 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Amazon S3 버킷을 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Amazon Simple Storage Service**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에서 **GET**을 선택합니다.

1. **작업 유형**에서 **경로 재정의 사용**을 선택합니다.

1. **경로 재정의**에 **\$1bucket\$1/\$1object\$1**를 입력합니다.

1. **실행 역할**에 **APIGatewayS3ProxyPolicy**의 ARN을 입력합니다.

1. **메서드 생성**을 선택합니다.

Amazon S3 엔드포인트 URL에 `{folder}` 및 `{item}` 경로 파라미터를 설정합니다. 메서드 요청의 경로 파라미터를 통합 요청의 경로 파라미터에 매핑해야 합니다.

이 단계에서는 다음 작업을 수행합니다.
+ 메서드 요청의 `{folder}` 경로 파라미터를 통합 요청의 `{bucket}` 경로 파라미터에 매핑합니다.
+ 메서드 요청의 `{item}` 경로 파라미터를 통합 요청의 `{object}` 경로 파라미터에 매핑합니다.

**`{folder}`를 `{bucket}`에 매핑하고 `{item}`을 `{object}`에 매핑하려면**

1.  **통합 요청** 탭의 **통합 요청 설정**에서 **편집**을 선택합니다.

1. **URL 경로 파라미터**를 선택합니다.

1. **경로 파라미터 추가**를 선택합니다.

1. **이름**에 **bucket**을 입력합니다.

1. **다음에서 매핑됨**에 **method.request.path.folder**을 입력합니다.

1. **경로 파라미터 추가**를 선택합니다.

1. **이름**에 **object**을 입력합니다.

1. **다음에서 매핑됨**에 **method.request.path.item**을 입력합니다.

1. **Save**(저장)를 선택합니다.

**`/{folder}/{object} GET` 메서드를 테스트하려면**

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **경로**의 **folder**에서 버킷 이름을 입력합니다.

1. **경로**의 **item**에서 항목 이름을 입력합니다.

1. **테스트**를 선택합니다.

   응답 본문에는 항목의 콘텐츠가 포함됩니다.

      
![\[Amazon S3 버킷을 생성하는 GET 메서드를 테스트합니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/aws_proxy_s3_test_api_item_get_new_console.png)

   이 요청은 (“Hello world”)의 일반 텍스트를 해당 Amazon S3 버킷(amzn-s3-demo-bucket)에 지정된 파일(test.txt)의 콘텐츠로 올바르게 반환합니다.

 API Gateway에서 utf-8 인코딩된 JSON 콘텐츠 이외의 것으로 간주되는 이진 파일을 다운로드 또는 업로드하려면 추가 API 설정이 필요합니다. 개략적으로 설명하면 다음과 같습니다.

**S3에서 이진 파일을 다운로드 또는 업로드하려면**

1.  해당 파일의 미디어 유형을 API의 binaryMediaTypes에 등록합니다. 이 작업은 콘솔에서 다음과 같이 수행할 수 있습니다.

   1. API에 대한 **API 설정**을 선택합니다.

   1. **이진 미디어 형식**에서 **미디어 형식 관리**를 선택합니다.

   1. **이진 미디어 형식 추가**를 선택한 다음 필요한 미디어 형식(예: `image/png`)을 입력합니다.

   1. **변경 사항 저장**을 선택하여 설정을 저장합니다.

1. `Content-Type`(업로드하는 경우) 및/또는 `Accept`(다운로드하는 경우) 헤더를 메서드 요청에 추가하여 클라이언트에게 필요한 이진 미디어 유형을 지정하고 통합 유형에 매핑하도록 요청합니다.

1. 통합 요청(업로드하는 경우) 및 통합 응답(다운로드하는 경우)에서 **콘텐츠 처리(Content Handling)**를 `Passthrough`로 설정합니다. 해당 콘텐츠 유형에 어떤 매핑 템플릿도 정의되어 있지 않은지 확인하십시오. 자세한 내용은 [API Gateway에서 REST API의 데이터 변환](rest-api-data-transformations.md) 단원을 참조하십시오.

페이로드 크기 제한은 10MB입니다. [REST API 구성 및 실행에 대한 API Gateway 할당량](api-gateway-execution-service-limits-table.md)을(를) 참조하세요.

Amazon S3에 저장된 파일에서 올바른 콘텐츠 유형이 파일의 메타데이터로 추가되어 있는지 확인하십시오. 스트리밍 가능한 미디어 콘텐츠의 경우, `Content-Disposition:inline`도 메타데이터에 추가되어야 할 수 있습니다.

API Gateway에서의 이진 지원에 대한 자세한 내용은 [API Gateway의 콘텐츠 유형 변환](api-gateway-payload-encodings-workflow.md) 단원을 참조하십시오.

# Amazon S3 프록시로 샘플 API의 OpenAPI 정의
<a name="api-as-s3-proxy-export-swagger-with-extensions"></a>

다음 OpenAPI 정의에서는 Amazon S3 프록시로 작동하는 API를 설명합니다. 이 API에는 자습서에서 생성한 API보다 더 많은 Amazon S3 작업이 포함되어 있습니다. OpenAPI 정의에는 다음과 같은 메서드가 노출되어 있습니다.
+ API의 루트 리소스에서 GET을 노출하여 [호출자의 모든 Amazon S3 버킷을 나열합니다](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html).
+ 폴더 리소스에서 GET을 노출하여 [Amazon S3 버킷의 모든 객체 목록을 봅니다](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html).
+ 폴더 리소스에서 PUT을 노출하여 [Amazon S3에 버킷을 추가합니다](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html).
+ 폴더 리소스에서 DELETE를 노출하여 [Amazon S3에서 버킷을 제거합니다](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html).
+ 폴더/항목 리소스에서 GET을 노출하여 [Amazon S3 버킷에서 객체를 보거나 다운로드합니다](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html).
+ 폴더/항목 리소스에서 PUT을 노출하여 [Amazon S3 버킷에 객체를 업로드합니다](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html).
+ 폴더/항목 리소스에서 HEAD를 노출하여 [객체 메타데이터를 Amazon S3 버킷에 가져옵니다](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html).
+ 폴더/항목 리소스에서 DELETE를 노출하여 [Amazon S3 버킷에서 객체를 제거합니다](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html).

OpenAPI 정의를 사용하여 API를 가져오는 방법에 대한 지침은 [API Gateway에서 OpenAPI를 사용하여 REST API 개발](api-gateway-import-api.md) 단원을 참조하십시오.

유사한 API를 생성하는 방법에 대한 지침은 [자습서: Amazon Kinesis 프록시로 REST API 생성](integrating-api-with-aws-services-s3.md) 섹션을 참조하세요.

AWS IAM 권한 부여를 지원하는 [Postman](https://www.postman.com/)을 사용하여 이 API를 간접적으로 호출하는 방법은 [REST API 클라이언트를 사용하여 API 호출](api-as-s3-proxy-test-using-postman.md) 섹션을 참조하세요.

------
#### [ OpenAPI 2.0 ]

```
{
  "swagger": "2.0",
  "info": {
    "version": "2016-10-13T23:04:43Z",
    "title": "MyS3"
  },
  "host": "9gn28ca086.execute-api.{region}.amazonaws.com",
  "basePath": "/S3",
  "schemes": [
    "https"
  ],
  "paths": {
    "/": {
      "get": {
        "produces": [
          "application/json"
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Timestamp": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Content-Length": "integration.response.header.Content-Length",
                "method.response.header.Timestamp": "integration.response.header.Date"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path//",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "GET",
          "type": "aws"
        }
      }
    },
    "/{folder}": {
      "get": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Date": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Date": "integration.response.header.Date",
                "method.response.header.Content-Length": "integration.response.header.content-length"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.bucket": "method.request.path.folder"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "GET",
          "type": "aws"
        }
      },
      "put": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "required": false,
            "type": "string"
          },
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Content-Length": "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.bucket": "method.request.path.folder",
            "integration.request.header.Content-Type": "method.request.header.Content-Type"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "PUT",
          "type": "aws"
        }
      },
      "delete": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Date": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Date": "integration.response.header.Date"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.bucket": "method.request.path.folder"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "DELETE",
          "type": "aws"
        }
      }
    },
    "/{folder}/{item}": {
      "get": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "item",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "content-type": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.content-type": "integration.response.header.content-type",
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.object": "method.request.path.item",
            "integration.request.path.bucket": "method.request.path.folder"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "GET",
          "type": "aws"
        }
      },
      "head": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "item",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Content-Length": "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.object": "method.request.path.item",
            "integration.request.path.bucket": "method.request.path.folder"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "HEAD",
          "type": "aws"
        }
      },
      "put": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "required": false,
            "type": "string"
          },
          {
            "name": "item",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type",
                "method.response.header.Content-Length": "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.object": "method.request.path.item",
            "integration.request.path.bucket": "method.request.path.folder",
            "integration.request.header.Content-Type": "method.request.header.Content-Type"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "PUT",
          "type": "aws"
        }
      },
      "delete": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "item",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Length": {
                "type": "string"
              },
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response"
          },
          "500": {
            "description": "500 response"
          }
        },
        "security": [
          {
            "sigv4": []
          }
        ],
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400"
            },
            "default": {
              "statusCode": "200"
            },
            "5\\d{2}": {
              "statusCode": "500"
            }
          },
          "requestParameters": {
            "integration.request.path.object": "method.request.path.item",
            "integration.request.path.bucket": "method.request.path.folder"
          },
          "uri": "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "DELETE",
          "type": "aws"
        }
      }
    }
  },
  "securityDefinitions": {
    "sigv4": {
      "type": "apiKey",
      "name": "Authorization",
      "in": "header",
      "x-amazon-apigateway-authtype": "awsSigv4"
    }
  },
  "definitions": {
    "Empty": {
      "type": "object",
      "title": "Empty Schema"
    }
  }
}
```

------
#### [ OpenAPI 3.0 ]

```
{
  "openapi" : "3.0.1",
  "info" : {
    "title" : "MyS3",
    "version" : "2016-10-13T23:04:43Z"
  },
  "servers" : [ {
    "url" : "https://9gn28ca086.execute-api.{region}.amazonaws.com/{basePath}",
    "variables" : {
      "basePath" : {
        "default" : "S3"
      }
    }
  } ],
  "paths" : {
    "/{folder}" : {
      "get" : {
        "parameters" : [ {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Date" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "GET",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Date" : "integration.response.header.Date",
                "method.response.header.Content-Length" : "integration.response.header.content-length"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.bucket" : "method.request.path.folder"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      },
      "put" : {
        "parameters" : [ {
          "name" : "Content-Type",
          "in" : "header",
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "PUT",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Content-Length" : "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.bucket" : "method.request.path.folder",
            "integration.request.header.Content-Type" : "method.request.header.Content-Type"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      },
      "delete" : {
        "parameters" : [ {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Date" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "DELETE",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Date" : "integration.response.header.Date"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.bucket" : "method.request.path.folder"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      }
    },
    "/{folder}/{item}" : {
      "get" : {
        "parameters" : [ {
          "name" : "item",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "content-type" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "GET",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.content-type" : "integration.response.header.content-type",
                "method.response.header.Content-Type" : "integration.response.header.Content-Type"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.object" : "method.request.path.item",
            "integration.request.path.bucket" : "method.request.path.folder"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      },
      "put" : {
        "parameters" : [ {
          "name" : "Content-Type",
          "in" : "header",
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "item",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "PUT",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Content-Length" : "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.object" : "method.request.path.item",
            "integration.request.path.bucket" : "method.request.path.folder",
            "integration.request.header.Content-Type" : "method.request.header.Content-Type"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      },
      "delete" : {
        "parameters" : [ {
          "name" : "item",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "DELETE",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200"
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.object" : "method.request.path.item",
            "integration.request.path.bucket" : "method.request.path.folder"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      },
      "head" : {
        "parameters" : [ {
          "name" : "item",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "folder",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "HEAD",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path/{bucket}/{object}",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Content-Length" : "integration.response.header.Content-Length"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "requestParameters" : {
            "integration.request.path.object" : "method.request.path.item",
            "integration.request.path.bucket" : "method.request.path.folder"
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      }
    },
    "/" : {
      "get" : {
        "responses" : {
          "400" : {
            "description" : "400 response",
            "content" : { }
          },
          "500" : {
            "description" : "500 response",
            "content" : { }
          },
          "200" : {
            "description" : "200 response",
            "headers" : {
              "Content-Length" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Timestamp" : {
                "schema" : {
                  "type" : "string"
                }
              },
              "Content-Type" : {
                "schema" : {
                  "type" : "string"
                }
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration" : {
          "credentials" : "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "httpMethod" : "GET",
          "uri" : "arn:aws:apigateway:us-west-2:s3:path//",
          "responses" : {
            "4\\d{2}" : {
              "statusCode" : "400"
            },
            "default" : {
              "statusCode" : "200",
              "responseParameters" : {
                "method.response.header.Content-Type" : "integration.response.header.Content-Type",
                "method.response.header.Content-Length" : "integration.response.header.Content-Length",
                "method.response.header.Timestamp" : "integration.response.header.Date"
              }
            },
            "5\\d{2}" : {
              "statusCode" : "500"
            }
          },
          "passthroughBehavior" : "when_no_match",
          "type" : "aws"
        }
      }
    }
  },
  "components" : {
    "schemas" : {
      "Empty" : {
        "title" : "Empty Schema",
        "type" : "object"
      }
    }
  }
}
```

------

# REST API 클라이언트를 사용하여 API 호출
<a name="api-as-s3-proxy-test-using-postman"></a>

종합 자습서를 제공하기 위해 이제 AWS IAM 권한 부여를 지원하는 [Postman](https://www.postman.com/)을 사용하여 API를 호출하는 방법을 알아봅니다.<a name="api-as-s3-proxy-test-using-postman-steps"></a>

**Postman을 사용한 Amazon S3 프록시 API 호출 방법**

1. API를 배포 또는 재배포합니다. **단계 편집기(Stage Editor)** 상단의 **URL 호출(Invoke URL)** 옆에 표시된 API의 기본 URL를 적어 둡니다.

1. Postman을 시작합니다.

1. **권한 부여**(Authorization)를 선택한 다음 `AWS Signature`를 선택합니다. IAM 사용자의 액세스 키 ID 및 비밀 액세스 키를 각각 **AccessKey** 및 **SecretKey** 입력 필드에 입력합니다. API가 배포되는 AWS 리전을 **AWS 리전** 텍스트 상자에 입력합니다. **서비스 이름** 입력 필드에 `execute-api`를 입력합니다.

   IAM Management Console의 IAM 사용자 계정에 있는 **보안 자격 증명(Security Credentials)** 탭에서 키 페어를 생성할 수 있습니다.

1. `amzn-s3-demo-bucket`라는 버킷을 `{region}` 리전에 있는 Amazon S3 계정에 추가하려면:

   1. 드롭다운 메서드 목록에서 **PUT**을 선택하고 메서드 URL(`https://api-id.execute-api.aws-region.amazonaws.com/stage/folder-name`)을 입력합니다.

   1. `Content-Type` 헤더 값을 `application/xml`로 설정합니다. 콘텐츠 유형을 설정하기 전에 기존 헤더를 모두 삭제해야 할 수 있습니다.

   1. **본문** 메뉴 항목을 선택하고 다음의 XML 조각을 요청 본문으로 입력합니다.

      ```
      <CreateBucketConfiguration> 
        <LocationConstraint>{region}</LocationConstraint> 
      </CreateBucketConfiguration>
      ```

   1. **전송**을 선택하여 요청을 제출합니다. 성공한 경우 페이로드가 비어 있는 `200 OK` 응답을 수신하게 됩니다.

1. 위 지침에 따라 텍스트 파일을 버킷에 추가합니다. URL에서 **amzn-s3-demo-bucket**에 대해 `{folder}`의 버킷 이름을, **Readme.txt**에 대해 `{item}`의 파일 이름을 지정하고 파일 콘텐츠로(따라서 요청 페이로드가 됨) **Hello, World\$1**의 텍스트 문자열을 요청 페이로드로 제공하면 요청은 다음과 같이 됩니다.

   ```
   PUT /S3/amzn-s3-demo-bucket/Readme.txt HTTP/1.1
   Host: 9gn28ca086.execute-api.{region}.amazonaws.com
   Content-Type: application/xml
   X-Amz-Date: 20161015T062647Z
   Authorization: AWS4-HMAC-SHA256 Credential=access-key-id/20161015/{region}/execute-api/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date, Signature=ccadb877bdb0d395ca38cc47e18a0d76bb5eaf17007d11e40bf6fb63d28c705b
   Cache-Control: no-cache
   Postman-Token: 6135d315-9cc4-8af8-1757-90871d00847e
   
   Hello, World!
   ```

   모든 것이 순조롭게 완료되면 비어 있는 페이로드가 포함된 `200 OK` 응답을 수신할 것입니다.

1. 방금 `Readme.txt` 버킷에 추가한 `amzn-s3-demo-bucket` 파일의 콘텐츠를 얻으려면 다음과 같이 GET 요청을 합니다.

   ```
   GET /S3/amzn-s3-demo-bucket/Readme.txt HTTP/1.1
   Host: 9gn28ca086.execute-api.{region}.amazonaws.com
   Content-Type: application/xml
   X-Amz-Date: 20161015T063759Z
   Authorization: AWS4-HMAC-SHA256 Credential=access-key-id/20161015/{region}/execute-api/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=ba09b72b585acf0e578e6ad02555c00e24b420b59025bc7bb8d3f7aed1471339
   Cache-Control: no-cache
   Postman-Token: d60fcb59-d335-52f7-0025-5bd96928098a
   ```

   성공한 경우 페이로드처럼 `200 OK` 텍스트 문자열이 포함된 `Hello, World!` 응답을 수신하게 됩니다.

1. `amzn-s3-demo-bucket` 버킷에 있는 항목을 나열하려면 다음의 요청을 제출합니다.

   ```
   GET /S3/amzn-s3-demo-bucket HTTP/1.1
   Host: 9gn28ca086.execute-api.{region}.amazonaws.com
   Content-Type: application/xml
   X-Amz-Date: 20161015T064324Z
   Authorization: AWS4-HMAC-SHA256 Credential=access-key-id/20161015/{region}/execute-api/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=4ac9bd4574a14e01568134fd16814534d9951649d3a22b3b0db9f1f5cd4dd0ac
   Cache-Control: no-cache
   Postman-Token: 9c43020a-966f-61e1-81af-4c49ad8d1392
   ```

   성공적으로 수행했을 경우, 이 요청을 제출하기 전에 더 많은 파일을 해당 버킷에 추가하지 않았다면, 지정된 버킷에 단일 항목을 보여 주는 XML 페이로드가 포함된 `200 OK` 응답을 수신하게 됩니다

   ```
   <?xml version="1.0" encoding="UTF-8"?>
   <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
       <Name>apig-demo-5</Name>
       <Prefix></Prefix>
       <Marker></Marker>
       <MaxKeys>1000</MaxKeys>
       <IsTruncated>false</IsTruncated>
       <Contents>
           <Key>Readme.txt</Key>
           <LastModified>2016-10-15T06:26:48.000Z</LastModified>
           <ETag>"65a8e27d8879283831b664bd8b7f0ad4"</ETag>
           <Size>13</Size>
           <Owner>
               <ID>06e4b09e9d...603addd12ee</ID>
               <DisplayName>user-name</DisplayName>
           </Owner>
           <StorageClass>STANDARD</StorageClass>
       </Contents>
   </ListBucketResult>
   ```

**참고**  
이미지를 업로드하거나 다운로드하려면 콘텐츠 처리를 CONVERT\$1TO\$1BINARY로 설정해야 합니다.

# 자습서: REST API를 Amazon Kinesis 프록시로 생성
<a name="integrating-api-with-aws-services-kinesis"></a>

이 페이지에서는 `AWS` 유형의 통합을 통해 REST API를 생성하고 구성하여 Kinesis에 액세스하는 방법을 설명합니다.

**참고**  
 API Gateway API를 Kinesis와 통합하려면 API Gateway와 Kinesis 서비스를 모두 사용할 수 있는 리전을 선택해야 합니다. 리전 사용 가능성은 [서비스 엔드포인트 및 할당량](https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html) 단원을 참조하십시오.

 이 예시에서는 클라이언트가 다음 작업을 수행하도록 허용하는 예제 API를 생성합니다.

1. Kinesis에서 사용자의 사용 가능한 스트림 나열 

1. 지정된 스트림 생성, 설명 또는 삭제

1. 지정된 스트림에서 데이터 레코드 읽기 또는 쓰기

 위의 작업을 수행하기 위해 API에서는 다양한 리소스에 대해 각각 다음을 호출하는 메서드를 노출합니다.

1. Kinesis의 `ListStreams` 작업 

1. `CreateStream`, `DescribeStream` 또는 `DeleteStream` 작업

1. Kinesis의 `GetRecords` 또는 `PutRecords`(`PutRecord` 포함) 작업

 특히, API를 다음과 같이 빌드합니다.
+  API의 `/streams` 리소스에 HTTP GET 메서드를 노출하고 메서드를 Kinesis의 [ListStreams](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_ListStreams.html) 작업과 통합하여 호출자 계정의 스트림을 나열합니다.
+  API의 `/streams/{stream-name}` 리소스에 HTTP POST 메서드를 노출하고 메서드를 Kinesis의 [CreateStream](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_CreateStream.html) 작업과 통합하여 호출자 계정에서 명명된 스트림을 생성합니다.
+  API의 `/streams/{stream-name}` 리소스에 HTTP GET 메서드를 노출하고 메서드를 Kinesis의 [DescribeStream](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_DescribeStream.html) 작업과 통합하여 호출자 계정에서 명명된 스트림을 설명합니다.
+  API의 `/streams/{stream-name}` 리소스에 HTTP DELETE 메서드를 노출하고 메서드를 Kinesis의 [DeleteStream](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_DeleteStream.html) 작업과 통합하여 호출자 계정에서 스트림을 삭제합니다.
+  API의 `/streams/{stream-name}/record` 리소스에 HTTP PUT 메서드를 노출하고 메서드를 Kinesis의 [PutRecord](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecord.html) 작업과 통합합니다. 그러면 클라이언트가 단일 데이터 레코드를 명명된 스트림에 추가할 수 있습니다.
+  API의 `/streams/{stream-name}/records` 리소스에 HTTP PUT 메서드를 노출하고 메서드를 Kinesis의 [PutRecords](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecords.html) 작업과 통합합니다. 그러면 클라이언트가 데이터 레코드 목록을 명명된 스트림에 추가할 수 있습니다.
+  API의 `/streams/{stream-name}/records` 리소스에 HTTP GET 메서드를 노출하고 메서드를 Kinesis의 [GetRecords](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetRecords.html) 작업과 통합합니다. 그러면 클라이언트가 지정된 샤드 반복기를 사용하여 명명된 스트림에 데이터 레코드를 나열할 수 있습니다. 샤드 반복기는 순차적으로 데이터 레코드 읽기를 시작할 샤드 위치를 지정합니다.
+  API의 `/streams/{stream-name}/sharditerator` 리소스에 HTTP GET 메서드를 노출하고 메서드를 Kinesis의 [GetShardIterator](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html) 작업과 통합합니다. 이 헬퍼 메서드는 Kinesis의 `ListStreams` 작업에 제공되어야 합니다.

 여기에 제공된 지침을 다른 Kinesis 작업에 적용할 수 있습니다. Kinesis 작업의 전체 목록은 [Amazon Kinesis API 참조](https://docs.aws.amazon.com/kinesis/latest/APIReference/Welcome.html)를 참조하십시오.

 API Gateway 콘솔을 사용하여 샘플 API를 생성하는 대신 API Gateway [API 가져오기](https://docs.aws.amazon.com/apigateway/latest/api/API_ImportRestApi.html)를 사용하여 샘플 API를 API Gateway로 가져올 수 있습니다. API 가져오기를 사용하는 방법에 대한 자세한 내용은 [API Gateway에서 OpenAPI를 사용하여 REST API 개발](api-gateway-import-api.md) 단원을 참조하세요.

## API에서 Kinesis 액세스를 위한 IAM 역할 및 정책 생성
<a name="integrate-with-kinesis-create-iam-role-and-policy"></a>

 API에서 Kinesis 작업을 간접적으로 호출하도록 허용하려면 적절한 IAM 정책을 IAM 역할에 연결해야 합니다. 이 단계에서는 새 IAM 역할을 생성합니다.

**AWS 서비스 프록시 실행 역할을 생성하려면**

1. AWS Management Console에 로그인하여 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 에서 IAM 콘솔을 엽니다.

1. **Roles**를 선택합니다.

1. **역할 생성**을 선택합니다.

1.  **신뢰할 수 있는 유형의 엔터티 선택**에서 **AWS 서비스**를 선택한 다음 **API Gateway**를 선택하고 **API Gateway가 로그를 CloudWatch Logs로 푸시하도록 허용**을 선택합니다.

1.  **다음**을 선택한 후 다시 **다음**을 선택합니다.

1. **역할 이름**에 **APIGatewayKinesisProxyPolicy**를 입력한 다음 **역할 생성**을 선택합니다.

1. **역할** 목록에서 방금 생성한 역할을 선택합니다. 스크롤하거나 검색 창을 사용하여 역할을 찾을 수 있습니다.

1. 선택한 역할에 대해 **권한 추가** 탭을 선택합니다.

1. 드롭다운 목록에서 **정책 연결**을 선택합니다.

1. 검색 창에 **AmazonKinesisFullAccess**를 입력하고 **권한 추가**를 선택합니다.
**참고**  
이 자습서에서는 단순화를 위해 관리형 정책을 사용합니다. 가장 좋은 방법은 필요한 최소 권한을 부여하는 자체 IAM 정책을 생성하는 것입니다.

1. 새로 생성된 **역할 ARN**은 나중에 사용할 수 있도록 기록해 둡니다.

## API를 Kinesis 프록시로 생성
<a name="api-gateway-create-api-as-kinesis-proxy"></a>

다음 단계에 따라 API Gateway 콘솔에서 API를 생성합니다.

**API를 Kinesis에 대한 AWS 서비스 프록시로 생성**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API Gateway를 처음 사용하는 경우, 서비스의 기능을 소개하는 페이지가 나타납니다. **REST API**에서 **빌드**를 선택합니다. **예제 API 생성** 팝업이 나타나면 **확인**을 선택합니다.

   API Gateway를 처음 사용하는 것이 아닌 경우 **API 생성**을 선택합니다. **REST API**에서 **빌드**를 선택합니다.

1. **새 API(New API)**를 선택합니다.

1. **API 이름**에 **KinesisProxy**를 입력합니다. 다른 모든 필드에 대한 기본값을 그대로 유지합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **API 생성(Create API)**을 선택합니다.

 API가 생성되면 API Gateway 콘솔에 **리소스(Resources)** 페이지가 표시됩니다. 이 페이지에는 API의 루트(`/`) 리소스만 포함되어 있습니다.

## Kinesis에 스트림 나열
<a name="api-gateway-list-kinesis-streams"></a>

 Kinesis는 다음의 REST API 호출을 통해 `ListStreams` 작업을 지원합니다.

```
POST /?Action=ListStreams HTTP/1.1
Host: kinesis.<region>.<domain>
Content-Length: <PayloadSizeBytes>
User-Agent: <UserAgentString>
Content-Type: application/x-amz-json-1.1
Authorization: <AuthParams>
X-Amz-Date: <Date>
        
{
   ...
}
```

위의 REST API 요청에서 작업은 `Action` 쿼리 파라미터에 지정합니다. 또는 다음과 같이 `X-Amz-Target` 헤더에서 작업을 지정할 수도 있습니다.

```
POST / HTTP/1.1
Host: kinesis.<region>.<domain>
Content-Length: <PayloadSizeBytes>
User-Agent: <UserAgentString>
Content-Type: application/x-amz-json-1.1
Authorization: <AuthParams>
X-Amz-Date: <Date>
X-Amz-Target: Kinesis_20131202.ListStreams        
{
   ...
}
```

이 자습서에서는 쿼리 파라미터를 사용하여 작업을 지정합니다.

API에 Kinesis 작업을 표시하려면 `/streams` 리소스를 API의 루트에 추가합니다. 그런 다음 리소스에 `GET` 메서드를 설정하고 그 메서드를 Kinesis의 `ListStreams` 작업과 통합합니다.

다음 절차에서는 API Gateway 콘솔을 사용하여 Kinesis 스트림을 나열하는 방법에 대해 설명합니다.

**API Gateway 콘솔을 사용하여 Kinesis 스트림을 나열하려면**

1. `/` 리소스를 선택한 다음 **리소스 생성**을 선택합니다.

1. **리소스 이름**에 **streams**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

1.  `/streams` 리소스를 선택한 후 **메서드 생성**을 선택하고 다음을 수행합니다.

   1. **메서드 유형**에서 **GET**을 선택합니다.
**참고**  
클라이언트에 의해 호출된 메서드에 대한 HTTP 동사는 백엔드에서 요구하는 통합에 대한 HTTP 동사와 다를 수 있습니다. 여기에서는 `GET`을 선택했는데, 목록 스트림이 본질적으로 읽기(READ) 작업이기 때문입니다.

   1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

   1. **AWS 리전**에서 Kinesis 스트림을 생성한 AWS 리전을 선택합니다.

   1. **AWS 서비스**에서 **Kinesis**를 선택합니다.

   1. **AWS 하위 도메인**은 비워 둡니다.

   1. **HTTP 메서드(HTTP method)**에 대해 **POST**를 선택합니다.
**참고**  
여기에서는 `POST`를 선택했는데, Kinesis의 경우 `ListStreams` 작업이 POST로 호출되기 때문입니다.

   1. **작업 유형**에서 **사용자 작업 이름**을 선택합니다.

   1. **함수 이름**에 **ListStreams**를 입력합니다.

   1. **실행 역할**에 실행 역할의 ARN을 입력합니다.

   1. **콘텐츠 처리**에서 **패스스루**의 기본값을 유지합니다.

   1. **메서드 생성**을 선택합니다.

1. **통합 요청** 탭의 **통합 요청 설정**에서 **편집**을 선택합니다.

1. **요청 본문 패스스루**에서 **정의된 템플릿이 없는 경우(권장)**를 선택합니다.

1.  **URL 요청 헤더 파라미터**를 선택하고 다음을 수행합니다.

   1. **요청 헤더 파라미터 추가**를 선택합니다.

   1. **이름**에 **Content-Type**을 입력합니다.

   1. **다음에서 매핑됨**에 **'application/x-amz-json-1.1'**을 입력합니다.

    `Content-Type` 헤더를 `'application/x-amz-json-1.1'`의 정적 값으로 설정하는 요청 파라미터 매핑을 사용하여 입력이 특정 버전의 JSON임을 Kinesis에 알립니다.

1. **매핑 템플릿**을 선택한 다음 **매핑 템플릿 추가**를 선택하고 다음을 수행합니다.

   1. **콘텐츠 유형**에 **application/json**을 입력합니다.

   1. **템플릿 본문**에 **\$1\$1**를 입력합니다.

   1. **저장**을 선택합니다.

    [ListStreams](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_ListStreams.html#API_ListStreams_RequestSyntax) 요청은 아래 JSON 형식의 페이로드를 취합니다.

   ```
   {
       "ExclusiveStartStreamName": "string",
       "Limit": number
   }
   ```

   하지만 속성은 선택 사항입니다. 여기에서는 기본값을 사용하기 위해 비어 있는 JSON 페이로드를 선택했습니다.

1. Kinesis에서 `ListStreams` 작업을 호출하는 GET 메서드를 **/streams** 리소스에서 테스트합니다.

   **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

   **테스트**를 선택하여 메서드를 테스트합니다.

    Kinesis에서 이미 두 개의 스트림("myStream" 및 "yourStream")을 생성했다면, 테스트가 다음의 페이로드가 포함된 200 OK 응답을 반환할 것입니다.

   ```
   {
        "HasMoreStreams": false,
        "StreamNames": [
            "myStream",
            "yourStream"
        ]
   }
   ```

## Kinesis에서 스트림 생성, 설명, 삭제
<a name="api-gateway-create-describe-delete-stream"></a>

 Kinesis에서 스트림을 생성, 설명, 삭제하는 동안 각각 다음 Kinesis REST API 요청을 생성합니다.

```
POST /?Action=CreateStream HTTP/1.1
Host: kinesis.region.domain
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "ShardCount": number,
    "StreamName": "string"
}
```

```
POST /?Action=DescribeStream HTTP/1.1
Host: kinesis.region.domain
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "StreamName": "string"
}
```

```
POST /?Action=DeleteStream HTTP/1.1
Host: kinesis.region.domain
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "StreamName":"string"
}
```

 필요한 입력을 메서드 요청의 JSON 페이로드로 수락하고 페이로드를 통합 요청으로 전달하는 API를 빌드할 수 있습니다. 하지만 메서드와 통합 요청 사이와 메서드와 통합 응답 사이에 더 많은 데이터 매핑 예제를 제공하기 위해 API를 약간 다르게 생성합니다.

 `GET`, `POST` 및 `Delete` HTTP 메서드를 `Stream`라고 명명될 리소스에 표시합니다. `{stream-name}` 경로 변수를 스트림 리소스의 자리 표시자로 사용하고 이들 API 메서드를 각각 Kinesis의 `DescribeStream`, `CreateStream` 및 `DeleteStream` 작업과 통합합니다. 클라이언트에서 다른 입력 데이터를 헤더, 쿼리 파라미터 또는 메서드 요청의 페이로드로 전달하도록 해야 합니다, 데이터를 필요한 통합 요청 페이로드로 변환하는 매핑 템플릿을 제공합니다.

**\$1stream-name\$1 리소스를 생성하려면**

1. **/streams** 리소스를 선택한 다음 **리소스 생성**을 선택합니다.

1. **프록시 리소스**는 꺼진 상태로 둡니다.

1. **리소스 경로**에서 `/streams`를 선택합니다.

1. **리소스 이름**에 **\$1stream-name\$1**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

**스트림 리소스에서 GET 메서드를 구성하고 테스트하는 방법**

1. **/\$1stream-name\$1** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **GET**을 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Kinesis 스트림을 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Kinesis**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에 대해 **POST**를 선택합니다.

1. **작업 유형**에서 **사용자 작업 이름**을 선택합니다.

1. **함수 이름**에 **DescribeStream**를 입력합니다.

1. **실행 역할**에 실행 역할의 ARN을 입력합니다.

1. **콘텐츠 처리**에서 **패스스루**의 기본값을 유지합니다.

1. **메서드 생성**을 선택합니다.

1. **통합 요청** 섹션에서 다음 **URL 요청 헤더** 파라미터를 추가합니다.

   ```
   Content-Type: 'x-amz-json-1.1'
   ```

   작업 절차는 `GET /streams` 메서드에 대한 요청 파라미터 매핑을 설정하는 절차와 같습니다.

1. 다음의 본문 매핑 템플릿을 추가하여 데이터를 `GET /streams/{stream-name}` 메서드 요청에서 `POST /?Action=DescribeStream` 통합 요청으로 매핑합니다.

   ```
   {
       "StreamName": "$input.params('stream-name')"
   }
   ```

   이 매핑 템플릿은 메서드 요청의 `DescribeStream` 경로 파라미터 값으로부터 Kinesis의 `stream-name` 작업에 대한 필수 통합 요청 페이로드를 생성합니다.

1. Kinesis에서 `DescribeStream` 작업을 간접적으로 호출하는 `GET /stream/{stream-name}` 메서드를 테스트하려면 **테스트** 탭을 선택합니다.

1. **경로**의 **stream-name**에 기존 Kinesis 스트림의 이름을 입력합니다.

1. **테스트**를 선택합니다. 테스트가 성공하면 다음과 비슷한 페이로드와 함께 200 OK 응답이 반환됩니다.

   ```
   {
     "StreamDescription": {
       "HasMoreShards": false,
       "RetentionPeriodHours": 24,
       "Shards": [
         {
           "HashKeyRange": {
             "EndingHashKey": "68056473384187692692674921486353642290",
             "StartingHashKey": "0"
           },
           "SequenceNumberRange": {
             "StartingSequenceNumber": "49559266461454070523309915164834022007924120923395850242"
           },
           "ShardId": "shardId-000000000000"
         },
         ...
         {
           "HashKeyRange": {
             "EndingHashKey": "340282366920938463463374607431768211455",
             "StartingHashKey": "272225893536750770770699685945414569164"
           },
           "SequenceNumberRange": {
             "StartingSequenceNumber": "49559266461543273504104037657400164881014714369419771970"
           },
           "ShardId": "shardId-000000000004"
         }
       ],
       "StreamARN": "arn:aws:kinesis:us-east-1:12345678901:stream/myStream",
       "StreamName": "myStream",
       "StreamStatus": "ACTIVE"
     }
   }
   ```

    API를 배포한 후에 이 API 메서드에 대해 REST 요청을 할 수 있습니다.

   ```
   GET https://your-api-id.execute-api.region.amazonaws.com/stage/streams/myStream HTTP/1.1
   Host: your-api-id.execute-api.region.amazonaws.com
   Content-Type: application/json
   Authorization: ...
   X-Amz-Date: 20160323T194451Z
   ```

**스트림 리소스에서 POST 메서드를 구성하고 테스트하는 방법**

1. **/\$1stream-name\$1** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **POST**를 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Kinesis 스트림을 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Kinesis**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에 대해 **POST**를 선택합니다.

1. **작업 유형**에서 **사용자 작업 이름**을 선택합니다.

1. **함수 이름**에 **CreateStream**를 입력합니다.

1. **실행 역할**에 실행 역할의 ARN을 입력합니다.

1. **콘텐츠 처리**에서 **패스스루**의 기본값을 유지합니다.

1. **메서드 생성**을 선택합니다.

1. **통합 요청** 섹션에서 다음 **URL 요청 헤더** 파라미터를 추가합니다.

   ```
   Content-Type: 'x-amz-json-1.1'
   ```

   작업 절차는 `GET /streams` 메서드에 대한 요청 파라미터 매핑을 설정하는 절차와 같습니다.

1.  다음의 본문 매핑 템플릿을 추가하여 데이터를 `POST /streams/{stream-name}` 메서드 요청에서 `POST /?Action=CreateStream` 통합 요청으로 매핑합니다.

   ```
   {
       "ShardCount": #if($input.path('$.ShardCount') == '') 5 #else $input.path('$.ShardCount') #end,
       "StreamName": "$input.params('stream-name')"
   }
   ```

    앞서 다룬 매핑 템플릿에서, 클라이언트가 메서드 요청 페이로드에서 값을 지정하지 않은 경우 `ShardCount`를 고정값 5로 설정합니다.

1. Kinesis에서 `CreateStream` 작업을 간접적으로 호출하는 `POST /stream/{stream-name}` 메서드를 테스트하려면 **테스트** 탭을 선택합니다.

1. **경로**의 **stream-name**에 새 Kinesis 스트림의 이름을 입력합니다.

1. **테스트**를 선택합니다. 테스트가 성공하면 아무 데이터 없이 200 OK 응답이 반환됩니다.

    API를 배포한 후에 스트림 리소스 상에서 POST 메서드에 대한 REST API 요청을 만들어 Kinesis에서 `CreateStream` 작업을 호출할 수도 있습니다.

   ```
   POST https://your-api-id.execute-api.region.amazonaws.com/stage/streams/yourStream HTTP/1.1
   Host: your-api-id.execute-api.region.amazonaws.com
   Content-Type: application/json
   Authorization: ...
   X-Amz-Date: 20160323T194451Z
   
   { 
       "ShardCount": 5
   }
   ```

**스트림 리소스에서 DELETE 메서드를 구성하고 테스트하는 방법**

1. **/\$1stream-name\$1** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **DELETE**를 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Kinesis 스트림을 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Kinesis**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에 대해 **POST**를 선택합니다.

1. **작업 유형**에서 **사용자 작업 이름**을 선택합니다.

1. **함수 이름**에 **DeleteStream**를 입력합니다.

1. **실행 역할**에 실행 역할의 ARN을 입력합니다.

1. **콘텐츠 처리**에서 **패스스루**의 기본값을 유지합니다.

1. **메서드 생성**을 선택합니다.

1. **통합 요청** 섹션에서 다음 **URL 요청 헤더** 파라미터를 추가합니다.

   ```
   Content-Type: 'x-amz-json-1.1'
   ```

   작업 절차는 `GET /streams` 메서드에 대한 요청 파라미터 매핑을 설정하는 절차와 같습니다.

1.  다음의 본문 매핑 템플릿을 추가하여 데이터를 `DELETE /streams/{stream-name}` 메서드 요청에서 `POST /?Action=DeleteStream`의 해당 통합 요청으로 매핑합니다.

   ```
   {
       "StreamName": "$input.params('stream-name')"
   }
   ```

    이 매핑 템플릿은 클라이언트에서 제공한 `DELETE /streams/{stream-name}`의 URL 경로 이름으로부터 `stream-name` 작업에 대한 필수 입력을 생성합니다.

1. Kinesis에서 `DeleteStream` 작업을 간접적으로 호출하는 `DELETE /stream/{stream-name}` 메서드를 테스트하려면 **테스트** 탭을 선택합니다.

1. **경로**의 **stream-name**에 기존 Kinesis 스트림의 이름을 입력합니다.

1. **테스트**를 선택합니다. 테스트가 성공하면 아무 데이터 없이 200 OK 응답이 반환됩니다.

    API를 배포한 후에 스트림 리소스 상에서 다음과 같은 DELETE 메서드에 대한 REST API 요청을 만들어 Kinesis에서 `DeleteStream` 작업을 호출할 수도 있습니다.

   ```
   DELETE https://your-api-id.execute-api.region.amazonaws.com/stage/streams/yourStream HTTP/1.1
   Host: your-api-id.execute-api.region.amazonaws.com
   Content-Type: application/json
   Authorization: ...
   X-Amz-Date: 20160323T194451Z
   
   {}
   ```

## Kinesis의 스트림에서 레코드 가져오기 및 추가
<a name="api-gateway-get-and-add-records-to-stream"></a>

 Kinesis에서 스트림을 생성한 후 데이터 레코드를 스트림에 추가하고 스트림에서 데이터를 읽을 수 있습니다. 데이터 레코드를 추가하는 동안 Kinesis에서 [PutRecords](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecords.html#API_PutRecords_Examples) 또는 [PutRecord](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecord.html#API_PutRecord_Examples) 작업을 호출합니다. 첫 번째 작업은 여러 레코드를 추가하고 두 번째 작업은 단일 레코드를 스트림에 추가합니다.

```
POST /?Action=PutRecords HTTP/1.1
Host: kinesis.region.domain
Authorization: AWS4-HMAC-SHA256 Credential=..., ...
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "Records": [
        {
            "Data": blob,
            "ExplicitHashKey": "string",
            "PartitionKey": "string"
        }
    ],
    "StreamName": "string"
}
```

또는

```
POST /?Action=PutRecord HTTP/1.1
Host: kinesis.region.domain
Authorization: AWS4-HMAC-SHA256 Credential=..., ...
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "Data": blob,
    "ExplicitHashKey": "string",
    "PartitionKey": "string",
    "SequenceNumberForOrdering": "string",
    "StreamName": "string"
}
```

 여기서 `StreamName`은 레코드를 추가할 타겟 스트림을 식별합니다. `StreamName`, `Data` 및 `PartitionKey`는 필요한 입력 데이터입니다. 이 예에서는 모든 선택적 입력 데이터에 대해 기본값을 사용하며 메서드 요청에 대한 입력에서 해당 값을 명시적으로 지정하지 않습니다.

 Kinesis 금액으로 데이터를 읽어 [GetRecords](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetRecords.html#API_GetRecords_Examples) 작업 호출: 

```
POST /?Action=GetRecords HTTP/1.1
Host: kinesis.region.domain
Authorization: AWS4-HMAC-SHA256 Credential=..., ...
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes

{
    "ShardIterator": "string",
    "Limit": number
}
```

샤드 반복기를 가져오기 위한 다음 Kinesis 작업에 표시된 대로 레코드를 가져올 소스 스트림은 필수 `ShardIterator` 값으로 지정됩니다.

```
POST /?Action=GetShardIterator HTTP/1.1
Host: kinesis.region.domain
Authorization: AWS4-HMAC-SHA256 Credential=..., ...
...
Content-Type: application/x-amz-json-1.1
Content-Length: PayloadSizeBytes
                
{
    "ShardId": "string",
    "ShardIteratorType": "string",
    "StartingSequenceNumber": "string",
    "StreamName": "string"
}
```

 `GetRecords` 및 `PutRecords` 작업의 경우 명명된 스트림 리소스(`GET`)에 추가되는 `PUT` 리소스에 각각 `/records` 및 `/{stream-name}` 메서드를 노출합니다. 마찬가지로 `PutRecord` 리소스에 `PUT` 작업을 `/record` 메서드로 노출합니다.

 `GetRecords` 작업은 `ShardIterator` 헬퍼 작업을 호출하여 `GetShardIterator` 값을 입력으로 가져오므로 `GET` 리소스(`ShardIterator`)에 `/sharditerator` 헬퍼 메서드를 노출합니다.

**/record, /records 및 /sharditerator 리소스를 생성하려면**

1. **/\$1stream-name\$1** 리소스를 선택한 다음 **리소스 생성**을 선택합니다.

1. **프록시 리소스**는 꺼진 상태로 둡니다.

1. **리소스 경로**에서 `/{stream-name}`를 선택합니다.

1. **리소스 이름**에 **record**을 입력합니다.

1. **오리진 간 리소스 공유(CORS)**를 꺼진 상태로 둡니다.

1. **리소스 생성**을 선택합니다.

1. 이전 단계를 반복하여 **/records**와 **/sharditerator** 리소스를 생성합니다. 최종 API는 다음과 같아야 합니다.

      
![\[API에 대한 Records:GET|PUT|PUT|GET 메서드 생성\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/api-gateway-kinesis-proxy-setup-streams-stream-record-method-new-console.png)

 다음 네 가지 절차에서는 각 메서드를 설정하는 방법, 메서드 요청에서 통합 요청으로 데이터를 매핑하는 방법, 메서드를 테스트하는 방법을 설명합니다.

**Kinesis에서 `PutRecord`를 호출할 수 있도록 `PUT /streams/{stream-name}/record` 메서드를 설정하고 테스트하려면:**

1. **/record** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **PUT**을 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Kinesis 스트림을 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Kinesis**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에 대해 **POST**를 선택합니다.

1. **작업 유형**에서 **사용자 작업 이름**을 선택합니다.

1. **함수 이름**에 **PutRecord**를 입력합니다.

1. **실행 역할**에 실행 역할의 ARN을 입력합니다.

1. **콘텐츠 처리**에서 **패스스루**의 기본값을 유지합니다.

1. **메서드 생성**을 선택합니다.

1. **통합 요청** 섹션에서 다음 **URL 요청 헤더** 파라미터를 추가합니다.

   ```
   Content-Type: 'x-amz-json-1.1'
   ```

   작업 절차는 `GET /streams` 메서드에 대한 요청 파라미터 매핑을 설정하는 절차와 같습니다.

1.  다음의 본문 매핑 템플릿을 추가하여 데이터를 `PUT /streams/{stream-name}/record` 메서드 요청에서 `POST /?Action=PutRecord`의 해당 통합 요청으로 매핑합니다.

   ```
   {
       "StreamName": "$input.params('stream-name')",
       "Data": "$util.base64Encode($input.json('$.Data'))",
       "PartitionKey": "$input.path('$.PartitionKey')"
   }
   ```

    이 매핑 템플릿에서는 메서드 요청 페이로드의 형식이 다음과 같다고 가정합니다.

   ```
   {
      "Data": "some data",
      "PartitionKey": "some key"
   }
   ```

   이 데이터는 다음의 JSON 스키마에 의해 모델링할 수 있습니다.

   ```
   {
     "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "PutRecord proxy single-record payload",
     "type": "object",
     "properties": {
         "Data": { "type": "string" },
         "PartitionKey": { "type": "string" }
     }
   }
   ```

    이 스키마를 포함하는 모델을 생성한 다음 그 모델을 사용하면 매핑 템플릿을 용이하게 생성할 수 있습니다. 하지만 모델을 사용하지 않고 매핑 템플릿을 생성할 수도 있습니다.

1.  `PUT /streams/{stream-name}/record` 메서드를 테스트하려면 `stream-name` 경로 변수를 기존 스트림 이름으로 설정하고, 필수 형식의 페이로드를 공급한 다음, 메서드 요청을 제출합니다. 테스트가 성공하면 다음 형식의 페이로드가 포함된 `200 OK ` 응답이 반환됩니다.

   ```
   {
     "SequenceNumber": "49559409944537880850133345460169886593573102115167928386",
     "ShardId": "shardId-000000000004"
   }
   ```

**Kinesis에서 `PUT /streams/{stream-name}/records`를 호출할 수 있도록 `PutRecords` 메서드를 설정하고 테스트하려면**

1. **/record** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **PUT**을 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Kinesis 스트림을 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Kinesis**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에 대해 **POST**를 선택합니다.

1. **작업 유형**에서 **사용자 작업 이름**을 선택합니다.

1. **함수 이름**에 **PutRecords**를 입력합니다.

1. **실행 역할**에 실행 역할의 ARN을 입력합니다.

1. **콘텐츠 처리**에서 **패스스루**의 기본값을 유지합니다.

1. **메서드 생성**을 선택합니다.

1. **통합 요청** 섹션에서 다음 **URL 요청 헤더** 파라미터를 추가합니다.

   ```
   Content-Type: 'x-amz-json-1.1'
   ```

   작업 절차는 `GET /streams` 메서드에 대한 요청 파라미터 매핑을 설정하는 절차와 같습니다.

1.  다음의 매핑 템플릿을 추가하여 데이터를 `PUT /streams/{stream-name}/records` 메서드 요청에서 `POST /?Action=PutRecords`의 해당 통합 요청으로 매핑합니다.

   ```
   {
       "StreamName": "$input.params('stream-name')",
       "Records": [
          #foreach($elem in $input.path('$.records'))
             {
               "Data": "$util.base64Encode($elem.data)",
               "PartitionKey": "$elem.partition-key"
             }#if($foreach.hasNext),#end
           #end
       ]
   }
   ```

   이 매핑 템플릿에서는 메서드 요청 페이로드를 다음의 JSON 스키마에 의해 모델링할 수 있다고 가정합니다.

   ```
   {
     "$schema": "http://json-schema.org/draft-04/schema#",
     "title": "PutRecords proxy payload data",
     "type": "object",
     "properties": {
       "records": {
         "type": "array",
         "items": {
           "type": "object",
           "properties": {
             "data": { "type": "string" },
             "partition-key": { "type": "string" }
           }
         }
       }
     }
   }
   ```

    이 스키마를 포함하는 모델을 생성한 다음 그 모델을 사용하면 매핑 템플릿을 용이하게 생성할 수 있습니다. 하지만 모델을 사용하지 않고 매핑 템플릿을 생성할 수도 있습니다.

   이 자습서에서는 약간 다른 두 가지 페이로드 형식을 사용하여 API 개발자가 백엔드 데이터 형식을 클라이언트에 표시하거나 클라이언트로부터 숨길 수 있음을 보여 줬습니다. 형식 하나는 `PUT /streams/{stream-name}/records` 메서드(위)에 사용되고, 다른 형식은 `PUT /streams/{stream-name}/record` 메서드(이전 절차)에 사용됩니다. 프로덕션 환경에서는 두 형식의 일관성을 유지해야 합니다.

1. 

    `PUT /streams/{stream-name}/records` 메서드를 테스트하려면 `stream-name` 경로 변수를 기존 스트림으로 설정하고, 다음의 페이로드를 공급한 다음, 메서드 요청을 제출합니다.

   ```
   {
       "records": [
           {
               "data": "some data",
               "partition-key": "some key"
           },
           {
               "data": "some other data",
               "partition-key": "some key"
           }
       ]
   }
   ```

   테스트가 성공하면 다음과 출력과 비슷한 페이로드를 포함하는 200 OK 응답이 반환됩니다.

   ```
   {
     "FailedRecordCount": 0,
     "Records": [
       {
         "SequenceNumber": "49559409944537880850133345460167468741933742152373764162",
         "ShardId": "shardId-000000000004"
       },
       {
         "SequenceNumber": "49559409944537880850133345460168677667753356781548470338",
         "ShardId": "shardId-000000000004"
       }
     ]
   }
   ```

**Kinesis에서 `GET /streams/{stream-name}/sharditerator`를 호출할 수 있도록 `GetShardIterator` 메서드를 설정하고 테스트하려면**

`GET /streams/{stream-name}/sharditerator` 메서드는 `GET /streams/{stream-name}/records` 메서드를 호출하기 전에 필수 샤드 반복자를 취득하는 헬퍼 반복자입니다.

1. **/sharditerator** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **GET**을 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Kinesis 스트림을 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Kinesis**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에 대해 **POST**를 선택합니다.

1. **작업 유형**에서 **사용자 작업 이름**을 선택합니다.

1. **함수 이름**에 **GetShardIterator**를 입력합니다.

1. **실행 역할**에 실행 역할의 ARN을 입력합니다.

1. **콘텐츠 처리**에서 **패스스루**의 기본값을 유지합니다.

1. **URL 쿼리 문자열 파라미터**를 선택합니다.

   `GetShardIterator` 작업은 ShardId 값의 입력이 요구됩니다. 클라이언트에서 제공한 `ShardId` 값을 전달하려면 다음 단계에 나온 것처럼 `shard-id` 쿼리 파라미터를 메서드 요청에 추가합니다.

1. **쿼리 문자열 추가(Add query string)**를 선택합니다.

1. **이름**에 **shard-id**을 입력합니다.

1. **필수** 상태로 유지하고 **캐싱**을 해제합니다.

1. **메서드 생성**을 선택합니다.

1. **통합 요청** 섹션에서, 메서드 요청의 `shard-id` 및 `stream-name` 파라미터에서 `GetShardIterator` 작업에 대한 필수 입력(`ShardId` 및 `StreamName`)을 생성하도록 다음과 같은 매핑 템플릿을 추가합니다. 이에 더해, 매핑 템플릿은 기본값으로 `ShardIteratorType`을 `TRIM_HORIZON`로 설정합니다.

   ```
   {
       "ShardId": "$input.params('shard-id')",
       "ShardIteratorType": "TRIM_HORIZON",
       "StreamName": "$input.params('stream-name')"
   }
   ```

1.  API Gateway 콘솔에서 **테스트(Test)** 옵션을 사용하여 기존 스트림 이름을 `stream-name` **경로(Path)** 변수 값으로 입력하고, `shard-id` **쿼리 문자열(Query string)**을 기존 `ShardId` 값(예: `shard-000000000004`)으로 설정한 다음, **테스트(Test)**를 선택합니다.

    올바른 응답 페이로드는 다음 출력과 유사합니다.

   ```
   {
     "ShardIterator": "AAAAAAAAAAFYVN3VlFy..."
   }
   ```

   [`ShardIterator`] 값을 기록해 둡니다. 스트림에서 레코드를 가져올 때 필요합니다.

**Kinesis에서 `GET /streams/{stream-name}/records` 작업을 호출할 수 있도록 `GetRecords` 메서드를 구성하고 테스트하려면**

1. **/records** 리소스를 선택한 다음 **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 **GET**을 선택합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에서 Kinesis 스트림을 생성한 AWS 리전을 선택합니다.

1. **AWS 서비스**에서 **Kinesis**를 선택합니다.

1. **AWS 하위 도메인**은 비워 둡니다.

1. **HTTP 메서드**에 대해 **POST**를 선택합니다.

1. **작업 유형**에서 **사용자 작업 이름**을 선택합니다.

1. **함수 이름**에 **GetRecords**를 입력합니다.

1. **실행 역할**에 실행 역할의 ARN을 입력합니다.

1. **콘텐츠 처리**에서 **패스스루**의 기본값을 유지합니다.

1. **HTTP 요청 헤더**를 선택합니다.

    `GetRecords` 작업은 `ShardIterator` 값의 입력이 요구됩니다. 클라이언트에서 제공한 `ShardIterator` 값을 전달하려면 `Shard-Iterator` 헤더 파라미터를 메서드 요청에 추가합니다.

1. **헤더 추가(Add header)**를 선택합니다.

1. **이름**에 **Shard-Iterator**을 입력합니다.

1. **필수** 상태로 유지하고 **캐싱**을 해제합니다.

1. **메서드 생성**을 선택합니다.

1.  **통합 요청** 섹션에서 다음의 본문 매핑 템플릿을 설정하여 `Shard-Iterator` 헤더 파라미터 값을 Kinesis에서의 `GetRecords` 작업에 대한 JSON 페이로드의 `ShardIterator` 속성 값에 매핑합니다.

   ```
   {
       "ShardIterator": "$input.params('Shard-Iterator')"
   }
   ```

1.  API Gateway 콘솔에서 **테스트** 옵션을 사용하여 기존 스트림 이름을 `stream-name` **경로** 변수 값으로 입력하고, `Shard-Iterator` **헤더**를 `GET /streams/{stream-name}/sharditerator` 메서드(위)의 테스트 실행에서 얻은 `ShardIterator` 값으로 설정한 다음, **테스트**를 선택합니다.

    올바른 응답 페이로드는 다음 출력과 유사합니다.

   ```
   {
     "MillisBehindLatest": 0,
     "NextShardIterator": "AAAAAAAAAAF...",
     "Records": [ ... ]
   }
   ```

# Kinesis 프록시로 샘플 API의 OpenAPI 정의
<a name="api-as-kinesis-proxy-export-swagger-with-extensions"></a>

다음은 이 자습서에서 Kinesis 프록시로서 샘플 API에 대한 OpenAPI 정의입니다.

------
#### [ OpenAPI 3.0 ]

```
{
  "openapi": "3.0.0",
  "info": {
    "title": "KinesisProxy",
    "version": "2016-03-31T18:25:32Z"
  },
  "paths": {
    "/streams/{stream-name}/sharditerator": {
      "get": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "shard-id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/GetShardIterator",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardId\": \"$input.params('shard-id')\",\n    \"ShardIteratorType\": \"TRIM_HORIZON\",\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}/records": {
      "get": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Shard-Iterator",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/GetRecords",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardIterator\": \"$input.params('Shard-Iterator')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "put": {
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PutRecordsMethodRequestPayload"
              }
            },
            "application/x-amz-json-1.1": {
              "schema": {
                "$ref": "#/components/schemas/PutRecordsMethodRequestPayload"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/PutRecords",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\",\n    \"Records\": [\n          {\n            \"Data\": \"$util.base64Encode($elem.data)\",\n            \"PartitionKey\": \"$elem.partition-key\"\n          }#if($foreach.hasNext),#end\n    ]\n}",
            "application/x-amz-json-1.1": "{\n  \"StreamName\": \"$input.params('stream-name')\",\n  \"records\" : [\n    {\n        \"Data\" : \"$elem.data\",\n        \"PartitionKey\" : \"$elem.partition-key\"\n    }#if($foreach.hasNext),#end\n  ]\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}": {
      "get": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/DescribeStream",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "post": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/CreateStream",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardCount\": 5,\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "delete": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "headers": {
              "Content-Type": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "headers": {
              "Content-Type": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {}
          },
          "500": {
            "description": "500 response",
            "headers": {
              "Content-Type": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {}
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/DeleteStream",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            },
            "5\\d{2}": {
              "statusCode": "500",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}/record": {
      "put": {
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/PutRecord",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\",\n    \"Data\": \"$util.base64Encode($input.json('$.Data'))\",\n    \"PartitionKey\": \"$input.path('$.PartitionKey')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams": {
      "get": {
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Empty"
                }
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/ListStreams",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Empty": {
        "type": "object"
      },
      "PutRecordsMethodRequestPayload": {
        "type": "object",
        "properties": {
          "records": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "data": {
                  "type": "string"
                },
                "partition-key": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}
```

------
#### [ OpenAPI 2.0 ]

```
{
  "swagger": "2.0",
  "info": {
    "version": "2016-03-31T18:25:32Z",
    "title": "KinesisProxy"
  },
  "basePath": "/test",
  "schemes": [
    "https"
  ],
  "paths": {
    "/streams": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/ListStreams",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/DescribeStream",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "post": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/CreateStream",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardCount\": 5,\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "delete": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            },
            "headers": {
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "400": {
            "description": "400 response",
            "headers": {
              "Content-Type": {
                "type": "string"
              }
            }
          },
          "500": {
            "description": "500 response",
            "headers": {
              "Content-Type": {
                "type": "string"
              }
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/DeleteStream",
          "responses": {
            "4\\d{2}": {
              "statusCode": "400",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            },
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            },
            "5\\d{2}": {
              "statusCode": "500",
              "responseParameters": {
                "method.response.header.Content-Type": "integration.response.header.Content-Type"
              }
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}/record": {
      "put": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/PutRecord",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\",\n    \"Data\": \"$util.base64Encode($input.json('$.Data'))\",\n    \"PartitionKey\": \"$input.path('$.PartitionKey')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}/records": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "Shard-Iterator",
            "in": "header",
            "required": false,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/GetRecords",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardIterator\": \"$input.params('Shard-Iterator')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      },
      "put": {
        "consumes": [
          "application/json",
          "application/x-amz-json-1.1"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "required": false,
            "type": "string"
          },
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "in": "body",
            "name": "PutRecordsMethodRequestPayload",
            "required": true,
            "schema": {
              "$ref": "#/definitions/PutRecordsMethodRequestPayload"
            }
          },
          {
            "in": "body",
            "name": "PutRecordsMethodRequestPayload",
            "required": true,
            "schema": {
              "$ref": "#/definitions/PutRecordsMethodRequestPayload"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/PutRecords",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"StreamName\": \"$input.params('stream-name')\",\n    \"Records\": [\n          {\n            \"Data\": \"$util.base64Encode($elem.data)\",\n            \"PartitionKey\": \"$elem.partition-key\"\n          }#if($foreach.hasNext),#end\n    ]\n}",
            "application/x-amz-json-1.1": "{\n  \"StreamName\": \"$input.params('stream-name')\",\n  \"records\" : [\n    {\n        \"Data\" : \"$elem.data\",\n        \"PartitionKey\" : \"$elem.partition-key\"\n    }#if($foreach.hasNext),#end\n  ]\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    },
    "/streams/{stream-name}/sharditerator": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "stream-name",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "shard-id",
            "in": "query",
            "required": false,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "aws",
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "uri": "arn:aws:apigateway:us-east-1:kinesis:action/GetShardIterator",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "requestParameters": {
            "integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
          },
          "requestTemplates": {
            "application/json": "{\n    \"ShardId\": \"$input.params('shard-id')\",\n    \"ShardIteratorType\": \"TRIM_HORIZON\",\n    \"StreamName\": \"$input.params('stream-name')\"\n}"
          },
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST"
        }
      }
    }
  },
  "definitions": {
    "Empty": {
      "type": "object"
    },
    "PutRecordsMethodRequestPayload": {
      "type": "object",
      "properties": {
        "records": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "data": {
                "type": "string"
              },
              "partition-key": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}
```

------

# 자습서: AWS SDK 또는 AWS CLI를 사용하여 REST API 생성
<a name="api-gateway-create-api-cli-sdk"></a>

다음 자습서를 사용하면 `GET /pets` 및 `GET /pets/{petId}` 메서드를 지원하는 PetStore API를 생성할 수 있습니다. 이러한 메서드는 HTTP 엔드포인트와 통합됩니다. AWS SDK for JavaScript, SDK for Python(Boto3) 또는 AWS CLI를 사용하여 이 튜토리얼을 따를 수 있습니다. 다음 함수 또는 명령을 사용하여 API를 설정합니다.

------
#### [ JavaScript v3 ]
+ [ CreateRestApiCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/CreateRestApiCommand/)
+ [ CreateResourceCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/CreateResourceCommand/)
+ [ PutMethodCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/PutMethodCommand/)
+ [ PutMethodResponseCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/PutMethodResponseCommand/)
+ [ PutIntegrationCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/PutIntegrationCommand/)
+ [ PutIntegrationResponseCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/PutIntegrationResponseCommand/)
+ [ CreateDeploymentCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/api-gateway/command/CreateDeploymentCommand/)

------
#### [ Python ]
+ [ create\$1rest\$1api](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/create_rest_api.html)
+ [ create\$1resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/create_resource.html)
+ [ put\$1method](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/put_method.html)
+ [ put\$1method\$1response](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/put_method_response.html)
+ [ put\$1integration](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/put_integration.html)
+ [ put\$1integration\$1response](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/put_integration_response.html)
+ [ create\$1deployment](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigateway/client/create_deployment.html)

------
#### [ AWS CLI ]
+ [create-rest-api](https://docs.aws.amazon.com/cli/latest/reference/apigateway/create-rest-api.html)
+  [create-resource](https://docs.aws.amazon.com/cli/latest/reference/apigateway/create-resource.html) 
+  [put-method](https://docs.aws.amazon.com/cli/latest/reference/apigateway/put-method.html) 
+  [put-method-response](https://docs.aws.amazon.com/cli/latest/reference/apigateway/put-method-response.html) 
+  [put-integration](https://docs.aws.amazon.com/cli/latest/reference/apigateway/put-integration.html) 
+  [put-integration-response](https://docs.aws.amazon.com/cli/latest/reference/apigateway/put-integration-response.html) 
+  [create-deployment](https://docs.aws.amazon.com/cli/latest/reference/apigateway/create-deployment.html) 

------

자바스크립트 v3용 AWS SDK에 대한 자세한 내용은 [자바스크립트용 AWS SDK란 무엇인가요?](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/welcome.html)를 참조합니다. Python(Boto3)용 SDK에 대한 자세한 내용은 [AWS SDK for Python (Boto3)](https://docs.aws.amazon.com/pythonsdk)을 참조합니다. AWS CLI에 대한 자세한 내용은 [AWS CLI란 무엇입니까?](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html)를 참조하세요.

## 엣지 최적화 PetStore API 설정
<a name="api-gateway-create-api-cli-sdk-tutorial"></a>

이 튜토리얼에서는 예시 명령의 값 ID(예: API ID 및 리소스 ID)에 자리 표시자 값이 사용됩니다. 튜토리얼을 완료할 때 이러한 값을 해당 값으로 바꾸세요.

**AWS SDK를 사용하여 엣지 최적화 PetStore API를 설정하려면**

1. 다음 예시를 따라 `RestApi` 엔터티를 생성합니다.

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

   ```
   import {APIGatewayClient, CreateRestApiCommand} from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new CreateRestApiCommand({
       name: "Simple PetStore (JavaScript v3 SDK)",
       description: "Demo API created using the AWS SDK for JavaScript v3",
       version: "0.00.001",
       binaryMediaTypes: [
       '*']
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.error(Couldn't create API:\n", err)
   }
   })();
   ```

   직접 호출이 성공하면 API ID와 API의 루트 리소스 ID가 다음과 같은 출력으로 반환됩니다.

   ```
   {
     id: 'abc1234',
     name: 'PetStore (JavaScript v3 SDK)',
     description: 'Demo API created using the AWS SDK for node.js',
     createdDate: 2017-09-05T19:32:35.000Z,
     version: '0.00.001',
     rootResourceId: 'efg567'
     binaryMediaTypes: [ '*' ] 
   }
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.create_rest_api(
           name='Simple PetStore (Python SDK)',
           description='Demo API created using the AWS SDK for Python',
           version='0.00.001',
           binaryMediaTypes=[
               '*'
           ]
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Couldn't create REST API %s.", error)
       raise
   attribute=["id","name","description","createdDate","version","binaryMediaTypes","apiKeySource","endpointConfiguration","disableExecuteApiEndpoint","rootResourceId"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   직접 호출이 성공하면 API ID와 API의 루트 리소스 ID가 다음과 같은 출력으로 반환됩니다.

   ```
   {'id': 'abc1234', 'name': 'Simple PetStore (Python SDK)', 'description': 'Demo API created using the AWS SDK for Python', 'createdDate': datetime.datetime(2024, 4, 3, 14, 31, 39, tzinfo=tzlocal()), 'version': '0.00.001', 'binaryMediaTypes': ['*'], 'apiKeySource': 'HEADER', 'endpointConfiguration': {'types': ['EDGE']}, 'disableExecuteApiEndpoint': False, 'rootResourceId': 'efg567'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway create-rest-api --name 'Simple PetStore (AWS CLI)' --region us-west-2
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "id": "abcd1234", 
       "name": "Simple PetStore (AWS CLI)", 
       "createdDate": "2022-12-15T08:07:04-08:00",
       "apiKeySource": "HEADER",
       "endpointConfiguration": {
           "types": [
               "EDGE"
           ]
       },
       "disableExecuteApiEndpoint": false,
       "rootResourceId": "efg567"
   }
   ```

------

   생성한 API의 API ID는 `abcd1234`이고 루트 리소스 ID는 `efg567`입니다. API 설정 시 이 값을 사용합니다.

1. 다음으로, 루트 아래에 하위 리소스를 추가하고 `RootResourceId`를 `parentId` 속성 값으로 지정합니다. 다음 예제를 따라 API용 `/pets` 리소스를 생성합니다.

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

   ```
   import {APIGatewayClient,  CreateResourceCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new CreateResourceCommand({
       restApiId: 'abcd1234',
       parentId: 'efg567',
       pathPart: 'pets'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The '/pets' resource setup failed:\n", err)
   }
   })();
   ```

   직접 호출이 성공하면 다음과 같은 출력으로 리소스에 대한 정보가 반환됩니다.

   ```
   {
       "path": "/pets", 
       "pathPart": "pets", 
       "id": "aaa111", 
       "parentId": "efg567'"
   }
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.create_resource(
           restApiId='abcd1234',
           parentId='efg567',
           pathPart='pets'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("The '/pets' resource setup failed: %s.", error)
       raise
   attribute=["id","parentId", "pathPart", "path",]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   직접 호출이 성공하면 다음과 같은 출력으로 리소스에 대한 정보가 반환됩니다.

   ```
   {'id': 'aaa111', 'parentId': 'efg567', 'pathPart': 'pets', 'path': '/pets'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway create-resource --rest-api-id abcd1234 \
     --region us-west-2 \
     --parent-id efg567 \
     --path-part pets
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "id": "aaa111", 
       "parentId": "efg567",
       "pathPart": "pets",
       "path": "/pets"
   }
   ```

------

   생성한 `/pets` 리소스의 리소스 ID는 `aaa111`입니다. 이 값은 API 설정 시 사용합니다.

1. 다음으로, `/pets` 리소스 아래에 하위 리소스를 추가합니다. 이 리소스 `/{petId}`에는 `{petId}`에 대한 경로 파라미터가 있습니다. 경로 부분을 경로 파라미터로 만들려면 중괄호 `{ }`로 묶습니다. 다음 예제를 따라 API용 `/pets/{petId}` 리소스를 생성합니다.

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

   ```
   import {APIGatewayClient,  CreateResourceCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new CreateResourceCommand({
       restApiId: 'abcd1234',
       parentId: 'aaa111',
       pathPart: '{petId}'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The '/pets/{petId}' resource setup failed:\n", err)
   }
   })();
   ```

   직접 호출이 성공하면 다음과 같은 출력으로 리소스에 대한 정보가 반환됩니다.

   ```
   {
       "path": "/pets/{petId}", 
       "pathPart": "{petId}", 
       "id": "bbb222", 
       "parentId": "aaa111'"
   }
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.create_resource(
           restApiId='abcd1234',
           parentId='aaa111',
           pathPart='{petId}'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("The '/pets/{petId}' resource setup failed: %s.", error)
       raise
   attribute=["id","parentId", "pathPart", "path",]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   직접 호출이 성공하면 다음과 같은 출력으로 리소스에 대한 정보가 반환됩니다.

   ```
   {'id': 'bbb222', 'parentId': 'aaa111', 'pathPart': '{petId}', 'path': '/pets/{petId}'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway create-resource --rest-api-id abcd1234 \
     --region us-west-2 \
     --parent-id aaa111 \
     --path-part '{petId}'
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "id": "bbb222",
       "parentId": "aaa111",
       "path": "/pets/{petId}", 
       "pathPart": "{petId}"
   }
   ```

------

   생성한 `/pets/{petId}` 리소스의 리소스 ID는 `bbb222`입니다. 이 값은 API 설정 시 사용합니다.

1. 다음 두 단계에서는 리소스에 HTTP 메서드를 추가합니다. 이 튜토리얼에서는 `authorization-type`을 `NONE`으로 설정하여 메서드에 오픈 액세스를 활성화합니다. 인증된 사용자만 메서드를 호출하도록 허용하려면 IAM 역할과 정책, Lambda 권한 부여자(이전에는 사용자 지정 권한 부여자라고 함) 또는 Amazon Cognito 사용자 풀을 사용할 수 있습니다. 자세한 내용은 [API Gateway에서 REST API에 대한 액세스 제어 및 관리](apigateway-control-access-to-api.md) 단원을 참조하십시오.

   다음 예제를 따라 `/pets` 리소스에 `GET` HTTP 메서드를 추가합니다.

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

   ```
   import {APIGatewayClient,  PutMethodCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutMethodCommand({
       restApiId: 'abcd1234',
       resourceId: 'aaa111',
       httpMethod: 'GET',
       authorizationType: 'NONE'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The 'GET /pets' method setup failed:\n", err)
   }
   })();
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {
       "apiKeyRequired": false, 
       "httpMethod": "GET", 
       "authorizationType": "NONE"
   }
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_method(
           restApiId='abcd1234',
           resourceId='aaa111',
           httpMethod='GET',
           authorizationType='NONE'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("The 'GET /pets' method setup failed: %s", error)
       raise
   attribute=["httpMethod","authorizationType","apiKeyRequired"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {'httpMethod': 'GET', 'authorizationType': 'NONE', 'apiKeyRequired': False}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-method --rest-api-id abcd1234 \
     --resource-id aaa111 \
     --http-method GET \
     --authorization-type "NONE" \
     --region us-west-2
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "httpMethod": "GET", 
       "authorizationType": "NONE",
       "apiKeyRequired": false
   }
   ```

------

1. 다음 예제를 따라 `/pets/{petId}` 리소스에 `GET` HTTP 메서드를 추가하고 클라이언트가 제공한 `petId` 값을 백엔드로 전달하도록 `requestParameters` 속성을 설정합니다.

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

   ```
   import {APIGatewayClient,  PutMethodCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutMethodCommand({
       restApiId: 'abcd1234',
       resourceId: 'bbb222',
       httpMethod: 'GET',
       authorizationType: 'NONE'
       requestParameters: {
           "method.request.path.petId" : true
       }
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The 'GET /pets/{petId}' method setup failed:\n", err)
   }
   })();
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {
       "apiKeyRequired": false, 
       "httpMethod": "GET", 
       "authorizationType": "NONE",
       "requestParameters": {
          "method.request.path.petId": true
       }
   }
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_method(
           restApiId='abcd1234',
           resourceId='bbb222',
           httpMethod='GET',
           authorizationType='NONE',
           requestParameters={
               "method.request.path.petId": True
           }
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("The 'GET /pets/{petId}' method setup failed: %s", error)
       raise
   attribute=["httpMethod","authorizationType","apiKeyRequired", "requestParameters" ]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {'httpMethod': 'GET', 'authorizationType': 'NONE', 'apiKeyRequired': False, 'requestParameters': {'method.request.path.petId': True}}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-method --rest-api-id abcd1234 \
     --resource-id bbb222 --http-method GET \
     --authorization-type "NONE" \
     --region us-west-2 \
     --request-parameters method.request.path.petId=true
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "httpMethod": "GET", 
       "authorizationType": "NONE", 
       "apiKeyRequired": false, 
       "requestParameters": {
           "method.request.path.petId": true
       }
   }
   ```

------

1. 다음 예시를 따라 `GET /pets` 메서드에 대한 200 OK 메서드 응답을 추가합니다.

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

   ```
   import {APIGatewayClient,  PutMethodResponseCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutMethodResponseCommand({
       restApiId: 'abcd1234',
       resourceId: 'aaa111',
       httpMethod: 'GET',
       statusCode: '200'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("Set up the 200 OK response for the 'GET /pets' method failed:\n", err)
   }
   })();
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {
       "statusCode": "200"
   }
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_method_response(
           restApiId='abcd1234',
           resourceId='aaa111',
           httpMethod='GET',
           statusCode='200'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the 200 OK response for the 'GET /pets' method failed %s.", error)
       raise
   attribute=["statusCode"]
   filtered_result ={key:result[key] for key in attribute}
   logger.info(filtered_result)
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {'statusCode': '200'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-method-response --rest-api-id abcd1234 \ 
     --resource-id aaa111 --http-method GET \
     --status-code 200  --region us-west-2
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "statusCode": "200"
   }
   ```

------

1. 다음 예시를 따라 `GET /pets/{petId}` 메서드에 대한 200 OK 메서드 응답을 추가합니다.

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

   ```
   import {APIGatewayClient,  PutMethodResponseCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutMethodResponseCommand({
       restApiId: 'abcd1234',
       resourceId: 'bbb222',
       httpMethod: 'GET',
       statusCode: '200'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("Set up the 200 OK response for the 'GET /pets/{petId}' method failed:\n", err)
   }
   })();
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {
       "statusCode": "200"
   }
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_method_response(
           restApiId='abcd1234',
           resourceId='bbb222',
           httpMethod='GET',
           statusCode='200'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the 200 OK response for the 'GET /pets/{petId}' method failed %s.", error)
       raise
   attribute=["statusCode"]
   filtered_result ={key:result[key] for key in attribute}
   logger.info(filtered_result)
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {'statusCode': '200'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-method-response --rest-api-id abcd1234 \ 
     --resource-id bbb222 --http-method GET \
     --status-code 200  --region us-west-2
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "statusCode": "200"
   }
   ```

------

1. 다음 예제를 따라 HTTP 엔드포인트가 있는 `GET /pets` 메서드의 통합을 구성합니다. HTTPS 엔드포인트는 `http://petstore-demo-endpoint.execute-api.com/petstore/pets`입니다.

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

   ```
   import {APIGatewayClient,  PutIntegrationCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutIntegrationCommand({
       restApiId: 'abcd1234',
       resourceId: 'aaa111',
       httpMethod: 'GET',
       type: 'HTTP',
       integrationHttpMethod: 'GET',
       uri: 'http://petstore-demo-endpoint.execute-api.com/petstore/pets'
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("Set up the integration of the 'GET /pets' method of the API failed:\n", err)
   }
   })();
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {
       "httpMethod": "GET", 
       "passthroughBehavior": "WHEN_NO_MATCH", 
       "cacheKeyParameters": [], 
       "type": "HTTP", 
       "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets", 
       "cacheNamespace": "ccc333"
   }
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_integration(
           restApiId='abcd1234',
           resourceId='aaa111',
           httpMethod='GET',
           type='HTTP',
           integrationHttpMethod='GET',
           uri='http://petstore-demo-endpoint.execute-api.com/petstore/pets'
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the integration of the 'GET /' method of the API failed %s.", error)
       raise
   attribute=["httpMethod","passthroughBehavior","cacheKeyParameters", "type", "uri", "cacheNamespace"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {'httpMethod': 'GET', 'passthroughBehavior': 'WHEN_NO_MATCH', 'cacheKeyParameters': [], 'type': 'HTTP', 'uri': 'http://petstore-demo-endpoint.execute-api.com/petstore/pets', 'cacheNamespace': 'ccc333'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-integration --rest-api-id abcd1234 \
     --resource-id aaa111 --http-method GET --type HTTP \
     --integration-http-method GET \
     --uri 'http://petstore-demo-endpoint.execute-api.com/petstore/pets' \
     --region us-west-2
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "type": "HTTP",
       "httpMethod": "GET",
       "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets",
       "connectionType": "INTERNET",
       "passthroughBehavior": "WHEN_NO_MATCH",
       "timeoutInMillis": 29000,
       "cacheNamespace": "6sxz2j",
       "cacheKeyParameters": []
   }
   ```

------

1. 다음 예제를 따라 HTTP 엔드포인트가 있는 `GET /pets/{petId}` 메서드의 통합을 구성합니다. HTTPS 엔드포인트는 `http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}`입니다. 이 단계에서는 경로 매개변수 `petId`를 통합 엔드포인트 경로 매개변수 `id`에 매핑합니다.

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

   ```
   import {APIGatewayClient,  PutIntegrationCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutIntegrationCommand({
       restApiId: 'abcd1234',
       resourceId: 'bbb222',
       httpMethod: 'GET',
       type: 'HTTP',
       integrationHttpMethod: 'GET',
       uri: 'http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}'
       requestParameters: {
           "integration.request.path.id": "method.request.path.petId"
        }
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("Set up the integration of the 'GET /pets/{petId}' method of the API failed:\n", err)
   }
   })();
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {
       "httpMethod": "GET", 
       "passthroughBehavior": "WHEN_NO_MATCH", 
       "cacheKeyParameters": [], 
       "type": "HTTP", 
       "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}", 
       "cacheNamespace": "ddd444",
       "requestParameters": {
          "integration.request.path.id": "method.request.path.petId"
       }
   }
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_integration(
           restApiId='ieps9b05sf',
           resourceId='t8zeb4',
           httpMethod='GET',
           type='HTTP',
           integrationHttpMethod='GET',
           uri='http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}',
           requestParameters={
               "integration.request.path.id": "method.request.path.petId"
           }
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the integration of the 'GET /pets/{petId}' method of the API failed %s.", error)
       raise
   attribute=["httpMethod","passthroughBehavior","cacheKeyParameters", "type", "uri", "cacheNamespace", "requestParameters"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {'httpMethod': 'GET', 'passthroughBehavior': 'WHEN_NO_MATCH', 'cacheKeyParameters': [], 'type': 'HTTP', 'uri': 'http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}', 'cacheNamespace': 'ddd444', 'requestParameters': {'integration.request.path.id': 'method.request.path.petId'}}}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-integration --rest-api-id abcd1234 \
     --resource-id bbb222 --http-method GET --type HTTP \
     --integration-http-method GET \
     --uri 'http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}' \ 
     --request-parameters '{"integration.request.path.id":"method.request.path.petId"}' \
     --region us-west-2
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "type": "HTTP",
       "httpMethod": "GET",
       "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}",
       "connectionType": "INTERNET",
       "requestParameters": {
           "integration.request.path.id": "method.request.path.petId"
       },
       "passthroughBehavior": "WHEN_NO_MATCH",
       "timeoutInMillis": 29000,
       "cacheNamespace": "rjkmth",
       "cacheKeyParameters": []
   }
   ```

------

1. 다음 예제를 따라 `GET /pets` 통합에 대한 통합 응답을 추가합니다.

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

   ```
   import {APIGatewayClient,  PutIntegrationResponseCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutIntegrationResponseCommand({
       restApiId: 'abcd1234',
       resourceId: 'aaa111',
       httpMethod: 'GET',
       statusCode: '200',
       selectionPattern: ''
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The 'GET /pets' method integration response setup failed:\n", err)
   }
   })();
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {
       "selectionPattern": "", 
       "statusCode": "200"
   }
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_integration_response(
           restApiId='abcd1234',
           resourceId='aaa111',
           httpMethod='GET',
           statusCode='200',
           selectionPattern='',
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the integration response of the 'GET /pets' method of the API failed: %s", error)
       raise
   attribute=["selectionPattern","statusCode"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {'selectionPattern': "", 'statusCode': '200'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-integration-response --rest-api-id abcd1234 \
     --resource-id aaa111 --http-method GET \
     --status-code 200 --selection-pattern ""  \
     --region us-west-2
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "statusCode": "200",
       "selectionPattern": "" 
   }
   ```

------

1. 다음 예제를 따라 `GET /pets/{petId}` 통합에 대한 통합 응답을 추가합니다.

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

   ```
   import {APIGatewayClient,  PutIntegrationResponseCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new PutIntegrationResponseCommand({
       restApiId: 'abcd1234',
       resourceId: 'bbb222',
       httpMethod: 'GET',
       statusCode: '200',
       selectionPattern: ''
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The 'GET /pets/{petId}' method integration response setup failed:\n", err)
   }
   })();
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {
       "selectionPattern": "", 
       "statusCode": "200"
   }
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.put_integration_response(
           restApiId='abcd1234',
           resourceId='bbb222',
           httpMethod='GET',
           statusCode='200',
           selectionPattern='',
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Set up the integration response of the 'GET /pets/{petId}' method of the API failed: %s", error)
       raise
   attribute=["selectionPattern","statusCode"]
   filtered_result ={key:result[key] for key in attribute}
   print(filtered_result)
   ```

   성공적으로 직접 호출되면 다음 출력 결과를 반환합니다.

   ```
   {'selectionPattern': "", 'statusCode': '200'}
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway put-integration-response --rest-api-id abcd1234 \
     --resource-id bbb222 --http-method GET 
     --status-code 200 --selection-pattern ""  
     --region us-west-2
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "statusCode": "200",
       "selectionPattern": "" 
   }
   ```

------

   통합 응답을 생성한 후 API는 PetStore 웹 사이트에서 사용 가능한 반려 동물을 쿼리하고 지정된 식별자의 개별 반려 동물을 볼 수 있습니다. 고객이 API를 직접적으로 호출할 수 있게 하려면 먼저 API를 배포해야 합니다. API를 배포하기 전에 테스트하는 것이 좋습니다.

1. 다음 예제를 따라 `GET /pets` 메서드를 테스트합니다.

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

   ```
   import {APIGatewayClient,  TestInvokeMethodCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new TestInvokeMethodCommand({
       restApiId: 'abcd1234',
       resourceId: 'aaa111',
       httpMethod: 'GET',
       pathWithQueryString: '/',
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The test on 'GET /pets' method failed:\n", err)
   }
   })();
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.test_invoke_method(
           restApiId='abcd1234',
           resourceId='aaa111',
           httpMethod='GET',
           pathWithQueryString='/',
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Test invoke method on 'GET /pets' failed: %s", error)
       raise
   print(result)
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway test-invoke-method --rest-api-id abcd1234 /
     --resource-id aaa111 /
     --http-method GET /
     --path-with-query-string '/'
   ```

------

1. 다음 예제를 따라 `petId`가 3인 `GET /pets/{petId}` 메서드를 테스트합니다.

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

   ```
   import {APIGatewayClient,  TestInvokeMethodCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new TestInvokeMethodCommand({
       restApiId: 'abcd1234',
       resourceId: 'bbb222',
       httpMethod: 'GET',
       pathWithQueryString: '/pets/3',
   });
   try {
       const results = await apig.send(command)
       console.log(results)
   } catch (err) {
       console.log("The test on 'GET /pets/{petId}' method failed:\n", err)
   }
   })();
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.test_invoke_method(
           restApiId='abcd1234',
           resourceId='bbb222',
           httpMethod='GET',
           pathWithQueryString='/pets/3',
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Test invoke method on 'GET /pets/{petId}' failed: %s", error)
       raise
   print(result)
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway test-invoke-method --rest-api-id abcd1234 /
     --resource-id bbb222 /
     --http-method GET /
     --path-with-query-string '/pets/3'
   ```

------

   API를 테스트에 성공하면 API를 스테이지에 배포할 수 있습니다.

1. 다음 예제를 따라 `test`라는 스테이지에 API를 배포합니다. API를 스테이지에 배포하면 API 호출자가 API를 호출할 수 있습니다.

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

   ```
   import {APIGatewayClient,  CreateDeploymentCommand } from "@aws-sdk/client-api-gateway";
   (async function (){
   const apig = new APIGatewayClient({region:"us-east-1"});
   const command = new CreateDeploymentCommand({
       restApiId: 'abcd1234',
       stageName: 'test',
       stageDescription: 'test deployment'
   });
   try {
       const results = await apig.send(command)
       console.log("Deploying API succeeded\n", results)
   } catch (err) {
       console.log("Deploying API failed:\n", err)
   }
   })();
   ```

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

   ```
   import botocore
   import boto3
   import logging
   
   logger = logging.getLogger()
   apig = boto3.client('apigateway')
   
   try:
       result = apig.create_deployment(
           restApiId='ieps9b05sf',
           stageName='test',
           stageDescription='my test stage',
       )
   except botocore.exceptions.ClientError as error:
       logger.exception("Error deploying stage  %s.", error)
       raise
   print('Deploying API succeeded')
   print(result)
   ```

------
#### [ AWS CLI ]

   ```
   aws apigateway create-deployment --rest-api-id abcd1234 \ 
     --region us-west-2 \
     --stage-name test \
     --stage-description 'Test stage' \
     --description 'First deployment'
   ```

   다음은 이 명령의 출력입니다.

   ```
   {
       "id": "ab1c1d",
       "description": "First deployment",
       "createdDate": "2022-12-15T08:44:13-08:00"
   }
   ```

------

   이제 고객이 API를 직접적으로 호출할 수 있습니다. 브라우저에 `https://abcd1234.execute-api.us-west-2.amazonaws.com/test/pets` URL을 입력하고 `abcd1234`를 API의 ID로 대체하여 이 API를 테스트할 수 있습니다.

AWS SDK 또는 AWS CLI를 사용하여 API를 생성하거나 업데이트는 방법에 대한 추가 예시는 [AWS SDK를 사용한 API Gateway에 대한 작업](https://docs.aws.amazon.com/code-library/latest/ug/api-gateway_code_examples_actions.html)을 참조하세요.

## API 설정 자동화
<a name="api-gateway-create-api-cli-sdk-iac"></a>

API를 단계별로 생성하는 대신 OpenAPI, CloudFormation 또는 Terraform을 사용해 API를 생성함으로써 AWS 리소스 생성 및 정리를 자동화할 수 있습니다.

### OpenAPI 3.0 정의
<a name="api-gateway-create-api-cli-sdk-template-OpenAPI"></a>

OpenAPI 정의를 API Gateway로 가져올 수 있습니다. 자세한 내용은 [API Gateway에서 OpenAPI를 사용하여 REST API 개발](api-gateway-import-api.md) 단원을 참조하십시오.

```
{
  "openapi" : "3.0.1",
  "info" : {
    "title" : "Simple PetStore (OpenAPI)",
    "description" : "Demo API created using OpenAPI",
    "version" : "2024-05-24T20:39:34Z"
  },
  "servers" : [ {
    "url" : "{basePath}",
    "variables" : {
      "basePath" : {
        "default" : "Prod"
      }
    }
  } ],
  "paths" : {
    "/pets" : {
      "get" : {
        "responses" : {
          "200" : {
            "description" : "200 response",
            "content" : { }
          }
        },
        "x-amazon-apigateway-integration" : {
          "type" : "http",
          "httpMethod" : "GET",
          "uri" : "http://petstore-demo-endpoint.execute-api.com/petstore/pets",
          "responses" : {
            "default" : {
              "statusCode" : "200"
            }
          },
          "passthroughBehavior" : "when_no_match",
          "timeoutInMillis" : 29000
        }
      }
    },
    "/pets/{petId}" : {
      "get" : {
        "parameters" : [ {
          "name" : "petId",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "200 response",
            "content" : { }
          }
        },
        "x-amazon-apigateway-integration" : {
          "type" : "http",
          "httpMethod" : "GET",
          "uri" : "http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}",
          "responses" : {
            "default" : {
              "statusCode" : "200"
            }
          },
          "requestParameters" : {
            "integration.request.path.id" : "method.request.path.petId"
          },
          "passthroughBehavior" : "when_no_match",
          "timeoutInMillis" : 29000
        }
      }
    }
  },
  "components" : { }
}
```

### AWS CloudFormation 템플릿
<a name="api-gateway-create-api-cli-sdk-template-CloudFormation"></a>

CloudFormation 템플릿을 배포하려면 [AWS CloudFormation 콘솔에서 스택 생성](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-create-stack.html)을 참조하세요.

```
AWSTemplateFormatVersion: 2010-09-09
Resources:
  Api:
    Type: 'AWS::ApiGateway::RestApi'
    Properties:
      Name: Simple PetStore (AWS CloudFormation)
  PetsResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref Api
      ParentId: !GetAtt Api.RootResourceId
      PathPart: 'pets'
  PetIdResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref Api
      ParentId: !Ref PetsResource
      PathPart: '{petId}'
  PetsMethodGet:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      RestApiId: !Ref Api
      ResourceId: !Ref PetsResource
      HttpMethod: GET
      AuthorizationType: NONE
      Integration:
        Type: HTTP
        IntegrationHttpMethod: GET
        Uri: http://petstore-demo-endpoint.execute-api.com/petstore/pets/
        IntegrationResponses:
          - StatusCode: '200'
      MethodResponses:
        - StatusCode: '200'
  PetIdMethodGet:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      RestApiId: !Ref Api
      ResourceId: !Ref PetIdResource
      HttpMethod: GET
      AuthorizationType: NONE
      RequestParameters: 
        method.request.path.petId: true
      Integration:
        Type: HTTP
        IntegrationHttpMethod: GET
        Uri: http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}
        RequestParameters:
          integration.request.path.id: method.request.path.petId
        IntegrationResponses:
          - StatusCode: '200'
      MethodResponses:
        - StatusCode: '200'
  ApiDeployment:
    Type: 'AWS::ApiGateway::Deployment'
    DependsOn:
      - PetsMethodGet
    Properties:
      RestApiId: !Ref Api
      StageName: Prod
Outputs:
  ApiRootUrl:
    Description: Root Url of the API
    Value: !Sub 'https://${Api}.execute-api.${AWS::Region}.amazonaws.com/Prod'
```

### Terraform 구성
<a name="api-gateway-create-api-cli-sdk-template-terraform"></a>

Terraform에 대한 자세한 내용은 [Terraform](https://developer.hashicorp.com/terraform/intro)을 참조하세요.

```
provider "aws" {
  region = "us-east-1" # Update with your desired region
}
resource "aws_api_gateway_rest_api" "Api" {
  name        = "Simple PetStore (Terraform)"
  description = "Demo API created using Terraform"
}
resource "aws_api_gateway_resource" "petsResource"{
    rest_api_id = aws_api_gateway_rest_api.Api.id
    parent_id = aws_api_gateway_rest_api.Api.root_resource_id
    path_part = "pets"
}
resource "aws_api_gateway_resource" "petIdResource"{
    rest_api_id = aws_api_gateway_rest_api.Api.id
    parent_id = aws_api_gateway_resource.petsResource.id
    path_part = "{petId}"
}
resource "aws_api_gateway_method" "petsMethodGet" {
  rest_api_id   = aws_api_gateway_rest_api.Api.id
  resource_id   = aws_api_gateway_resource.petsResource.id
  http_method   = "GET"
  authorization = "NONE"
}


resource "aws_api_gateway_method_response" "petsMethodResponseGet" {
    rest_api_id = aws_api_gateway_rest_api.Api.id 
    resource_id = aws_api_gateway_resource.petsResource.id
    http_method = aws_api_gateway_method.petsMethodGet.http_method 
    status_code ="200"
}

resource "aws_api_gateway_integration" "petsIntegration" {
  rest_api_id = aws_api_gateway_rest_api.Api.id
  resource_id = aws_api_gateway_resource.petsResource.id
  http_method = aws_api_gateway_method.petsMethodGet.http_method
  type        = "HTTP"
  
  uri                     = "http://petstore-demo-endpoint.execute-api.com/petstore/pets"
  integration_http_method = "GET"
  depends_on              = [aws_api_gateway_method.petsMethodGet]
}

resource "aws_api_gateway_integration_response" "petsIntegrationResponse" {
    rest_api_id = aws_api_gateway_rest_api.Api.id
    resource_id = aws_api_gateway_resource.petsResource.id
    http_method = aws_api_gateway_method.petsMethodGet.http_method
    status_code = aws_api_gateway_method_response.petsMethodResponseGet.status_code
}

resource "aws_api_gateway_method" "petIdMethodGet" {
    rest_api_id   = aws_api_gateway_rest_api.Api.id
    resource_id   = aws_api_gateway_resource.petIdResource.id
    http_method   = "GET"
    authorization = "NONE"
    request_parameters = {"method.request.path.petId" = true}
}

resource "aws_api_gateway_method_response" "petIdMethodResponseGet" {
    rest_api_id = aws_api_gateway_rest_api.Api.id 
    resource_id = aws_api_gateway_resource.petIdResource.id
    http_method = aws_api_gateway_method.petIdMethodGet.http_method 
    status_code ="200"
}


resource "aws_api_gateway_integration" "petIdIntegration" {
    rest_api_id = aws_api_gateway_rest_api.Api.id
    resource_id = aws_api_gateway_resource.petIdResource.id
    http_method = aws_api_gateway_method.petIdMethodGet.http_method
    type        = "HTTP"
    uri                     = "http://petstore-demo-endpoint.execute-api.com/petstore/pets/{id}"
    integration_http_method = "GET"
    request_parameters = {"integration.request.path.id" = "method.request.path.petId"}
    depends_on              = [aws_api_gateway_method.petIdMethodGet]
}

resource "aws_api_gateway_integration_response" "petIdIntegrationResponse" {
    rest_api_id = aws_api_gateway_rest_api.Api.id
    resource_id = aws_api_gateway_resource.petIdResource.id
    http_method = aws_api_gateway_method.petIdMethodGet.http_method
    status_code = aws_api_gateway_method_response.petIdMethodResponseGet.status_code
}


resource "aws_api_gateway_deployment" "Deployment" {
  rest_api_id = aws_api_gateway_rest_api.Api.id
  depends_on  = [aws_api_gateway_integration.petsIntegration,aws_api_gateway_integration.petIdIntegration ]
}
resource "aws_api_gateway_stage" "Stage" {
  stage_name    = "Prod"
  rest_api_id   = aws_api_gateway_rest_api.Api.id
  deployment_id = aws_api_gateway_deployment.Deployment.id
}
```

# 자습서: 프라이빗 REST API 생성
<a name="private-api-tutorial"></a>

이 자습서에서는 프라이빗 REST API를 생성합니다. 클라이언트는 Amazon VPC 내에서만 API에 액세스할 수 있습니다. API는 일반적인 보안 요구 사항인 공용 인터넷과 격리됩니다.

이 자습서는 완료되는데 약 30분이 걸립니다. 먼저 CloudFormation 템플릿을 사용하여 Amazon VPC, VPC 엔드포인트, AWS Lambda 함수를 생성하고 API를 테스트하는 데 사용할 Amazon EC2 인스턴스를 시작합니다. 그런 다음 AWS Management Console를 사용하여 프라이빗 API를 생성하고 VPC 엔드포인트에서만 액세스를 허용하는 리소스 정책을 연결합니다. 마지막으로 API를 테스트합니다.

![\[이 튜토리얼에서 생성하는 프라이빗 API의 개요입니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/private-api-tutorial-diagram.png)


이 자습서를 완료하려면 AWS 계정과 콘솔 액세스 권한이 있는 AWS Identity and Access Management 사용자가 있어야 합니다. 자세한 내용은 [API Gateway를 사용하도록 설정](setting-up.md) 단원을 참조하세요.

이 자습서에서는 를 사용합니다AWS Management Console 이 API 및 모든 관련 리소스를 생성하는 CloudFormation 템플릿은 [template.yaml](samples/private-api-full-template.zip)을 참조하세요.

**Topics**
+ [1단계: 종속성 생성](#private-api-tutorial-create-dependencies)
+ [2단계: 프라이빗 API 생성](#private-api-tutorial-create-api)
+ [3단계: 메서드 및 통합 생성](#private-api-tutorial-create-method)
+ [4단계: 리소스 정책 연결](#private-api-tutorial-attach-resource-policy)
+ [5 단계: API 배포](#private-api-tutorial-deploy-api)
+ [6단계: API에 공개적으로 액세스할 수 없는지 확인](#private-api-tutorial-test-private-api)
+ [7단계: VPC의 인스턴스에 연결하고 API 호출](#private-api-tutorial-connect-to-instance)
+ [8단계: 정리](#private-api-tutorial-cleanup)
+ [다음 단계: 를 통한 자동화CloudFormation](#private-api-tutorial-next-steps)

## 1단계: 종속성 생성
<a name="private-api-tutorial-create-dependencies"></a>

[이 CloudFormation 템플릿](samples/private-api-starter-template.zip)을 다운로드하고 압축을 풉니다. 템플릿을 사용하여 Amazon VPC, VPC 엔드포인트 및 API의 백엔드 역할을 하는 Lambda 함수를 포함하여 프라이빗 API에 대한 모든 종속성을 생성합니다. 나중에 프라이빗 API를 생성합니다.

**CloudFormation 스택을 생성하려면**

1. CloudFormation 콘솔([https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/))을 엽니다.

1. **스택 생성**을 선택한 다음 **새 리소스 사용(표준)**을 선택합니다.

1. **템플릿 지정**에서 **템플릿 파일 업로드**를 선택합니다.

1. 다운로드한 템플릿을 선택합니다.

1. **다음**을 선택합니다.

1. **스택 이름**에 **private-api-tutorial**을 입력하고 **다음**을 선택합니다.

1. **스택 옵션 구성**에서 **다음**을 선택합니다.

1. **기능**의 경우 CloudFormation이 계정에 IAM 리소스를 생성할 수 있음을 확인합니다.

1. **다음**을 선택한 후 **제출**을 선택합니다.

CloudFormation는 API에 대한 종속성을 프로비저닝합니다. 이 작업은 몇 분 정도 걸릴 수 있습니다. CloudFormation 스택 상태가 **CREATE\$1COMPLETE**인 경우 **출력(Outputs)**을 선택합니다. VPC 엔드포인트 ID를 적어둡니다. 이 자습서의 이후 단계를 위해 필요합니다.

## 2단계: 프라이빗 API 생성
<a name="private-api-tutorial-create-api"></a>

프라이빗 API를 생성하여 VPC 내의 클라이언트만 액세스할 수 있도록 합니다.

**프라이빗 API 생성**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **API 생성**(Create API)을 선택한 다음 **REST API**에 대해 **빌드**(Build)를 선택합니다.

1. **API 이름**에서 **private-api-tutorial**을(를) 입력합니다.

1. **API 엔드포인트 유형**에서 **프라이빗**을 선택합니다.

1. **VPC 엔드포인트 ID**의 경우 CloudFormation 스택의 **출력**에서 VPC 엔드포인트 ID를 입력합니다.

1. **IP 주소 유형**의 경우 **듀얼 스택**을 선택합니다.

1. **API 생성**을 선택합니다.

## 3단계: 메서드 및 통합 생성
<a name="private-api-tutorial-create-method"></a>

`GET` 메서드와 Lambda 통합을 생성하여 API에 대한 `GET` 요청을 처리합니다. 클라이언트가 API를 호출하면 API Gateway는 1단계에서 생성한 Lambda 함수로 요청을 보낸 다음 클라이언트에 대한 응답을 반환합니다.

**메서드 및 통합 생성**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. **메서드 생성**을 선택합니다.

1. **메서드 유형**에서 `GET`을 선택합니다.

1. **통합 유형**에서 **Lambda 함수**를 선택합니다.

1. **Lambda 프록시 통합**을 켭니다. Lambda 프록시 통합을 통해 API Gateway는 정의된 구조를 사용하여 이벤트를 Lambda에 보내고 Lambda 함수의 응답을 HTTP 응답으로 변환합니다.

1. **Lambda 함수**의 경우 1단계에서 CloudFormation 템플릿으로 생성한 함수를 선택합니다. 함수의 이름은 **private-api-tutorial**로 시작합니다.

1. **메서드 생성**을 선택합니다.

## 4단계: 리소스 정책 연결
<a name="private-api-tutorial-attach-resource-policy"></a>

클라이언트가 VPC 엔드포인트를 통해서만 API를 호출하도록 허용하는 [리소스 정책](apigateway-resource-policies.md)을 API에 연결합니다. API에 대한 액세스를 추가로 제한하기 위해 VPC 엔드포인트에 대한 [ VPC 엔드포인트 정책](apigateway-vpc-endpoint-policies.md)을 구성할 수도 있지만 이 자습서에는 필요하지 않습니다.

**리소스 정책 연결**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. **리소스 정책**, **정책 생성**을 차례로 선택합니다.

1. 다음 정책을 입력합니다. *vpceID*를 CloudFormation 스택의 **출력(Outputs)**에서 VPC 엔드포인트 ID로 바꿉니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Deny",
               "Principal": "*",
               "Action": "execute-api:Invoke",
               "Resource": "execute-api:/*",
               "Condition": {
                   "StringNotEquals": {
                       "aws:sourceVpce": "vpce-abcd1234"
                   }
               }
           },
           {
               "Effect": "Allow",
               "Principal": "*",
               "Action": "execute-api:Invoke",
               "Resource": "execute-api:/*"
           }
       ]
   }
   ```

------

1. **변경 사항 저장**을 선택합니다.

## 5 단계: API 배포
<a name="private-api-tutorial-deploy-api"></a>

그런 다음 API를 배포하여 Amazon VPC의 클라이언트가 사용할 수 있도록 합니다.

**API 배포**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. **Deploy API(API 배포)**를 선택합니다.

1. **스테이지**에서 **새 스테이지**를 선택합니다.

1. **단계 이름**에 **test**를 입력합니다.

1. (선택 사항) **설명**에 설명을 입력합니다.

1. [**Deploy**]를 선택합니다.

이제 API를 테스트 할 준비가 되었습니다.

## 6단계: API에 공개적으로 액세스할 수 없는지 확인
<a name="private-api-tutorial-test-private-api"></a>

`curl`를 사용하여 Amazon VPC 외부에서 API를 호출할 수 없는지 확인합니다.

**API 테스트하기**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. 기본 탐색 창에서 **스테이지**를 선택한 후 **테스트** 스테이지를 선택합니다.

1. **스테이지 세부 정보**에서 복사 아이콘을 선택하여 API의 호출 URL을 복사합니다. 이 URL은 `https://abcdef123.execute-api.us-west-2.amazonaws.com/test`와 같은 형식입니다. 1단계에서 생성한 VPC 엔드포인트에는 프라이빗 DNS가 활성화되어 있으므로 제공된 URL을 사용하여 API를 호출할 수 있습니다.

1. curl을 사용하여 VPC 외부에서 API를 호출합니다.

   ```
   curl https://abcdef123.execute-api.us-west-2.amazonaws.com/test
   ```

   Curl은 API의 엔드포인트를 확인할 수 없음을 나타냅니다. 다른 응답을 받은 경우 2단계로 돌아가서 API의 엔드포인트 유형에 대해 **프라이빗**(Private)으로 선택해야 합니다.

   ```
   curl: (6) Could not resolve host: abcdef123.execute-api.us-west-2.amazonaws.com/test
   ```

그런 다음 VPC의 Amazon EC2 인스턴스에 연결하여 API를 호출합니다.

## 7단계: VPC의 인스턴스에 연결하고 API 호출
<a name="private-api-tutorial-connect-to-instance"></a>

그런 다음 Amazon VPC 내에서 API를 테스트합니다. 프라이빗 API에 액세스하려면 VPC의 Amazon EC2 인스턴스에 연결한 다음 curl을 사용하여 API를 호출합니다. Systems Manager 세션 관리자를 사용하여 브라우저에서 인스턴스에 연결합니다.

**API 테스트하기**

1. [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/)에서 Amazon EC2 콘솔을 엽니다.

1. **인스턴스**를 선택합니다.

1. 1단계에서 CloudFormation 템플릿으로 생성한 **private-api-tutorial**이라는 인스턴스를 선택합니다.

1. **연결**(Connect)을 선택한 다음 **세션 관리자**(Session Manager)를 선택합니다.

1. **연결**(Connect)을 선택하여 인스턴스에 대한 브라우저 기반 세션을 시작합니다.

1. 세션 관리자 세션에서 curl을 사용하여 API를 호출합니다. Amazon VPC에서 인스턴스를 사용하고 있기 때문에 API를 호출할 수 있습니다.

   ```
   curl https://abcdef123.execute-api.us-west-2.amazonaws.com/test
   ```

   응답 `Hello from Lambda!`이 수신되는지 확인합니다.

![\[세션 관리자를 사용하여 Amazon VPC 내에서 API를 호출합니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/private-api-tutorial-invoke.png)


Amazon VPC 내에서만 액세스할 수 있는 API를 성공적으로 생성한 다음 작동하는지 확인했습니다.

## 8단계: 정리
<a name="private-api-tutorial-cleanup"></a>

불필요한 비용을 방지하려면 이 자습서의 일부로 생성한 리소스를 삭제합니다. 다음 단계에서는 REST API 및 CloudFormation 스택을 삭제합니다.

**REST API 삭제**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **API** 페이지에서 API를 선택합니다. **API 작업**을 선택하고 **API 삭제**를 선택한 다음 선택을 확인합니다.

**CloudFormation 스택을 삭제하려면**

1. CloudFormation 콘솔([https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/))을 엽니다.

1. CloudFormation 스택을 선택합니다.

1. **삭제**를 선택한 다음 해당 선택을 확인합니다.

## 다음 단계: 를 통한 자동화CloudFormation
<a name="private-api-tutorial-next-steps"></a>

이 자습서와 관련된 모든 AWS 리소스의 생성 및 정리를 자동화할 수 있습니다. 전체 예제 CloudFormation 템플릿에 대해서는 [template.yaml](samples/private-api-full-template.zip)을 참조하세요.

# Amazon API Gateway HTTP API 자습서
<a name="api-gateway-http-tutorials"></a>

다음 자습서에는 API Gateway HTTP API에 대해 알아보는 데 도움이 되는 실습용 과제가 나와 있습니다.

**Topics**
+ [자습서: Lambda 및 DynamoDB를 사용한 CRUD HTTP API 생성](http-api-dynamo-db.md)
+ [자습서: Amazon ECS 서비스에 대한 프라이빗 통합을 통해 HTTP API 생성](http-api-private-integration.md)

# 자습서: Lambda 및 DynamoDB를 사용한 CRUD HTTP API 생성
<a name="http-api-dynamo-db"></a>

이 자습서에서는 DynamoDB 테이블에서 항목을 생성, 읽기, 업데이트 및 삭제하는 서버리스 API를 생성합니다. DynamoDB는 완전관리형 NoSQL 데이터베이스 서비스로서 원활한 확장성과 함께 빠르고 예측 가능한 성능을 제공합니다. 이 자습서를 완료하는 데 약 30분이 소요되며 [AWS 프리 티어](https://aws.amazon.com/free/) 내에서 이를 수행할 수 있습니다.

먼저 [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) 콘솔을 사용하여 DynamoDB 테이블을 생성합니다. 그런 다음, AWS Lambda 콘솔을 사용하여 [Lambda](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) 함수를 생성합니다. 그런 다음 API Gateway 콘솔을 사용하여 HTTP API를 생성합니다. 마지막으로 API를 테스트합니다.

HTTP API를 호출하면 API Gateway는 요청을 Lambda 함수로 라우팅합니다. Lambda 함수는 DynamoDB와 상호 작용하고 API Gateway에 대한 응답을 반환합니다. 그러고 나면 API Gateway가 응답을 반환합니다.

![\[이 튜토리얼에서 생성하는 HTTP API의 개요입니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/ddb-crud.png)


이 연습을 완료하려면 AWS 계정과 콘솔 액세스 권한이 있는 AWS Identity and Access Management 사용자가 있어야 합니다. 자세한 내용은 [API Gateway를 사용하도록 설정](setting-up.md) 단원을 참조하세요.

이 자습서에서는 를 사용합니다AWS Management Console 이 API 및 모든 관련 리소스를 생성하는 AWS SAM 템플릿은 [samples/http-dynamo-tutorial.zip](samples/http-dynamo-tutorial.zip) 단원을 참조하세요.

**Topics**
+ [1단계: DynamoDB 테이블 생성](#http-api-dynamo-db-create-table)
+ [2단계: Lambda 함수 생성](#http-api-dynamo-db-create-function)
+ [3단계: HTTP API 생성](#http-api-dynamo-db-create-api)
+ [4단계: 경로 생성](#http-api-dynamo-db-create-routes)
+ [5단계: 통합 생성](#http-api-dynamo-db-create-integration)
+ [6단계: 경로에 통합 연결](#http-api-dynamo-db-attach-integrations)
+ [7단계: API 테스트](#http-api-dynamo-db-invoke-api)
+ [8단계: 정리](#http-api-dynamo-db-cleanup)
+ [다음 단계: AWS SAM 또는 CloudFormation을 통한 자동화](#http-api-dynamo-db-next-steps)

## 1단계: DynamoDB 테이블 생성
<a name="http-api-dynamo-db-create-table"></a>

[DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) 테이블을 사용하여 API에 대한 데이터를 저장합니다.

각 항목에는 테이블의 [파티션 키](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.PrimaryKey)로 사용하는 고유 ID가 있습니다.

**DynamoDB 테이블을 생성하려면**

1. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)에서 DynamoDB 콘솔을 엽니다.

1. [**Create table**]을 선택합니다.

1. **테이블 이름**에 **http-crud-tutorial-items**을(를) 입력합니다.

1. **파티션 키(Partition key)**에 **id**를 입력합니다.

1. **테이블 생성**을 선택합니다.

## 2단계: Lambda 함수 생성
<a name="http-api-dynamo-db-create-function"></a>

API의 백엔드에 [Lambda](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) 함수를 생성합니다. 이 Lambda 함수는 DynamoDB에서 항목을 생성, 읽기, 업데이트 및 삭제합니다. 이 함수는 [API Gateway의 이벤트](http-api-develop-integrations-lambda.md#http-api-develop-integrations-lambda.proxy-format)를 사용하여 DynamoDB와 상호 작용하는 방법을 결정합니다. 단순화를 위해 이 자습서에서는 단일 Lambda 함수를 사용합니다. 가장 좋은 방법은 각 경로에 대해 별도의 함수를 생성하는 것입니다. 자세한 내용은 [Lambda 모놀리스](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/monolith)를 참조하세요.

**Lambda 함수 생성**

1. [https://console.aws.amazon.com/lambda](https://console.aws.amazon.com/lambda)에서 Lambda 콘솔에 로그인합니다.

1. **함수 생성**을 선택합니다.

1. [**함수 이름(Function name)**]에 **http-crud-tutorial-function**을 입력합니다.

1. **런타임**에서 지원되는 최신 **Node.js** 또는 **Python** 런타임을 선택합니다.

1. **사용 권한**에서 [**기본 실행 역할 변경(Change default execution role)**]을 선택합니다.

1. **AWS 정책 템플릿에서 새 역할 생성**을 선택합니다.

1. [**역할 이름(Role name)**]에 **http-crud-tutorial-role**을 입력합니다.

1. **정책 템플릿**에서 **Simple microservice permissions**을(를) 선택합니다. 이 정책은 Lambda 함수에 DynamoDB와 상호 작용할 수 있는 권한을 부여합니다.
**참고**  
이 자습서에서는 단순화를 위해 관리형 정책을 사용합니다. 가장 좋은 방법은 필요한 최소 권한을 부여하는 자체 IAM 정책을 생성하는 것입니다.

1. **함수 생성**을 선택합니다.

1. 콘솔의 코드 편집기에서 Lambda 함수를 열고 내용을 다음 코드로 바꿉니다. [**배포(Deploy)**]를 선택하여 함수를 업데이트합니다.

------
#### [ Node.js ]

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
  DynamoDBDocumentClient,
  ScanCommand,
  PutCommand,
  GetCommand,
  DeleteCommand,
} from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({});

const dynamo = DynamoDBDocumentClient.from(client);

const tableName = "http-crud-tutorial-items";

export const handler = async (event, context) => {
  let body;
  let statusCode = 200;
  const headers = {
    "Content-Type": "application/json",
  };

  try {
    switch (event.routeKey) {
      case "DELETE /items/{id}":
        await dynamo.send(
          new DeleteCommand({
            TableName: tableName,
            Key: {
              id: event.pathParameters.id,
            },
          })
        );
        body = `Deleted item ${event.pathParameters.id}`;
        break;
      case "GET /items/{id}":
        body = await dynamo.send(
          new GetCommand({
            TableName: tableName,
            Key: {
              id: event.pathParameters.id,
            },
          })
        );
        body = body.Item;
        break;
      case "GET /items":
        body = await dynamo.send(
          new ScanCommand({ TableName: tableName })
        );
        body = body.Items;
        break;
      case "PUT /items":
        let requestJSON = JSON.parse(event.body);
        await dynamo.send(
          new PutCommand({
            TableName: tableName,
            Item: {
              id: requestJSON.id,
              price: requestJSON.price,
              name: requestJSON.name,
            },
          })
        );
        body = `Put item ${requestJSON.id}`;
        break;
      default:
        throw new Error(`Unsupported route: "${event.routeKey}"`);
    }
  } catch (err) {
    statusCode = 400;
    body = err.message;
  } finally {
    body = JSON.stringify(body);
  }

  return {
    statusCode,
    body,
    headers,
  };
};
```

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

```
import json
import boto3
from decimal import Decimal

client = boto3.client('dynamodb')
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table('http-crud-tutorial-items')
tableName = 'http-crud-tutorial-items'


def lambda_handler(event, context):
    print(event)
    body = {}
    statusCode = 200
    headers = {
        "Content-Type": "application/json"
    }

    try:
        if event['routeKey'] == "DELETE /items/{id}":
            table.delete_item(
                Key={'id': event['pathParameters']['id']})
            body = 'Deleted item ' + event['pathParameters']['id']
        elif event['routeKey'] == "GET /items/{id}":
            body = table.get_item(
                Key={'id': event['pathParameters']['id']})
            body = body["Item"]
            responseBody = [
                {'price': float(body['price']), 'id': body['id'], 'name': body['name']}]
            body = responseBody
        elif event['routeKey'] == "GET /items":
            body = table.scan()
            body = body["Items"]
            print("ITEMS----")
            print(body)
            responseBody = []
            for items in body:
                responseItems = [
                    {'price': float(items['price']), 'id': items['id'], 'name': items['name']}]
                responseBody.append(responseItems)
            body = responseBody
        elif event['routeKey'] == "PUT /items":
            requestJSON = json.loads(event['body'])
            table.put_item(
                Item={
                    'id': requestJSON['id'],
                    'price': Decimal(str(requestJSON['price'])),
                    'name': requestJSON['name']
                })
            body = 'Put item ' + requestJSON['id']
    except KeyError:
        statusCode = 400
        body = 'Unsupported route: ' + event['routeKey']
    body = json.dumps(body)
    res = {
        "statusCode": statusCode,
        "headers": {
            "Content-Type": "application/json"
        },
        "body": body
    }
    return res
```

------

## 3단계: HTTP API 생성
<a name="http-api-dynamo-db-create-api"></a>

HTTP API는 Lambda 함수에 대한 HTTP 엔드포인트를 제공합니다. 이 단계에서는 빈 API를 생성합니다. 다음 단계에서는 API와 Lambda 함수를 연결하기 위한 경로 및 통합을 구성합니다.



**HTTP API 생성하기**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. [**API 생성(Create API)**]을 선택한 다음 **HTTP API**에 대해 [**빌드(Build)**]를 선택합니다.

1. **API 이름**에서 **http-crud-tutorial-api**을(를) 입력합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **다음**을 선택합니다.

1. **경로 구성**에 대해 [**다음(Next)**]을 선택하여 경로 생성을 건너뜁니다. 나중에 루트를 생성합니다.

1. API Gateway가 생성하는 단계를 검토한 후 [**다음(Next)**]을 선택합니다.

1. **Create**를 선택합니다.

## 4단계: 경로 생성
<a name="http-api-dynamo-db-create-routes"></a>

경로는 수신 API 요청을 백엔드 리소스로 보내는 방법입니다. 경로는 HTTP 메서드와 리소스 경로(예: `GET /items`), 이렇게 두 부분으로 구성됩니다. 이 예제 API의 경우 네 개의 경로를 생성합니다.
+ `GET /items/{id}`
+ `GET /items`
+ `PUT /items`
+ `DELETE /items/{id}`

**경로 생성**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. **Routes(라우팅)**를 선택합니다.

1. **Create**를 선택합니다.

1. **메서드**(Method)에서 **GET**을(를) 선택합니다.

1. 경로에 **/items/\$1id\$1**을(를) 입력합니다. 경로 끝의 `{id}`은(는) 클라이언트가 요청을 할 때 API Gateway가 요청 경로에서 검색하는 경로 파라미터입니다.

1. **Create**를 선택합니다.

1. `GET /items`, `DELETE /items/{id}` 및 `PUT /items`에 대해 4-7단계를 반복합니다.

![\[API에 GET /items, GET /items/{id}, DELETE /items/{id} 및 PUT /items에 대한 경로가 있습니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/ddb-create-routes.png)


## 5단계: 통합 생성
<a name="http-api-dynamo-db-create-integration"></a>

백엔드 리소스에 경로를 연결하는 통합을 생성합니다. 이 예제 API에 대해 모든 경로에 사용할 Lambda 통합을 하나 생성합니다.

**통합 생성하기**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. [**통합(Integrations)**]을 선택합니다.

1. [**통합 관리(Manage integrations)**]를 선택한 다음 [**생성(Create)**]을 선택합니다.

1. [**경로에 이 통합 연결(Attach this integration to a route)**]을 건너뜁니다. 이후 단계에서 이 작업을 완료합니다.

1. **통합 유형**에서 **Lambda 함수(Lambda Function)**를 선택합니다.

1. **Lambda 함수**에서 **http-crud-tutorial-function**을(를) 입력합니다.

1. **Create**를 선택합니다.

## 6단계: 경로에 통합 연결
<a name="http-api-dynamo-db-attach-integrations"></a>

이 예제 API의 경우 모든 경로에 대해 Lambda 통합을 사용합니다. 모든 API의 경로에 통합을 연결한 후 클라이언트가 경로를 호출하면 Lambda 함수가 호출됩니다.



**경로에 통합 연결하기**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. [**통합(Integrations)**]을 선택합니다.

1. 경로를 선택합니다.

1. **기존 통합 선택**에서 **http-crud-tutorial-function**을(를) 선택합니다.

1. [**통합 연결(Attach integration)**]을 선택합니다.

1. 모든 경로에 대해 4-6단계를 반복합니다.

모든 경로가 AWS Lambda 통합이 연결되어 있음을 보여줍니다.

![\[콘솔이 모든 경로에서 AWS Lambda를 표시하여 통합이 연결되었음을 나타냅니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/ddb-attach-integrations.png)


이제 HTTP API에 경로 및 통합이 연결되었으므로 API를 테스트할 수 있습니다.

## 7단계: API 테스트
<a name="http-api-dynamo-db-invoke-api"></a>

API가 작동하는지 확인하려면 [curl](https://curl.se)을 사용합니다.

**API를 호출할 URL 가져오기**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. API의 호출 URL을 기록해 둡니다. **세부 정보** 페이지의 [**호출 URL(Invoke URL)**] 아래에 나타납니다.  
![\[API를 생성하면 콘솔에 API의 호출 URL이 표시됩니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/ddb-invoke-url.png)

1. API의 호출 URL을 복사합니다.

   전체 URL은 `https://abcdef123.execute-api.us-west-2.amazonaws.com`처럼 보입니다.

**항목 생성 또는 업데이트하기**
+ 다음 명령을 사용하여 항목을 생성하거나 업데이트합니다. 명령에는 항목의 ID, 가격 및 이름이 포함된 요청 본문이 포함됩니다.

  ```
  curl -X "PUT" -H "Content-Type: application/json" -d "{\"id\": \"123\", \"price\": 12345, \"name\": \"myitem\"}" https://abcdef123.execute-api.us-west-2.amazonaws.com/items
  ```

**모든 항목 가져오기**
+ 다음 명령을 사용하여 모든 항목을 나열합니다.

  ```
  curl https://abcdef123.execute-api.us-west-2.amazonaws.com/items
  ```

**항목 가져오기**
+ 다음 명령을 사용하여 ID별로 항목을 가져옵니다.

  ```
  curl https://abcdef123.execute-api.us-west-2.amazonaws.com/items/123
  ```

**항목 삭제 방법**

1. 다음 명령을 사용하여 항목을 삭제합니다.

   ```
   curl -X "DELETE" https://abcdef123.execute-api.us-west-2.amazonaws.com/items/123
   ```

1. 항목이 삭제되었는지 확인하려면 모든 항목을 가져옵니다.

   ```
   curl https://abcdef123.execute-api.us-west-2.amazonaws.com/items
   ```

## 8단계: 정리
<a name="http-api-dynamo-db-cleanup"></a>

불필요한 비용을 방지하려면 이 시작하기 연습의 일부로 생성한 리소스를 삭제하세요. 다음 단계에서는 HTTP API, Lambda 함수 및 관련 리소스를 삭제합니다.

**DynamoDB 테이블 삭제**

1. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)에서 DynamoDB 콘솔을 엽니다.

1. 테이블을 선택합니다.

1. [**Delete Table**]을 선택합니다.

1. 선택을 확인하고 [**삭제(Delete)**]를 선택합니다.

**HTTP API 삭제하기**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **API** 페이지에서 API를 선택합니다. [** Actions**]를 선택한 후 [**Delete**]를 선택합니다.

1. **삭제**를 선택합니다.

**Lambda 함수 삭제하기**

1. [https://console.aws.amazon.com/lambda](https://console.aws.amazon.com/lambda)에서 Lambda 콘솔에 로그인합니다.

1. **함수** 페이지에서 함수를 선택합니다. [** Actions**]를 선택한 후 [**Delete**]를 선택합니다.

1. **삭제**를 선택합니다.

**Lambda 함수의 로그 그룹 삭제하기**

1. Amazon CloudWatch 콘솔에서 [로그 그룹 페이지](https://console.aws.amazon.com/cloudwatch/home#logs:)를 엽니다.

1. **로그 그룹** 페이지에서 함수의 로그 그룹(`/aws/lambda/http-crud-tutorial-function`)을 선택합니다. **작업**을 선택한 다음 **로그 그룹 삭제**를 선택합니다.

1. **삭제**를 선택합니다.

**Lambda 함수의 실행 역할 삭제하기**

1. AWS Identity and Access Management 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home?#/roles)를 엽니다.

1. 함수의 역할(예: `http-crud-tutorial-role`)을 선택합니다.

1. **역할 삭제**를 선택합니다.

1. **예, 삭제**를 선택합니다.

## 다음 단계: AWS SAM 또는 CloudFormation을 통한 자동화
<a name="http-api-dynamo-db-next-steps"></a>

CloudFormation 또는 AWS SAM을 사용하여 AWS 리소스의 생성 및 정리를 자동화할 수 있습니다. 이 자습서의 AWS SAM 템플릿 예는 [samples/http-dynamo-tutorial.zip](samples/http-dynamo-tutorial.zip) 단원을 참조하세요.

예제 CloudFormation 템플릿에 대해서는 [예제 CloudFormation 템플릿](https://github.com/awsdocs/amazon-api-gateway-developer-guide/tree/main/cloudformation-templates)을 참조하세요.

# 자습서: Amazon ECS 서비스에 대한 프라이빗 통합을 통해 HTTP API 생성
<a name="http-api-private-integration"></a>

이 자습서에서는 Amazon VPC에서 실행되는 Amazon ECS 서비스에 연결하는 서버리스 API를 생성합니다. Amazon VPC 외부의 클라이언트는 API를 사용하여 Amazon ECS 서비스에 액세스할 수 있습니다.

이 자습서는 완료하는데 약 1시간이 걸립니다. 먼저 CloudFormation 템플릿을 사용하여 Amazon VPC 및 Amazon ECS 서비스를 생성합니다. 그런 다음 API Gateway 콘솔을 사용하여 VPC 링크를 생성합니다. VPC 링크를 통해 API Gateway는 Amazon VPC에서 실행되는 Amazon ECS 서비스에 액세스할 수 있습니다. 그런 다음 VPC 링크를 사용하여 Amazon ECS 서비스에 연결하는 HTTP API를 생성합니다. 마지막으로 API를 테스트합니다.

HTTP API를 호출하면 API Gateway는 VPC 링크를 통해 요청을 Amazon ECS 서비스로 라우팅한 다음 서비스에서 응답을 반환합니다.

![\[이 튜토리얼에서 생성하는 HTTP API의 개요입니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/private-integration.png)


이 자습서를 완료하려면 AWS 계정과 콘솔 액세스 권한이 있는 AWS Identity and Access Management 사용자가 있어야 합니다. 자세한 내용은 [API Gateway를 사용하도록 설정](setting-up.md) 단원을 참조하세요.

이 자습서에서는 를 사용합니다AWS Management Console 이 API 및 모든 관련 리소스를 생성하는 CloudFormation 템플릿은 [template.yaml](samples/private-integration-full-template.zip)을 참조하세요.

**Topics**
+ [1단계: Amazon ECS 서비스 생성](#http-api-private-integration-create-ecs-service)
+ [2단계: VPC 링크 생성](#http-api-private-integration-vpc-link)
+ [3단계: HTTP API 생성](#http-api-private-integration-create-api)
+ [4단계: 경로 생성](#http-api-private-integration-create-routes)
+ [5단계: 통합 생성](#http-api-private-integration-create-integration)
+ [6단계: API 테스트](#http-api-private-integration-invoke-api)
+ [7단계: 정리](#http-api-private-integration-cleanup)
+ [다음 단계: 를 통한 자동화CloudFormation](#http-api-private-integration-next-steps)

## 1단계: Amazon ECS 서비스 생성
<a name="http-api-private-integration-create-ecs-service"></a>

Amazon ECS는 클러스터에서 Docker 컨테이너를 손쉽게 실행, 중지 및 관리할 수 있게 해 주는 컨테이너 관리 서비스입니다. 이 자습서에서는 Amazon ECS에서 관리하는 서버리스 인프라에서 클러스터를 실행합니다.

Amazon VPC를 포함하여 서비스에 대한 모든 종속성을 생성하는 [이 CloudFormation 템플릿](samples/private-integration-cfn.zip)을 다운로드하고 압축을 풉니다. 이 템플릿을 사용하여 Application Load Balancer를 사용하는 Amazon ECS 서비스를 생성합니다.

**CloudFormation 스택을 생성하려면**

1. CloudFormation 콘솔([https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/))을 엽니다.

1. **스택 생성**을 선택한 다음 **새 리소스 사용(표준)**을 선택합니다.

1. **템플릿 지정**에서 **템플릿 파일 업로드**를 선택합니다.

1. 다운로드한 템플릿을 선택합니다.

1. **다음**을 선택합니다.

1. **스택 이름**에 **http-api-private-integrations-tutorial**을 입력하고 **다음**을 선택합니다.

1. **스택 옵션 구성**에서 **다음**을 선택합니다.

1. **기능**의 경우 CloudFormation이 계정에 IAM 리소스를 생성할 수 있음을 확인합니다.

1. **다음**을 선택한 후 **제출**을 선택합니다.

CloudFormation는 ECS 서비스를 프로비저닝하며 이 작업은 몇 분 정도 걸릴 수 있습니다. CloudFormation 스택 상태가 **CREATE\$1COMPLETE**인 경우 다음 단계로 넘어갈 준비가 된 것입니다.

## 2단계: VPC 링크 생성
<a name="http-api-private-integration-vpc-link"></a>

VPC 링크를 사용하면 API Gateway가 Amazon VPC의 프라이빗 리소스에 액세스할 수 있습니다. VPC 링크를 사용하면 클라이언트가 HTTP API를 통해 Amazon ECS 서비스에 액세스할 수 있습니다.

**VPC 링크 생성**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. 주요 탐색 창에서 **VPC 링크**를 선택한 후 **생성**을 선택합니다.

   메뉴 아이콘을 선택하여 기본 탐색 창을 열어야 할 수도 있습니다.

1. **VPC 링크 버전 선택**(Choose a VPC link version)에서 **HTTP API용 VPC 링크**(VPC link for HTTP APIs)를 선택합니다.

1. **이름**에 **private-integrations-tutorial**를 입력합니다.

1. **VPC**에서 1단계에서 생성한 VPC를 선택합니다. 이름은 **PrivateIntegrationsStack**으로 시작해야 합니다.

1. **서브넷**(Subnets)의 경우 VPC에 있는 두 개의 프라이빗 서브넷을 선택합니다. 이름은 `PrivateSubnet`(으)롤 끝납니다.

1. **보안 그룹**의 경우 `private-integrations-tutorial`로 시작하고 `PrivateIntegrationsStack/PrivateIntegrationsTutorialService/Service/SecurityGroup`의 설명이 있는 그룹 ID를 선택합니다.

1. **생성(Create)**을 선택합니다.

VPC 링크를 생성한 후 API Gateway는 탄력적 네트워크 인터페이스를 프로비저닝하여 VPC에 액세스합니다. 이 프로세스는 몇 분 정도 걸릴 수 있습니다. 그동안 API를 생성할 수 있습니다.

## 3단계: HTTP API 생성
<a name="http-api-private-integration-create-api"></a>

HTTP API는 Amazon ECS 서비스에 대한 HTTP 엔드포인트를 제공합니다. 이 단계에서는 빈 API를 생성합니다. 4단계와 5단계에서는 API와 Amazon ECS 서비스를 연결하기 위한 경로 및 통합을 구성합니다.



**HTTP API 생성하기**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. [**API 생성(Create API)**]을 선택한 다음 **HTTP API**에 대해 [**빌드(Build)**]를 선택합니다.

1. **API 이름**에서 **http-private-integrations-tutorial**을(를) 입력합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **다음**을 선택합니다.

1. **경로 구성**에 대해 [**다음(Next)**]을 선택하여 경로 생성을 건너뜁니다. 나중에 루트를 생성합니다.

1. API Gateway가 생성하는 스테이지를 검토합니다. API Gateway는 자동 배포가 활성화된 `$default` 스테이지를 생성합니다. 이 스테이지는 이 자습서에 가장 적합합니다. [**Next**]를 선택합니다.

1. **Create**를 선택합니다.

## 4단계: 경로 생성
<a name="http-api-private-integration-create-routes"></a>

경로는 수신 API 요청을 백엔드 리소스로 보내는 방법입니다. 경로는 HTTP 메서드와 리소스 경로(예: `GET /items`), 이렇게 두 부분으로 구성됩니다. 이 예제 API의 경우 1개의 경로를 생성합니다.

**경로 생성**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. **Routes(라우팅)**를 선택합니다.

1. **Create**를 선택합니다.

1. **메서드**(Method)에서 **ANY**을(를) 선택합니다.

1. 경로에 **/\$1proxy\$1\$1**을(를) 입력합니다. 경로 끝의 `{proxy+}`은(는) 복잡한 경로 변수입니다. API Gateway는 API에 대한 모든 요청을 이 경로로 보냅니다.

1. **Create**를 선택합니다.

## 5단계: 통합 생성
<a name="http-api-private-integration-create-integration"></a>

백엔드 리소스에 경로를 연결하는 통합을 생성합니다.

**통합 생성하기**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. [**통합(Integrations)**]을 선택합니다.

1. [**통합 관리(Manage integrations)**]를 선택한 다음 [**생성(Create)**]을 선택합니다.

1. **이 통합을 경로에 연결**(Attach this integration to a route)에서 이전에 생성한 **ANY /\$1proxy\$1\$1** 경로를 선택합니다.

1. **통합 유형**(Integration type)에서 **프라이빗 리소스**(Private resource)를 선택합니다.

1. **통합 세부 정보**(Integration details)에서 **수동 선택**(Select manually)을 선택합니다.

1. **대상 서비스**(Target service)에서 **ALB/NLB**를 선택합니다.

1. **로드 밸런서(Load balancer)**의 경우 1단계에서 CloudFormation 템플릿으로 생성한 로드 밸런서를 선택합니다. 이름은 **HTTP-Priva**로 시작해야 합니다.

1. **리스너**(Listener)에서 **HTTP 80**을(를) 선택합니다.

1. **VPC 링크**(VPC link)의 경우 2단계에서 생성한 VPC 링크를 선택합니다. 이름은 `private-integrations-tutorial`이어야 합니다.

1. **Create**를 선택합니다.

경로 및 통합이 올바르게 설정되었는지 확인하려면 **경로에 통합 연결**(Attach integrations to routes)을 선택합니다. 콘솔에 VPC Load Balancer에 대한 통합의 `ANY /{proxy+}` 경로가 있음이 표시됩니다.

![\[VPC에 Load Balancer에 대한 통합의 /{proxy+} 경로가 있음이 표시됩니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/private-integration-tutorial-route.png)


이제 API를 테스트 할 준비가 되었습니다.

## 6단계: API 테스트
<a name="http-api-private-integration-invoke-api"></a>

다음으로, API를 테스트하여 제대로 작동하는지 확인합니다. 간단하게 하기 위해, 웹 브라우저를 사용하여 API를 호출합니다.

**API 테스트하기**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. API의 호출 URL을 기록해 둡니다.  
![\[API를 생성하면 콘솔에 API의 호출 URL이 표시됩니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/getting-started-invoke-url.png)

1. 웹 브라우저에서 API의 호출 URL로 이동합니다.

   전체 URL은 `https://abcdef123.execute-api.us-east-2.amazonaws.com`와(과) 같아야 합니다.

   브라우저가 API에 `GET` 요청을 보냅니다.

1. API의 응답이 앱이 Amazon ECS에서 실행 중임을 알려주는 시작 메시지인지 확인합니다.

   시작 메시지가 표시되면 Amazon VPC에서 실행되는 Amazon ECS 서비스를 성공적으로 생성하고, VPC 링크와 함께 API Gateway HTTP API를 사용하여 Amazon ECS 서비스에 액세스한 것입니다.

## 7단계: 정리
<a name="http-api-private-integration-cleanup"></a>

불필요한 비용을 방지하려면 이 자습서의 일부로 생성한 리소스를 삭제합니다. 다음 단계에서는 VPC 링크, CloudFormation 스택 및 HTTP API를 삭제합니다.

**HTTP API 삭제하기**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **API** 페이지에서 API를 선택합니다. **작업**(Actions)을 선택하고 **삭제**(Delete)를 선택한 다음 선택을 확인합니다.

**VPC 링크 삭제**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **VPC 링크**(VPC link)를 선택합니다.

1. VPC 링크를 선택하고 **삭제**(Delete)를 선택한 다음, 해당 선택을 확인합니다.

**CloudFormation 스택을 삭제하려면**

1. CloudFormation 콘솔([https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/))을 엽니다.

1. CloudFormation 스택을 선택합니다.

1. **삭제**를 선택한 다음 해당 선택을 확인합니다.

## 다음 단계: 를 통한 자동화CloudFormation
<a name="http-api-private-integration-next-steps"></a>

이 자습서와 관련된 모든 AWS 리소스의 생성 및 정리를 자동화할 수 있습니다. 전체 예제 CloudFormation 템플릿에 대해서는 [template.yaml](samples/private-integration-full-template.zip)을 참조하세요.

# Amazon API Gateway WebSocket API 자습서
<a name="api-gateway-websocket-tutorials"></a>

다음 자습서에는 API Gateway WebSocket API에 대해 알아보는 데 도움이 되는 실습용 과제가 나와 있습니다.

**Topics**
+ [자습서: WebSocket API, Lambda 및 DynamoDB를 사용하여 WebSocket 채팅 앱 생성](websocket-api-chat-app.md)
+ [자습서: AWS 통합을 통해 WebSocket API 생성](websocket-api-step-functions-tutorial.md)

# 자습서: WebSocket API, Lambda 및 DynamoDB를 사용하여 WebSocket 채팅 앱 생성
<a name="websocket-api-chat-app"></a>

본 자습서에서는 WebSocket API를 사용하여 서버리스 채팅 애플리케이션을 생성합니다. WebSocket API를 사용하면 클라이언트 간의 양방향 통신을 지원할 수 있습니다. 클라이언트는 업데이트를 폴링하지 않고 메시지를 수신할 수 있습니다.

이 자습서는 완료되는데 약 30분이 걸립니다. 먼저, CloudFormation 템플릿을 사용하여 API 요청을 처리하는 Lambda 함수와 클라이언트 ID를 저장하는 DynamoDB 테이블을 생성합니다. 그런 다음 API Gateway 콘솔을 사용하여 Lambda 함수와 통합되는 WebSocket API를 생성합니다. 마지막으로 API를 테스트하여 메시지가 송신 및 수신되는지 확인합니다.

![\[이 자습서에서 생성하는 API의 아키텍처 개요입니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/ws-chat-app.png)


이 자습서를 완료하려면 AWS 계정과 콘솔 액세스 권한이 있는 AWS Identity and Access Management 사용자가 있어야 합니다. 자세한 내용은 [API Gateway를 사용하도록 설정](setting-up.md) 섹션을 참조하세요.

또한 API에 연결하기 위해 `wscat`가 필요합니다. 자세한 내용은 [`wscat`를 사용하여 WebSocket API에 연결하고 메시지 보내기](apigateway-how-to-call-websocket-api-wscat.md) 섹션을 참조하세요.

**Topics**
+ [1단계: Lambda 함수 및 DynamoDB 테이블 생성](#websocket-api-chat-app-create-dependencies)
+ [2단계: WebSocket API 생성](#websocket-api-chat-app-create-api)
+ [3단계: API 테스트](#websocket-api-chat-app-invoke-api)
+ [4단계: 정리](#websocket-api-chat-app-cleanup)
+ [다음 단계: 를 통한 자동화CloudFormation](#websocket-api-chat-app-next-steps)

## 1단계: Lambda 함수 및 DynamoDB 테이블 생성
<a name="websocket-api-chat-app-create-dependencies"></a>

[CloudFormation용 앱 생성 템플릿](samples/ws-chat-app-starter.zip)을 다운로드하고 압축을 해제합니다. 이 템플릿을 사용하여 앱의 클라이언트 ID를 저장할 Amazon DynamoDB 테이블을 생성합니다. 연결된 각 클라이언트에는 테이블의 파티션 키로 사용될 고유 ID가 있습니다. 또한 이 템플릿은 DynamoDB에서 클라이언트 연결을 업데이트하고 연결된 클라이언트로의 메시지 전송을 처리하는 Lambda 함수를 생성합니다.

**CloudFormation 스택을 생성하려면**

1. CloudFormation 콘솔([https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/))을 엽니다.

1. **스택 생성**을 선택한 다음 **새 리소스 사용(표준)**을 선택합니다.

1. **템플릿 지정**에서 **템플릿 파일 업로드**를 선택합니다.

1. 다운로드한 템플릿을 선택합니다.

1. **다음**을 선택합니다.

1. **스택 이름**에 **websocket-api-chat-app-tutorial**을 입력하고 **다음**을 선택합니다.

1. **스택 옵션 구성**에서 **다음**을 선택합니다.

1. **기능**의 경우 CloudFormation이 계정에 IAM 리소스를 생성할 수 있음을 확인합니다.

1. **다음**을 선택한 후 **제출**을 선택합니다.

CloudFormation은 템플릿에 지정된 리소스를 프로비저닝합니다. 리소스 프로비저닝을 완료하는 데 몇 분 정도 걸릴 수 있습니다. CloudFormation 스택 상태가 **CREATE\$1COMPLETE**인 경우 다음 단계로 넘어갈 준비가 된 것입니다.

## 2단계: WebSocket API 생성
<a name="websocket-api-chat-app-create-api"></a>

클라이언트 연결을 처리하고 1단계에서 생성한 Lambda 함수로 요청을 라우팅하는 WebSocket API를 생성합니다.



**WebSocket API를 생성하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **API 생성**을 선택합니다. **WebSocket API**에서 **빌드(Build)**를 선택합니다.

1. **API 이름**에서 **websocket-chat-app-tutorial**을 입력합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **경로 선택 표현식(Route selection expression)**에 **request.body.action**을 입력합니다. 경로 선택 표현식에 따라 클라이언트가 메시지를 보낼 때 API Gateway에서 호출할 경로가 결정됩니다.

1. **다음**을 선택합니다.

1. **사전 정의된 경로(Predefined routes)**에서 **\$1connect 추가(Add \$1connect)**, **\$1disconnect 추가(Add \$1disconnect)**, **\$1default 추가(Add \$1default)**를 선택합니다. **\$1connect** 및 **\$1disconnect** 경로는 클라이언트가 API에 연결하거나 API에서 연결을 끊을 때 API Gateway가 자동으로 호출하는 특수 경로입니다. API Gateway는 요청과 일치하는 다른 경로가 없을 때 `$default` 경로를 호출합니다.

1. **사용자 지정 경로(Custom routes)**에서 **사용자 지정 경로 추가(Add custom routes)**를 선택합니다. **경로 키(Route key)**에 **sendmessage**를 입력합니다. 이 사용자 지정 경로는 연결된 클라이언트로 전송되는 메시지를 처리합니다.

1. **다음**을 선택합니다.

1. 각 경로 및 **통합 유형(Integration type)**에 대한 **통합 연결(Attach integrations)**에서 Lambda를 선택합니다.

   **Lambda**에서, 1단계에서 CloudFormation을 사용하여 생성한 해당 Lambda 함수를 선택합니다. 각 함수의 이름은 경로와 일치합니다. 예를 들어 **\$1connect** 경로에서 이름이 **websocket-chat-app-tutorial-ConnectHandler**인 함수를 선택합니다.

1. API Gateway가 생성하는 스테이지를 검토합니다. 기본적으로 API Gateway는 스테이지 이름 `production`을 생성하여 API를 해당 스테이지에 자동으로 배포합니다. **다음**을 선택합니다.

1. **생성 및 배포(Create and deploy)**를 선택합니다.

## 3단계: API 테스트
<a name="websocket-api-chat-app-invoke-api"></a>

다음으로, API를 테스트하여 제대로 작동하는지 확인합니다. `wscat` 명령을 사용하여 API에 연결합니다.

**API의 호출 URL을 가져오려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. API를 선택합니다.

1. **스테이지(Stages)**를 선택한 다음 **프로덕션(production)**을 선택합니다.

1. API의 **WebSocket URL**을 기록해 둡니다. URL은 `wss://abcdef123.execute-api.us-east-2.amazonaws.com/production`와 같아야 합니다.

**API에 연결하려면**

1. API에 연결하려면 다음 명령을 사용합니다. API에 연결하면 API Gateway에서 `$connect` 경로를 호출합니다. 이 경로가 호출되면 API Gateway가 DynamoDB에 연결 ID를 저장하는 Lambda 함수를 호출합니다.

   ```
   wscat -c wss://abcdef123.execute-api.us-west-2.amazonaws.com/production
   ```

   ```
   Connected (press CTRL+C to quit)
   ```

1. 새 터미널을 열고 다음 파라미터를 사용하여 **wscat** 명령을 다시 실행합니다.

   ```
   wscat -c wss://abcdef123.execute-api.us-west-2.amazonaws.com/production
   ```

   ```
   Connected (press CTRL+C to quit)
   ```

   이렇게 하면 메시지를 교환할 수 있는 연결된 두 클라이언트가 제공됩니다.

**메시지를 전송하려면**
+  API Gateway는 API의 경로 선택 표현식을 기반으로 호출할 경로를 결정합니다. API의 경로 선택 표현식은 `$request.body.action`입니다. 따라서 API Gateway는 다음 메시지가 전송될 때 `sendmessage` 경로를 호출합니다.

  ```
  {"action": "sendmessage", "message": "hello, everyone!"}
  ```

  호출된 경로와 연결된 Lambda 함수는 DynamoDB에서 클라이언트 ID를 수집합니다. 그런 다음 이 함수는 API Gateway Management API를 호출하고 해당 클라이언트에 메시지를 보냅니다. 연결된 모든 클라이언트는 다음과 같은 메시지를 받습니다.

  ```
  < hello, everyone!
  ```

**API의 \$1default 경로를 호출하려면**
+ API Gateway는 클라이언트가 정의된 경로와 일치하지 않는 메시지를 전송하는 경우 API의 기본 경로를 호출합니다. `$default` 경로와 연결된 Lambda 함수는 API Gateway Management API를 사용하여 연결에 대한 클라이언트 정보를 보냅니다.

  ```
  test
  ```

  ```
  Use the sendmessage route to send a message. Your info: {"ConnectedAt":"2022-01-25T18:50:04.673Z","Identity":{"SourceIp":"192.0.2.1","UserAgent":null},"LastActiveAt":"2022-01-25T18:50:07.642Z","connectionID":"Mg_ugfpqPHcCIVA="}
  ```

**API 연결을 해제하려면**
+ API 연결을 해제하려면 **CTRL\$1C**를 누릅니다. 클라이언트가 API에서 연결을 해제하면 API Gateway에서 API의 `$disconnect` 경로를 호출합니다. API의 `$disconnect` 경로에 대한 Lambda 통합이 DynamoDB에서 연결 ID를 제거합니다.

## 4단계: 정리
<a name="websocket-api-chat-app-cleanup"></a>

불필요한 비용을 방지하려면 이 자습서의 일부로 생성한 리소스를 삭제합니다. 다음 단계에서는 CloudFormation 스택 및 WebSocket API를 삭제합니다.

**WebSocket API를 삭제하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **API(APIs)** 페이지에서 `websocket-chat-app-tutorial` API를 선택합니다. **작업**(Actions)을 선택하고 **삭제**(Delete)를 선택한 다음 선택을 확인합니다.

**CloudFormation 스택을 삭제하려면**

1. CloudFormation 콘솔([https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/))을 엽니다.

1. CloudFormation 스택을 선택합니다.

1. **삭제**를 선택한 다음 해당 선택을 확인합니다.

## 다음 단계: 를 통한 자동화CloudFormation
<a name="websocket-api-chat-app-next-steps"></a>

이 자습서와 관련된 모든 AWS 리소스의 생성 및 정리를 자동화할 수 있습니다. 이 API 및 모든 관련 리소스를 생성하는 CloudFormation 템플릿은 [ws-chat-app.yaml](samples/ws-chat-app.zip)을 참조하세요.

# 자습서: AWS 통합을 통해 WebSocket API 생성
<a name="websocket-api-step-functions-tutorial"></a>

본 자습서에서는 WebSocket API를 사용하여 서버리스 브로드캐스트 애플리케이션을 생성합니다. 클라이언트는 업데이트를 폴링하지 않고 메시지를 수신할 수 있습니다.

 이 자습서는 연결된 클라이언트에 메시지를 브로드캐스트하는 방법을 보여 주며, Lambda 권한 부여자, 모의 통합, Step Functions에 대한 비프록시 통합의 예를 포함합니다.

![\[이 자습서에서 생성하는 API의 아키텍처 개요입니다.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/ws-sfn-app.png)


CloudFormation 템플릿을 사용하여 리소스를 생성한 후에는 API Gateway 콘솔을 사용하여 AWS 리소스와 통합되는 WebSocket API를 생성합니다. Lambda 권한 부여자를 API에 연결하고 Step Functions와 AWS 서비스 통합을 생성하여 상태 머신 실행을 시작합니다. Step Functions 상태 머신은 연결된 모든 클라이언트에 메시지를 보내는 Lambda 함수를 간접 호출합니다.

API를 빌드한 후에는 API에 대한 연결을 테스트하고 메시지가 송신 및 수신되는지 확인합니다. 이 자습서는 완료되는데 약 45분이 걸립니다.

**Topics**
+ [사전 조건](#websocket-api-step-functions-prerequisites)
+ [1단계: 리소스 생성](#websocket-api-step-functions-create-dependencies)
+ [2단계: WebSocket API 생성](#websocket-api-step-functions-create-api)
+ [3단계: Lambda 권한 부여자 생성 단계](#websocket-api-step-functions-create-authorizer)
+ [4단계: 모의 양방향 통합 생성](#websocket-api-step-functions-create-mock-integration)
+ [5단계: Step Functions와의 비프록시 통합 생성](#websocket-api-step-functions-create-step-function-integration)
+ [6단계: API 테스트](#websocket-api-step-functions-test-api)
+ [7단계: 정리](#websocket-api-step-functions-cleanup)
+ [다음 단계](#websocket-api-step-functions-next-steps)

## 사전 조건
<a name="websocket-api-step-functions-prerequisites"></a>

필요한 사전 조건은 다음과 같습니다.
+ 콘솔 액세스 권한이 있는 AWS 계정 및 AWS Identity and Access Management 사용자 자세한 내용은 [API Gateway를 사용하도록 설정](setting-up.md) 단원을 참조하세요.
+ API에 연결하는 `wscat` 자세한 내용은 [`wscat`를 사용하여 WebSocket API에 연결하고 메시지 보내기](apigateway-how-to-call-websocket-api-wscat.md) 섹션을 참조하세요.

이 자습서를 시작하기 전에 WebSocket 채팅 앱 자습서를 완료하는 것이 좋습니다. WebSocket 채팅 앱 자습서를 완료하려면 [자습서: WebSocket API, Lambda 및 DynamoDB를 사용하여 WebSocket 채팅 앱 생성](websocket-api-chat-app.md)을 참조하세요.

## 1단계: 리소스 생성
<a name="websocket-api-step-functions-create-dependencies"></a>

[CloudFormation용 앱 생성 템플릿](samples/ws-sfn-starter.zip)을 다운로드하고 압축을 해제합니다. 이 템플릿을 사용하여 다음을 만들 수 있습니다.
+ API 요청을 처리하고 API에 대한 액세스를 승인하는 Lambda 함수.
+ Lambda 권한 부여자가 반환한 클라이언트 ID 및 주 사용자 ID를 저장하는 DynamoDB 테이블입니다.
+ 연결된 클라이언트로 메시지를 보내는 Step Functions 상태 머신입니다.

**CloudFormation 스택을 생성하려면**

1. CloudFormation 콘솔([https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/))을 엽니다.

1. **스택 생성**을 선택한 다음 **새 리소스 사용(표준)**을 선택합니다.

1. **템플릿 지정**에서 **템플릿 파일 업로드**를 선택합니다.

1. 다운로드한 템플릿을 선택합니다.

1. **다음**을 선택합니다.

1. **스택 이름**에 **websocket-step-functions-tutorial**을 입력하고 **다음**을 선택합니다.

1. **스택 옵션 구성**에서 **다음**을 선택합니다.

1. **기능**의 경우 CloudFormation이 계정에 IAM 리소스를 생성할 수 있음을 확인합니다.

1. **다음**을 선택한 후 **제출**을 선택합니다.

CloudFormation은 템플릿에 지정된 리소스를 프로비저닝합니다. 리소스 프로비저닝을 완료하는 데 몇 분 정도 걸릴 수 있습니다. **출력** 탭을 선택하면 생성된 리소스와 해당 ARN을 확인할 수 있습니다. CloudFormation 스택 상태가 **CREATE\$1COMPLETE**인 경우 다음 단계로 넘어갈 준비가 된 것입니다.

## 2단계: WebSocket API 생성
<a name="websocket-api-step-functions-create-api"></a>

클라이언트 연결을 처리하고 1단계에서 생성한 리소스로 요청을 라우팅하는 WebSocket API를 생성합니다.

**WebSocket API를 생성하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **API 생성**을 선택합니다. **WebSocket API**에서 **빌드(Build)**를 선택합니다.

1. **API 이름**에서 **websocket-step-functions-tutorial**을 입력합니다.

1. **IP 주소 유형**에서 **IPv4**를 선택합니다.

1. **경로 선택 표현식(Route selection expression)**에 **request.body.action**을 입력합니다.

   경로 선택 표현식에 따라 클라이언트가 메시지를 보낼 때 API Gateway에서 호출할 경로가 결정됩니다.

1. **다음**을 선택합니다.

1. **미리 정의된 경로**의 경우 **\$1connect 추가**, **\$1disconnect 추가**, **\$1default 추가**를 선택합니다.

   **\$1connect** 및 **\$1disconnect** 경로는 클라이언트가 API에 연결하거나 API에서 연결을 끊을 때 API Gateway가 자동으로 호출하는 특수 경로입니다. API Gateway는 요청과 일치하는 다른 경로가 없는 경우 **\$1default** 경로를 간접 호출합니다. API를 생성한 후 Step Functions에 연결할 사용자 지정 경로를 생성합니다.

1. **다음**을 선택합니다.

1. **\$1connect를 위한 통합**의 경우 다음을 수행합니다.

   1. **통합 유형**‬에서 **‬Lambda**를 선택합니다.

   1. **Lambda 함수**에서, 1단계에서 CloudFormation으로 생성한 해당 **\$1connect** Lambda 함수를 선택합니다. Lambda 함수 이름은 **websocket-step**으로 시작해야 합니다.

1. **\$1disconnect를 위한 통합**의 경우 다음을 수행합니다.

   1. **통합 유형**‬에서 **‬Lambda**를 선택합니다.

   1. **Lambda**에서, 1단계에서 CloudFormation으로 생성한 해당 **\$1disconnect** Lambda 함수를 선택합니다. Lambda 함수 이름은 **websocket-step**으로 시작해야 합니다.

1. **\$1default를 위한 통합**의 경우 **모의**을 선택합니다.

   모의 통합에서는 API Gateway가 통합 백엔드가 없어도 경로 응답을 관리합니다.

1. **다음**을 선택합니다.

1. API Gateway가 생성하는 스테이지를 검토합니다. 기본적으로 API Gateway는 스테이지 **프로덕션**이라는 스테이지를 생성하여 API를 해당 스테이지에 자동으로 배포합니다. **다음**을 선택합니다.

1. **생성 및 배포**를 선택합니다.

## 3단계: Lambda 권한 부여자 생성 단계
<a name="websocket-api-step-functions-create-authorizer"></a>

WebSocket API에 대한 액세스를 제어하려면 Lambda 권한 부여자를 생성합니다. CloudFormation 템플릿은 Lambda 권한 부여 함수를 생성했습니다. Lambda 콘솔에서 Lambda 함수를 볼 수도 있습니다. **websocket-step-functions-tutorial-AuthorizerHandler**로 시작하는 이름은 사용해야 합니다. 이 Lambda 함수는 `Authorization` 헤더가 `Allow`가 아닌 한 WebSocket API에 대한 모든 직접 호출을 거부합니다. 또한 Lambda 함수는 `$context.authorizer.principalId` 변수를 API로 전달하며, 이 변수는 나중에 DynamoDB 테이블에서 API 호출자를 식별하는 데 사용됩니다.

이 단계에서는 Lambda 권한 부여자를 사용하도록 **\$1connect** 경로를 구성합니다.

**Lambda 권한 부여자를 생성하려는 경우**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. 기본 탐색 창에서 **권한 부여자**를 선택합니다.

1. **권한 부여자 생성**을 선택합니다.

1. **권한 부여자 이름**에 **LambdaAuthorizer**를 입력합니다.

1. **권한 부여자 ARN**의 경우 CloudFormation 템플릿에서 생성한 권한 부여자의 이름을 입력합니다. **websocket-step-functions-tutorial-AuthorizerHandler**로 시작하는 이름은 사용할 수 없습니다.
**참고**  
프로덕션 API에는 이 예제 권한 부여자를 사용하지 않는 것이 좋습니다.

1. **ID 소스 유형**에서는 **헤더**를 선택합니다. **키**에 **Authorization**를 입력합니다.

1. **권한 부여자 생성**을 선택합니다.

권한 부여자를 생성한 후 API의 **\$1connect** 경로에 권한 부여자를 연결합니다.

**\$1connect 경로에 권한 부여자를 연결하려면**

1. 기본 탐색 창에서 **경로**를 선택합니다.

1. **\$1connect** 경로를 선택합니다.

1. **경로 요청 설정** 섹션에서 **편집**을 선택합니다.

1. **권한 부여**의 경우 드롭다운 메뉴를 선택한 다음 요청 권한 부여자를 선택합니다.

1. **변경 사항 저장**을 선택합니다.

## 4단계: 모의 양방향 통합 생성
<a name="websocket-api-step-functions-create-mock-integration"></a>

다음으로 **\$1default** 경로에 대한 양방향 모의 통합을 생성합니다. 모의 통합을 사용하면 백엔드를 사용하지 않고도 클라이언트에 응답을 보낼 수 있습니다. **\$1default** 경로에 대한 통합을 생성하면 클라이언트에게 API와 상호 작용하는 방법을 보여줄 수 있습니다.

**\$1default** 경로를 구성하여 클라이언트에게 **sendmessage** 경로를 사용하도록 알릴 수 있습니다.

**모의 통합을 생성하는 방법**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **\$1default** 경로를 선택한 다음 **통합 요청** 탭을 선택합니다.

1. **요청 템플릿**의 경우 **편집**을 선택합니다.

1. **템플릿 선택 표현식**에 **200**을 입력한 다음 **편집**을 선택합니다.

1. **통합 요청** 탭의 **요청 템플릿**에서 **템플릿 생성**을 선택합니다.

1. **템플릿 키**에 **200**를 입력합니다.

1. **템플릿 생성**에 다음 매핑 템플릿을 입력합니다:

   ```
   {"statusCode": 200}
   ```

   **템플릿 생성**을 선택합니다.

   결과는 다음과 같아야 합니다.  
![\[$default 경로에 대한 모의 통합을 위한 통합 요청 구성\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/ws-sfn-mock-integration-request.png)

1. **\$1default 경로** 창에서 **양방향 통신 활성화**를 선택합니다.

1. **통합 응답** 탭을 선택한 다음 **통합 응답 생성**을 선택합니다.

1. **응답 본문**에 **\$1default**를 입력합니다.

1. **템플릿 선택 표현식**에 **200**을 입력합니다.

1. **응답 생성**을 선택합니다.

1. **응답 템플릿**에서 **템플릿 생성**을 선택합니다.

1. **템플릿 키**에 **200**를 입력합니다.

1. **응답 템플릿**에 다음 매핑 템플릿을 입력합니다.

   ```
   {"Use the sendmessage route to send a message. Connection ID: $context.connectionId"}
   ```

1. **템플릿 생성**을 선택합니다.

   결과는 다음과 같아야 합니다.  
![\[$default 경로에 대한 모의 통합을 위한 통합 응답 구성\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/ws-sfn-mock-integration-response.png)

## 5단계: Step Functions와의 비프록시 통합 생성
<a name="websocket-api-step-functions-create-step-function-integration"></a>

다음으로 **sendmessage** 경로를 생성합니다. 클라이언트는 **sendmessage** 경로를 간접 호출하여 연결된 모든 클라이언트에 메시지를 브로드캐스트할 수 있습니다. **sendmessage** 경로에는 AWS Step Functions와의 비프록시 AWS 서비스 통합이 있습니다. 통합은 CloudFormation 템플릿이 사용자를 위해 생성한 Step Functions 상태 머신에 대해 [StartExecution](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartExecution.html) 명령을 간접 호출합니다.

**비프록시 통합을 생성하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **경로 생성**(Create route)을 선택합니다.

1. **경로 키(Route key)**에 **sendmessage**를 입력합니다.

1. **통합 유형**에서 **AWS 서비스**를 선택합니다.

1. **AWS 리전**에는 CloudFormation 템플릿을 배포한 리전을 입력합니다.

1. **AWS 서비스**에서 **Step Functions**를 선택합니다.

1. **HTTP 메서드**에 대해 **POST**를 선택합니다.

1. **함수 이름**에 **StartExecution**를 입력합니다.

1. **실행 역할**에는 CloudFormation 템플릿에서 생성한 실행 역할을 입력합니다. 이름은 **WebsocketTutorialApiRole**이어야 합니다.

1. **경로 생성**(Create route)을 선택합니다.

다음으로, 요청 파라미터를 Step Functions 상태 머신에 전송하는 매핑 템플릿을 생성합니다.

**매핑 템플릿을 생성하려면**

1. **sendmessage** 경로를 선택한 다음 **통합 요청** 탭을 선택합니다.

1. **요청 템플릿** 섹션에서 **편집**을 선택합니다.

1. **템플릿 선택 표현식**에 **\$1\$1default**를 입력합니다.

1. **편집**을 선택합니다.

1. **템플릿 요청** 섹션에서 **템플릿 생성**을 선택합니다.

1. **템플릿 키**에 **\$1\$1default**를 입력합니다.

1. **템플릿 생성**에 다음 매핑 템플릿을 입력합니다.

   ```
   #set($domain = "$context.domainName")
   #set($stage = "$context.stage")
   #set($body = $input.json('$'))
   #set($getMessage = $util.parseJson($body))
   #set($mymessage = $getMessage.message)
   {
   "input": "{\"domain\": \"$domain\", \"stage\": \"$stage\", \"message\": \"$mymessage\"}",
   "stateMachineArn": "arn:aws:states:us-east-2:123456789012:stateMachine:WebSocket-Tutorial-StateMachine"
   }
   ```

   *stateMachineArn*을 CloudFormation이 만든 스테이트 머신의 ARN으로 바꿉니다.

   매핑 템플릿이 다음을 수행합니다.
   + 컨텍스트 변수 `domainName`을 사용하여 변수 `$domain`을 생성합니다.
   + 컨텍스트 변수 `stage`를 사용하여 변수 `$stage`를 생성합니다.

     `$domain` 및 `$stage` 변수는 콜백 URL을 작성하는 데 필요합니다.
   + 수신되는 `sendmessage` JSON 메시지를 받아 `message` 속성을 추출합니다.
   + 상태 머신에 대한 입력을 생성합니다. 입력은 WebSocket API의 도메인 및 스테이지와 `sendmessage` 경로의 메시지입니다.

1. **템플릿 생성**을 선택합니다.  
![\[sendmessage 경로 구성.\]](http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/images/ws-sfn-integration-request.png)

**\$1connect** 또는 **\$1disconnect** 경로에 비프록시 통합을 생성하여 Lambda 함수를 간접 호출하지 않고도 DynamoDB 테이블에 연결 ID를 직접 추가하거나 제거할 수 있습니다.

## 6단계: API 테스트
<a name="websocket-api-step-functions-test-api"></a>

다음으로 API를 배포하고 테스트하여 올바르게 작동하는지 확인합니다. `wscat` 명령을 사용하여 API에 연결한 다음 슬래시 명령을 사용하여 WebSocket API에 대한 연결을 확인하는 ping 프레임을 전송합니다.

**API를 배포하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. 기본 탐색 창에서 **경로**를 선택합니다.

1. **Deploy API(API 배포)**를 선택합니다.

1. **스테이지**에서는 **프로덕션**을 선택합니다.

1. (선택 사항) **배포 설명**에 설명을 입력합니다.

1. **배포(Deploy)**를 선택합니다.

API를 배포한 후 API를 간접 호출할 수 있습니다. 호출 간접 URL을 사용하여 API를 직접 호출할 수 있습니다.

**API의 URL 간접 호출을 가져오려면**

1. API를 선택합니다.

1. **스테이지(Stages)**를 선택한 다음 **프로덕션(production)**을 선택합니다.

1. API의 **WebSocket URL**을 기록해 둡니다. URL은 `wss://abcdef123.execute-api.us-east-2.amazonaws.com/production`와 같아야 합니다.

이제 간접 호출 URL이 연결되었으므로 WebSocket API에 대한 연결을 테스트할 수 있습니다.

**API에 대한 연결을 테스트하려면**

1. API에 연결하려면 다음 명령을 사용합니다. 먼저 `/ping` 경로를 간접 호출하여 연결을 테스트합니다.

   ```
   wscat -c wss://abcdef123.execute-api.us-east-2.amazonaws.com/production -H "Authorization: Allow" --slash -P
   ```

   ```
   Connected (press CTRL+C to quit)
   ```

1. 다음 명령을 입력하여 컨트롤 프레임을 핑합니다. 클라이언트 측에서 keepalive 목적으로 컨트롤 프레임을 사용할 수 있습니다.

   ```
   /ping
   ```

   결과는 다음과 같아야 합니다.

   ```
   < Received pong (data: "")
   ```

연결 테스트에 성공했으므로 API가 제대로 작동하는지 테스트할 수 있습니다. 이 단계에서는 WebSocket API가 연결된 모든 클라이언트에 메시지를 보낼 수 있도록 새 터미널 창을 엽니다.

**API 테스트하기**

1. 새 터미널을 열고 다음 파라미터를 사용하여 `wscat` 명령을 다시 실행합니다.

   ```
   wscat -c wss://abcdef123.execute-api.us-east-2.amazonaws.com/production -H "Authorization: Allow"
   ```

   ```
   Connected (press CTRL+C to quit)
   ```

1. API Gateway는 API의 경로 선택 표현식을 기반으로 간접 호출할 경로를 결정합니다. API의 경로 선택 표현식은 `$request.body.action`입니다. 따라서 API Gateway는 다음 메시지가 전송될 때 `sendmessage` 경로를 호출합니다.

   ```
   {"action": "sendmessage", "message": "hello, from Step Functions!"}
   ```

   경로와 연결된 Step Functions 상태 머신은 메시지 및 콜백 URL과 함께 Lambda 함수를 간접 호출합니다. Lambda 함수는 API Gateway Management API를 호출하고 모든 연결된 클라이언트에 메시지를 보냅니다. 모든 클라이언트는 다음과 같은 메시지를 받습니다.

   ```
   < hello, from Step Functions!
   ```

이제 WebSocket API를 테스트했으므로 API와의 연결을 끊을 수 있습니다.

**API 연결을 해제하려면**
+ API 연결을 해제하려면 `CTRL+C`를 누릅니다.

  클라이언트가 API에서 연결을 해제하면 API Gateway에서 API **\$1disconnect**의 경로를 간접 호출합니다. API의 **\$1disconnect** 경로에 대한 Lambda 통합이 DynamoDB에서 연결 ID를 제거합니다.

## 7단계: 정리
<a name="websocket-api-step-functions-cleanup"></a>

불필요한 비용을 방지하려면 이 자습서의 일부로 생성한 리소스를 삭제합니다. 다음 단계에서는 CloudFormation 스택 및 WebSocket API를 삭제합니다.

**WebSocket API를 삭제하려면**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)에서 API Gateway 콘솔에 로그인합니다.

1. **APIs** 페이지에서 **websocket-api**.를 선택합니다.

1. **작업**(Actions)을 선택하고 **삭제**(Delete)를 선택한 다음 선택을 확인합니다.

**CloudFormation 스택을 삭제하려면**

1. CloudFormation 콘솔([https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/))을 엽니다.

1. CloudFormation 스택을 선택합니다.

1. **삭제**를 선택한 다음 해당 선택을 확인합니다.

## 다음 단계
<a name="websocket-api-step-functions-next-steps"></a>

이 자습서와 관련된 모든 AWS 리소스의 생성 및 정리를 자동화할 수 있습니다. 이 자습서에서 이러한 작업을 자동화하는 CloudFormation 템플릿의 예는 [ws-sfn.zip](samples/ws-sfn-complete.zip)를 참조합니다.