

# API Gateway에서 WebSocket API 개발
<a name="websocket-api-develop"></a>

이 단원에서는 API Gateway API를 개발하는 동안 필요한 API Gateway 기능에 대해 자세히 설명합니다.

API Gateway API를 개발할 때 API의 여러 특성을 결정합니다. 이러한 특성은 API의 사용 사례에 따라 달라집니다. 예를 들어, 특정 클라이언트만 API를 호출하도록 허용하거나 모든 사용자가 API를 사용할 수 있도록 할 수 있습니다. API 호출로 Lambda 함수를 실행하거나, 데이터베이스 쿼리를 작성하거나, 애플리케이션을 호출할 수 있습니다.

**Topics**
+ [API Gateway에서 WebSocket API 생성](apigateway-websocket-api-create-empty-api.md)
+ [API Gateway의 WebSocket API에 대한 IP 주소 유형](websocket-api-ip-address-type.md)
+ [API Gateway에서 WebSocket API에 대한 라우팅 생성](websocket-api-develop-routes.md)
+ [API Gateway에서 WebSocket API에 대한 액세스 제어 및 관리](apigateway-websocket-api-control-access.md)
+ [API Gateway의 WebSocket API 통합](apigateway-websocket-api-integrations.md)
+ [API Gateway의 WebSocket API 검증 요청](websocket-api-request-validation.md)
+ [API Gateway에서 WebSocket API의 데이터 변환](websocket-api-data-transformations.md)
+ [API Gateway의 WebSocket API에 대한 이진 미디어 유형](websocket-api-develop-binary-media-types.md)
+ [WebSocket API 간접 호출](apigateway-how-to-call-websocket-api.md)

# API Gateway에서 WebSocket API 생성
<a name="apigateway-websocket-api-create-empty-api"></a>

AWS CLI [create-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html) 명령을 사용하거나 AWS SDK에서 `CreateApi` 명령을 사용하면 API Gateway 콘솔에서 WebSocket API를 생성할 수 있습니다. 다음 절차는 새 WebSocket API를 생성하는 방법을 보여줍니다.

**참고**  
WebSocket API는 TLS 1.2 및 TLS 1.3만 지원합니다. 이전 버전의 TLS는 지원되지 않습니다.

## AWS CLI 명령을 사용하여 WebSocket API 생성
<a name="apigateway-websocket-api-create-using-awscli"></a>

다음 [create-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html) 명령은 `$request.body.action` 경로 선택 표현식을 사용하여 API를 생성합니다.

```
aws apigatewayv2 --region us-east-1 create-api --name "myWebSocketApi3" --protocol-type WEBSOCKET --route-selection-expression '$request.body.action'
```

출력은 다음과 같습니다.

```
{
    "ApiKeySelectionExpression": "$request.header.x-api-key",
    "Name": "myWebSocketApi3",
    "CreatedDate": "2018-11-15T06:23:51Z",
    "ProtocolType": "WEBSOCKET",
    "RouteSelectionExpression": "'$request.body.action'",
    "ApiId": "aabbccddee"
}
```

## API Gateway 콘솔을 사용하여 WebSocket API 생성
<a name="apigateway-websocket-api-create-using-console"></a>

콘솔에서 WebSocket 프로토콜을 선택하고 API에 이름을 지정하여 WebSocket API를 만들 수 있습니다.

**중요**  
API를 생성한 후에는 선택한 프로토콜을 변경할 수 없습니다. WebSocket API를 REST API로 또는 그 반대로 변환할 수는 없습니다.

**API Gateway 콘솔을 사용하여 WebSocket API를 생성하려면**

1. API Gateway 콘솔에 로그인하고 **API 생성**을 선택합니다.

1. **WebSocket API**에서 **빌드**를 선택합니다. 리전 엔드포인트만 지원됩니다.

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

1. **라우팅 선택 표현식**에 값을 입력합니다. 예: `$request.body.action`.

   라우팅 선택 표현식에 대한 자세한 내용은 [라우팅 선택 표현식](websocket-api-develop-routes.md#apigateway-websocket-api-route-selection-expressions) 단원을 참조하십시오.

1. 다음 중 하나를 수행합니다.
   + 라우팅이 없는 API를 생성하려면 **빈 API 생성**을 선택합니다.
   + **다음**을 선택하여 API에 라우팅을 연결합니다.

   API를 생성한 후 라우팅을 연결할 수 있습니다.

# API Gateway의 WebSocket API에 대한 IP 주소 유형
<a name="websocket-api-ip-address-type"></a>

API를 만들 때 API를 간접적으로 호출할 수 있는 IP 주소 유형을 지정합니다. IPv4를 선택하여 IPv4 주소가 API를 간접적으로 호출하도록 확인하거나, 듀얼 스택을 선택하여 IPv4 및 IPv6 주소가 모두 API를 간접적으로 호출하도록 허용할 수 있습니다. IP 공간 소진을 완화하기 위해 또는 보안 태세를 위해 IP 주소 유형을 듀얼 스택으로 설정하는 것이 좋습니다. 듀얼 스택 IP 주소 유형의 이점에 대한 자세한 내용은 [IPv6 on AWS](https://docs.aws.amazon.com/whitepapers/latest/ipv6-on-aws/internet-protocol-version-6.html)를 참조하세요.

## IP 주소 유형에 대한 고려 사항
<a name="websocket-api-ip-address-type-considerations"></a>

다음 고려 사항은 IP 주소 유형 사용에 영향을 미칠 수 있습니다.
+ 모든 WebSocket API의 기본 IP 주소 유형은 IPv4입니다.
+ 기존 API의 IP 주소 유형을 IPv4에서 듀얼 스택으로 변경하는 경우 API에 대한 액세스를 제어하는 정책이 IPv6 직접 호출을 설명하도록 업데이트되었는지 확인합니다. IP 주소 유형을 변경하면 변경 사항이 즉시 적용됩니다.
+ API는 API와 다른 IP 주소 유형의 사용자 지정 도메인 이름에 매핑할 수 있습니다. 기본 API 엔드포인트를 비활성화하면 직접 호출자가 API를 간접적으로 호출하는 방법에 영향을 미칠 수 있습니다.

## WebSocket API의 IP 주소 유형 변경
<a name="websocket-api-ip-address-type-change"></a>

API의 구성을 업데이트하여 IP 주소 유형을 변경할 수 있습니다. AWS Management Console, AWS CLI, CloudFormation 또는 AWS SDK를 사용하여 API의 구성을 업데이트할 수 있습니다. API의 IP 주소 유형을 변경하는 경우 변경 사항이 적용되려면 API를 재배포해서는 안 됩니다.

------
#### [ AWS Management Console ]

**WebSocket API의 IP 주소 유형을 변경하려면**

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

1. WebSocket API를 선택합니다.

1. **API 설정**을 선택한 다음 **편집**을 선택합니다.

1. IP 주소 유형에서 **IPv4** 또는 **듀얼 스택**을 선택합니다.

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

   API 구성에 대한 변경 사항은 즉시 적용됩니다.

------
#### [ AWS CLI ]

다음 [update-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-api.html) 명령은 IP 주소 유형이 듀얼 스택이 되도록 API를 업데이트합니다.

```
aws apigatewayv2 update-api \
    --api-id abcd1234 \
    --ip-address-type dualstack
```

출력은 다음과 같습니다.

```
{
    "ApiEndpoint": "https://abcd1234.execute-api.us-east-1.amazonaws.com",
    "ApiId": "abcd1234",
    "ApiKeySelectionExpression": "$request.header.x-api-key",
    "CreatedDate": "2025-02-04T22:20:20+00:00",
    "DisableExecuteApiEndpoint": false,
    "Name": "My-WebSocket-API",
    "ProtocolType": "WEBSOCKET",
    "RouteSelectionExpression": "$request.method $request.path",
    "Tags": {},
    "NotificationUris": [],
    "IpAddressType": "dualstack"
}
```

------

# API Gateway에서 WebSocket API에 대한 라우팅 생성
<a name="websocket-api-develop-routes"></a>

WebSocket API에서 수신되는 JSON 메시지는 사용자가 구성한 라우팅을 기반으로 백엔드 통합으로 전달됩니다. (비 JSON 메시지는 사용자가 구성한 `$default` 라우팅으로 전달됩니다.)

*라우팅*에는 *라우팅 선택 표현식*을 평가할 경우 예상되는 값인 *라우팅 키*가 포함되어 있습니다. `routeSelectionExpression`은 API 수준에서 정의되는 속성입니다. 메시지 페이로드에 존재할 것으로 예상되는 JSON 속성을 지정합니다. 라우팅 선택 표현식에 대한 자세한 내용은 [라우팅 선택 표현식](#apigateway-websocket-api-route-selection-expressions) 단원을 참조하십시오.

예를 들어 JSON 메시지에 `action` 속성이 있고 이 속성을 기반으로 다른 작업을 수행하려는 경우, 라우팅 선택 표현식은 `${request.body.action}`일 수 있습니다. 라우팅 테이블은 사용자가 테이블에 정의한 사용자 지정 라우팅 키 값에 따라 `action` 속성 값을 일치시켜 어떤 작업을 수행할 것인지 지정할 것입니다.

`$connect`, `$disconnect`, `$default` 등 세 가지 사전 정의된 라우팅을 사용할 수 있습니다. 또한 사용자 지정 라우팅을 생성할 수 있습니다.
+ API Gateway는 클라이언트와 WebSocket API 간 지속적인 연결이 시작될 때 `$connect` 라우팅을 호출합니다.
+ API Gateway는 클라이언트 또는 서버가 API와의 연결을 끊을 때 `$disconnect` 라우팅을 호출합니다.
+ 일치하는 라우팅이 발견되면 메시지를 기준으로 라우팅 선택 표현식이 평가된 후 API Gateway가 사용자 지정 라우팅을 호출합니다. 일치 여부에 따라 어떤 통합이 호출될지 결정됩니다.
+ 일치하는 라우팅이 없거나 메시지를 기준으로 라우팅 선택 표현식을 평가할 수 없는 경우 API Gateway가 `$default` 라우팅을 호출합니다.

## 라우팅 선택 표현식
<a name="apigateway-websocket-api-route-selection-expressions"></a>

서비스가 수신 메시지에 대해 따라야 할 라우팅을 선택할 때 *라우팅 선택 표현식*이 평가됩니다. 서비스는 `routeKey`가 평가된 값과 정확하게 일치하는 라우팅을 사용합니다. 일치하는 값이 없고 라우팅 키가 `$default`인 라우팅이 존재하는 경우, 그 값이 선택됩니다. 평가된 값과 일치하는 라우팅이 없고 `$default` 라우팅이 없는 경우 서비스는 오류를 반환합니다. WebSocket 기반 API의 경우 표현식은 `$request.body.{path_to_body_element}` 형식이어야 합니다.

예를 들어 다음과 같은 JSON 메시지를 보낸다고 가정하겠습니다.

```
{
    "service" : "chat",
    "action" : "join",
    "data" : {
        "room" : "room1234"
   }
}
```

`action` 속성을 기반으로 API의 동작을 선택할 수 있습니다. 이 경우 다음 라우팅 선택 표현식을 정의할 수 있습니다.

```
$request.body.action
```

이 예에서 `request.body`는 메시지의 JSON 페이로드를 나타내며 `.action`은 [JSONPath](https://goessner.net/articles/JsonPath/) 표현식입니다. `request.body` 뒤에 모든 JSON 경로 표현식을 사용할 수 있지만 결과는 문자열로 변환됩니다. 예를 들어, JSONPath 표현식이 두 요소의 배열을 반환하면 `"[item1, item2]"` 문자열로 표시됩니다. 따라서 표현식을 배열이나 객체가 아닌 값으로 평가하는 것이 좋습니다.

단순히 정적 값을 사용하거나 여러 변수를 사용할 수 있습니다. 다음 표는 이전의 페이로드에 대한 예제와 평가된 결과를 보여줍니다.


| 표현식 | 평가된 결과 | 설명 | 
| --- | --- | --- | 
| \$1request.body.action | join | 언래핑된 변수 | 
| \$1\$1request.body.action\$1 | join | 래핑된 변수 | 
| \$1\$1request.body.service\$1/\$1\$1request.body.action\$1 | chat/join | 정적 값이 있는 여러 변수 | 
| \$1\$1request.body.action\$1-\$1\$1request.body.invalidPath\$1  | join- | JSONPath를 찾지 못하면 변수는 ""로 해석됩니다. | 
| action | action | 정적 값 | 
| \$1\$1default | \$1default | 정적 값 | 

평가된 결과는 라우팅을 찾는 데 사용됩니다. 일치하는 라우팅 키를 가진 라우팅이 있는 경우, 해당 라우팅이 선택되어 메시지를 처리합니다. 일치하는 라우팅이 없으면 API Gateway가 사용 가능한 `$default` 라우팅을 찾습니다. `$default` 라우팅이 정의되지 않은 경우, API Gateway는 오류를 반환합니다.

## API Gateway에서 WebSocket API에 대한 라우팅 설정
<a name="apigateway-websocket-api-routes"></a>

처음 새 WebSocket API를 생성할 때 `$connect`, `$disconnect`, `$default` 등 세 가지 사전 정의된 라우팅이 있습니다. 콘솔, API 또는 AWS CLI를 사용하여 생성할 수 있습니다. 필요에 따라 사용자 지정 라우팅을 생성할 수 있습니다. 자세한 내용은 [API Gateway의 WebSocket API 개요](apigateway-websocket-api-overview.md) 단원을 참조하세요.

**참고**  
CLI에서는 통합을 생성하기 이전 또는 이후에 라우팅을 생성할 수 있으며 여러 라우팅에 대해 동일한 통합을 재사용할 수 있습니다.

### API Gateway 콘솔을 사용하여 라우팅 생성
<a name="apigateway-websocket-api-route-using-console"></a>

**API Gateway 콘솔을 사용하여 라우팅을 생성하려면**

1. API Gateway 콘솔에 로그인하고 API를 선택한 다음 **라우팅**을 선택하세요.

1. **경로 생성**을 선택합니다.

1. **라우팅 키**에 라우팅 키 이름을 입력합니다. 사전 정의된 경로(`$connect`, `$disconnect` 및 `$default`) 또는 사용자 지정 경로를 생성할 수 있습니다.
**참고**  
사용자 지정 라우팅을 생성할 때 라우팅 키 이름에 `$` 접두사를 사용하지 마십시오. 이 접두사는 미리 정의된 라우팅에 예약되어 있습니다.

1. 경로의 통합 유형을 선택하고 구성합니다. 자세한 내용은 [API Gateway 콘솔을 사용하여 WebSocket API 통합 요청을 설정](apigateway-websocket-api-integration-requests.md#apigateway-websocket-api-integration-request-using-console) 섹션을 참조하세요.

### AWS CLI를 사용하여 라우팅 생성
<a name="apigateway-websocket-api-route-using-awscli"></a>

다음 [create-route](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-route.html) 명령은 라우팅을 생성합니다.

```
aws apigatewayv2 --region us-east-1 create-route --api-id aabbccddee --route-key $default
```

출력은 다음과 같습니다.

```
{
    "ApiKeyRequired": false,
    "AuthorizationType": "NONE",
    "RouteKey": "$default",
    "RouteId": "1122334"
}
```

### `$connect`에 대한 라우팅 요청 설정 지정
<a name="apigateway-websocket-api-route-request-connect"></a>

API에 대해 `$connect` 라우팅을 설정하면 다음 선택적 설정을 사용하여 API에 대한 권한 부여를 활성화할 수 있습니다. 자세한 내용은 [`$connect` 라우팅](apigateway-websocket-api-route-keys-connect-disconnect.md#apigateway-websocket-api-routes-about-connect) 단원을 참조하세요.
+ **권한 부여**: 권한 부여가 필요하지 않으면 `NONE`을 지정할 수 있습니다. 또는 다음을 지정할 수 있습니다.
  + `AWS_IAM`: 표준 AWS IAM 정책을 사용하여 API에 대한 액세스를 제어합니다.
  + `CUSTOM`: 이전에 생성한 Lambda 권한 부여자 함수를 지정하여 API에 대한 권한 부여를 구현합니다. 권한 부여자는 자신의 AWS 계정이나 다른 AWS 계정에 상주할 수 있습니다. Lambda 권한 부여자에 대한 자세한 내용은 [API Gateway Lambda 권한 부여자 사용](apigateway-use-lambda-authorizer.md) 단원을 참조하세요.
**참고**  
API Gateway 콘솔에서 `CUSTOM` 설정은 [Lambda 권한 부여자 구성(콘솔)](configure-api-gateway-lambda-authorization.md#configure-api-gateway-lambda-authorization-with-console)에서 설명한 대로 권한 부여자 함수를 설정한 후에만 볼 수 있습니다.
**중요**  
**권한 부여** 설정은 `$connect` 라우팅뿐만 아니라 전체 API에 적용됩니다. `$connect` 라우팅은 모든 연결에서 호출되기 때문에 다른 라우팅을 보호합니다.
+ **API Key Required(API 키 필요)**: 선택적으로, API의 `$connect` 라우팅에 대한 API 키가 필요할 수 있습니다. API 키와 사용량 계획을 함께 사용하여 API 액세스를 제어하고 추적할 수 있습니다. 자세한 내용은 [API Gateway의 REST API 사용량 계획 및 API 키](api-gateway-api-usage-plans.md) 단원을 참조하세요.

### API Gateway 콘솔을 사용하여 `$connect` 라우팅 요청 설정
<a name="apigateway-websocket-api-connect-route-request-using-console"></a>

API Gateway 콘솔을 사용하여 WebSocket API에 대한 `$connect` 라우팅 요청을 설정하려면 다음을 수행하세요.

1. API Gateway 콘솔에 로그인하고 API를 선택한 다음 **라우팅**을 선택하세요.

1. **경로**에서 [API Gateway 콘솔을 사용하여 라우팅 생성](#apigateway-websocket-api-route-using-console)을 따라 `$connect`를 선택하거나 `$connect` 경로를 생성합니다.

1. **경로 요청 설정** 섹션에서 **편집**을 선택합니다.

1. **권한 부여**에서 권한 부여 유형을 선택합니다.

1. `$connect` 경로용 API를 요구하려면 **API 키 필요**를 선택합니다.

1. **변경 사항 저장**을 선택합니다.

# API Gateway에서 WebSocket API에 대한 라우팅 응답 설정
<a name="apigateway-websocket-api-route-response"></a>

WebSocket 라우팅은 양방향 또는 단방향 통신으로 구성할 수 있습니다. 경로 응답을 설정하지 않으면 API Gateway가 경로 응답을 통해 백엔드 응답을 전달하지 않습니다.

**참고**  
WebSocket API에 대한 `$default` 경로 응답만 정의할 수 있습니다. 통합 응답을 사용하여 백엔드 서비스의 응답을 조작할 수 있습니다. 자세한 내용은 [통합 응답 개요](apigateway-websocket-api-integration-responses.md#apigateway-websocket-api-integration-response-overview) 섹션을 참조하세요.

API Gateway 콘솔이나 AWS CLI 또는 AWS SDK를 사용하여 경로 응답 및 응답 선택 표현식을 구성할 수 있습니다.

라우팅 응답 선택 표현식에 대한 자세한 내용은 [라우팅 응답 선택 표현식](apigateway-websocket-api-selection-expressions.md#apigateway-websocket-api-route-response-selection-expressions) 단원을 참조하십시오.

**Topics**
+ [API Gateway 콘솔을 사용하여 라우팅 응답 설정](#apigateway-websocket-api-route-response-using-console)
+ [AWS CLI를 사용하여 라우팅 응답 설정](#apigateway-websocket-api-route-response-using-awscli)

## API Gateway 콘솔을 사용하여 라우팅 응답 설정
<a name="apigateway-websocket-api-route-response-using-console"></a>

WebSocket API를 생성하고 프록시 Lambda 함수를 기본 경로에 연결한 후, API Gateway 콘솔을 사용하여 경로 응답을 설정할 수 있습니다.

1. API Gateway 콘솔에 로그인하고 `$default` 경로에 프록시 Lambda 함수가 통합된 WebSocket API를 선택합니다.

1. **Routes**(경로)에서 `$default` 경로를 선택합니다.

1. **양방향 통신 활성화**를 선택합니다.

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

1. API를 스테이지에 배포합니다.

 API에 연결하려면 다음 [ wscat](https://www.npmjs.com/package/wscat) 명령을 사용합니다. 에 대한 자세한 내용은 `wscat` 단원을 참조하세요.[`wscat`를 사용하여 WebSocket API에 연결하고 메시지 보내기](apigateway-how-to-call-websocket-api-wscat.md).

```
wscat -c wss://api-id.execute-api.us-east-2.amazonaws.com/test
```

 기본 경로를 호출하려면 enter(엔터) 버튼을 누릅니다. Lambda 함수 본문이 반환될 것입니다.

## AWS CLI를 사용하여 라우팅 응답 설정
<a name="apigateway-websocket-api-route-response-using-awscli"></a>

다음 [create-route-response](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-route-response.html) 명령은 `$default` 라우팅에 대한 라우팅 응답을 생성합니다. [get-apis](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/get-apis.html) 및 [get-routes](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/get-routes.html) 명령을 사용하여 API ID와 라우팅 ID를 식별할 수 있습니다.

```
aws apigatewayv2 create-route-response \
    --api-id aabbccddee \
    --route-id 1122334  \
    --route-response-key '$default'
```

출력은 다음과 같습니다.

```
{
    "RouteResponseId": "abcdef",
    "RouteResponseKey": "$default"
}
```

# WebSocket 하위 프로토콜이 필요한 `$connect` 라우팅 설정
<a name="websocket-connect-route-subprotocol"></a>

클라이언트는 WebSocket API에 연결하는 동안 [WebSocket 서브프로토콜](https://datatracker.ietf.org/doc/html/rfc6455#page-12)을 요청하기 위해 `Sec-WebSocket-Protocol` 필드를 사용할 수 있습니다. 클라이언트가 API가 지원하는 서브프로토콜을 요청하는 경우에만 연결을 허용하도록 `$connect` 라우팅에 대한 통합을 설정할 수 있습니다.

다음 예제 Lambda 함수는 `Sec-WebSocket-Protocol` 헤더를 클라이언트에 반환합니다. 이 함수는 클라이언트가 `myprotocol` 서브프로토콜을 지정하는 경우에만 API에 대한 연결을 설정합니다.

이 예제 API 및 Lambda 프록시 통합을 생성하는 CloudFormation 템플릿에 대해서는 [samples/ws-subprotocol.zip](samples/ws-subprotocol.zip) 단원을 참조하세요.

```
export const handler = async (event) => {
    if (event.headers != undefined) {
        const headers = toLowerCaseProperties(event.headers);
        
        if (headers['sec-websocket-protocol'] != undefined) {
            const subprotocolHeader = headers['sec-websocket-protocol'];
            const subprotocols = subprotocolHeader.split(',');
            
            if (subprotocols.indexOf('myprotocol') >= 0) {
                const response = {
                    statusCode: 200,
                    headers: {
                        "Sec-WebSocket-Protocol" : "myprotocol"
                    }
                };
                return response;
            }
        }
    }
    
    const response = {
        statusCode: 400
    };
        
    return response;
};

function toLowerCaseProperties(obj) {
    var wrapper = {};
    for (var key in obj) {
        wrapper[key.toLowerCase()] = obj[key];
    }
    return wrapper;
}
```

[https://www.npmjs.com/package/wscat](https://www.npmjs.com/package/wscat)를 사용하면 클라이언트가 API가 지원하는 서브프로토콜을 요청하는 경우에만 API가 연결을 허용하는지 테스트할 수 있습니다. 다음 명령은 `-s` 플래그를 사용하여 연결 중에 서브프로토콜을 지정합니다.

다음 명령은 지원되지 않는 서브프로토콜을 사용하여 연결을 시도합니다. 클라이언트가 `chat1` 서브프로토콜을 지정했기 때문에 Lambda 통합에서 400 오류를 반환하고 연결이 실패합니다.

```
wscat -c wss://api-id.execute-api.region.amazonaws.com/beta -s chat1
error: Unexpected server response: 400
```

다음 명령은 연결 요청에 지원되는 서브프로토콜을 포함합니다. Lambda 통합은 연결을 허용합니다.

```
wscat -c wss://api-id.execute-api.region.amazonaws.com/beta -s chat1,myprotocol
connected (press CTRL+C to quit)
```

WebSocket API 호출에 대한 자세한 내용은 [WebSocket API 간접 호출](apigateway-how-to-call-websocket-api.md) 단원을 참조하세요.

# API Gateway에서 WebSocket API에 대한 액세스 제어 및 관리
<a name="apigateway-websocket-api-control-access"></a>

API Gateway는 WebSocket API 액세스 제어 및 관리에 다중 메커니즘을 지원합니다.

다음 메커니즘은 인증 및 권한 부여에 사용할 수 있습니다.
+ **표준 AWS IAM 역할 및 정책**은 유연하고 강력한 액세스 제어를 제공합니다. IAM 역할 및 정책을 사용하여 API를 생성하고 관리할 수 있는 사용자와 API를 호출할 수 있는 사용자를 관리할 수 있습니다. 자세한 내용은 [IAM 권한 부여를 통해 WebSocket API에 대한 액세스 제어](apigateway-websocket-control-access-iam.md) 단원을 참조하세요.
+ **IAM 태그**는 액세스 제어를 위해 IAM 정책과 함께 사용할 수 있습니다. 자세한 내용은 [태그를 사용하여 API Gateway REST API 리소스에 대한 액세스 제어](apigateway-tagging-iam-policy.md) 단원을 참조하세요.
+ **Lambda 권한 부여자**는 Lambda 함수를 사용하여 API에 대한 액세스를 제어합니다. 자세한 내용은 [AWS Lambda REQUEST 권한 부여자를 통해 WebSocket API에 대한 액세스 제어](apigateway-websocket-api-lambda-auth.md) 섹션을 참조하세요.

보안 태세를 개선하려면 모든 WebSocket API에서 `$connect` 경로에 대한 권한 부여자를 구성하는 것이 좋습니다. 다양한 규정 준수 프레임워크를 준수하기 위해 이 작업을 수행해야 할 수 있습니다. 자세한 내용은 *AWS Security Hub 사용 설명서*에서 [Amazon API Gateway 제어](https://docs.aws.amazon.com/securityhub/latest/userguide/apigateway-controls.html)를 참조하세요.

**Topics**
+ [IAM 권한 부여를 통해 WebSocket API에 대한 액세스 제어](apigateway-websocket-control-access-iam.md)
+ [AWS Lambda REQUEST 권한 부여자를 통해 WebSocket API에 대한 액세스 제어](apigateway-websocket-api-lambda-auth.md)

# IAM 권한 부여를 통해 WebSocket API에 대한 액세스 제어
<a name="apigateway-websocket-control-access-iam"></a>

WebSocket API에서 IAM 권한 부여는 [REST API](api-gateway-control-access-using-iam-policies-to-invoke-api.md)와 유사하지만 다음과 같은 예외가 있습니다.
+ `execute-api` 작업은기존 작업(`ManageConnections`, `Invoke`) 이외에 `InvalidateCache`를 지원합니다. `ManageConnections`는 @connections API에 대한 액세스를 제어합니다.
+ WebSocket 라우팅은 다른 ARN 형식을 사용합니다.

  ```
  arn:aws:execute-api:region:account-id:api-id/stage-name/route-key
  ```
+ `@connections` API는 REST API와 동일한 ARN 형식을 사용합니다.

  ```
  arn:aws:execute-api:region:account-id:api-id/stage-name/POST/@connections
  ```

**중요**  
[IAM 권한 부여](#apigateway-websocket-control-access-iam)를 사용하는 경우 [Signature Version 4(SigV4)](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html)로 서명해야 합니다.

예를 들어 클라이언트에 다음 정책을 설정할 수 있습니다. 이 예제는 모든 사람이 `Invoke` 스테이지에서 비밀 라우팅을 제외한 모든 라우팅에 대한 메시지(`prod`)를 보내도록 허용하고, 모든 사람이 모든 스테이지에 대해 연결된 클라이언트(`ManageConnections`)로 메시지를 보내는 것을 금지합니다.

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "execute-api:Invoke"
            ],
            "Resource": [
                "arn:aws:execute-api:us-east-1:111122223333:api-id/prod/*"
            ]
        },
        {
            "Effect": "Deny",
            "Action": [
                "execute-api:Invoke"
            ],
            "Resource": [
                "arn:aws:execute-api:us-east-1:111122223333:api-id/prod/secret"
            ]
        },
        {
            "Effect": "Deny",
            "Action": [
                "execute-api:ManageConnections"
            ],
            "Resource": [
                "arn:aws:execute-api:us-east-1:111122223333:api-id/*"
            ]
        }
    ]
}
```

------

# AWS Lambda REQUEST 권한 부여자를 통해 WebSocket API에 대한 액세스 제어
<a name="apigateway-websocket-api-lambda-auth"></a>

WebSocket API에서 Lambda 권한 부여자 함수는 [REST API](apigateway-use-lambda-authorizer.md#api-gateway-lambda-authorizer-lambda-function-create)와 유사하지만 다음과 같은 예외가 있습니다.
+  `$connect`경로에 Lambda 권한 부여자 함수만 사용할 수 있습니다.
+ 경로는 고정되어 있으므로 경로 변수(`event.pathParameters`)를 사용할 수 없습니다.
+ `event.methodArn`은 HTTP 메서드가 없으므로 상응하는 REST API와 다릅니다. `$connect`의 경우, `methodArn`은 `"$connect"`로 끝납니다.

  ```
  arn:aws:execute-api:region:account-id:api-id/stage-name/$connect
  ```
+ `event.requestContext`의 컨텍스트 변수는 REST API에 대한 변수와 다릅니다.

 다음 예시는 WebSocket API에 대한 `REQUEST` 권한 부여자 입력을 보여줍니다.

```
{
    "type": "REQUEST",
    "methodArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/default/$connect",
    "headers": {
        "Connection": "upgrade",
        "content-length": "0",
        "HeaderAuth1": "headerValue1",
        "Host": "abcdef123.execute-api.us-east-1.amazonaws.com",
        "Sec-WebSocket-Extensions": "permessage-deflate; client_max_window_bits",
        "Sec-WebSocket-Key": "...",
        "Sec-WebSocket-Version": "13",
        "Upgrade": "websocket",
        "X-Amzn-Trace-Id": "...",
        "X-Forwarded-For": "...",
        "X-Forwarded-Port": "443",
        "X-Forwarded-Proto": "https"
    },
    "multiValueHeaders": {
        "Connection": [
            "upgrade"
        ],
        "content-length": [
            "0"
        ],
        "HeaderAuth1": [
            "headerValue1"
        ],
        "Host": [
            "abcdef123.execute-api.us-east-1.amazonaws.com"
        ],
        "Sec-WebSocket-Extensions": [
            "permessage-deflate; client_max_window_bits"
        ],
        "Sec-WebSocket-Key": [
            "..."
        ],
        "Sec-WebSocket-Version": [
            "13"
        ],
        "Upgrade": [
            "websocket"
        ],
        "X-Amzn-Trace-Id": [
            "..."
        ],
        "X-Forwarded-For": [
            "..."
        ],
        "X-Forwarded-Port": [
            "443"
        ],
        "X-Forwarded-Proto": [
            "https"
        ]
    },
    "queryStringParameters": {
        "QueryString1": "queryValue1"
    },
    "multiValueQueryStringParameters": {
        "QueryString1": [
            "queryValue1"
        ]
    },
    "stageVariables": {},
    "requestContext": {
        "routeKey": "$connect",
        "eventType": "CONNECT",
        "extendedRequestId": "...",
        "requestTime": "19/Jan/2023:21:13:26 +0000",
        "messageDirection": "IN",
        "stage": "default",
        "connectedAt": 1674162806344,
        "requestTimeEpoch": 1674162806345,
        "identity": {
            "sourceIp": "..."
        },
        "requestId": "...",
        "domainName": "abcdef123.execute-api.us-east-1.amazonaws.com",
        "connectionId": "...",
        "apiId": "abcdef123"
    }
}
```

다음의 Lambda 권한 부여자 함수 예제는 [Lambda 권한 부여자 함수의 추가 예제](apigateway-use-lambda-authorizer.md#api-gateway-lambda-authorizer-lambda-function-create)의 REST API에 대한 Lambda 권한 부여자 함수의 WebSocket 버전입니다.

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

```
   // A simple REQUEST authorizer example to demonstrate how to use request 
   // parameters to allow or deny a request. In this example, a request is  
   // authorized if the client-supplied HeaderAuth1 header and QueryString1 query parameter
   // in the request context match the specified values of
   // of 'headerValue1' and 'queryValue1' respectively.
            export const handler = function(event, context, callback) {
    console.log('Received event:', JSON.stringify(event, null, 2));

   // Retrieve request parameters from the Lambda function input:
   var headers = event.headers;
   var queryStringParameters = event.queryStringParameters;
   var stageVariables = event.stageVariables;
   var requestContext = event.requestContext;
       
   // Parse the input for the parameter values
   var tmp = event.methodArn.split(':');
   var apiGatewayArnTmp = tmp[5].split('/');
   var awsAccountId = tmp[4];
   var region = tmp[3];
   var ApiId = apiGatewayArnTmp[0];
   var stage = apiGatewayArnTmp[1];
   var route = apiGatewayArnTmp[2];
       
   // Perform authorization to return the Allow policy for correct parameters and 
   // the 'Unauthorized' error, otherwise.
   var authResponse = {};
   var condition = {};
    condition.IpAddress = {};
    
   if (headers.HeaderAuth1 === "headerValue1"
       && queryStringParameters.QueryString1 === "queryValue1") {
        callback(null, generateAllow('me', event.methodArn));
    }  else {
        callback(null, generateDeny('me', event.methodArn)); 
    }
}
    
// Helper function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
   // Required output:
   var authResponse = {};
    authResponse.principalId = principalId;
   if (effect && resource) {
       var policyDocument = {};
        policyDocument.Version = '2012-10-17		 	 	 '; // default version
       policyDocument.Statement = [];
       var statementOne = {};
        statementOne.Action = 'execute-api:Invoke'; // default action
       statementOne.Effect = effect;
        statementOne.Resource = resource;
        policyDocument.Statement[0] = statementOne;
        authResponse.policyDocument = policyDocument;
    }
   // Optional output with custom properties of the String, Number or Boolean type.
   authResponse.context = {
       "stringKey": "stringval",
       "numberKey": 123,
       "booleanKey": true
    };
   return authResponse;
}
    
var generateAllow = function(principalId, resource) {
   return generatePolicy(principalId, 'Allow', resource);
}
    
var generateDeny = function(principalId, resource) {
   return generatePolicy(principalId, 'Deny', resource);
}
```

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

```
# A simple REQUEST authorizer example to demonstrate how to use request
# parameters to allow or deny a request. In this example, a request is
# authorized if the client-supplied HeaderAuth1 header and QueryString1 query parameter
# in the request context match the specified values of
# of 'headerValue1' and 'queryValue1' respectively.

import json


def lambda_handler(event, context):
    print(event)

    # Retrieve request parameters from the Lambda function input:
    headers = event['headers']
    queryStringParameters = event['queryStringParameters']
    stageVariables = event['stageVariables']
    requestContext = event['requestContext']

    # Parse the input for the parameter values
    tmp = event['methodArn'].split(':')
    apiGatewayArnTmp = tmp[5].split('/')
    awsAccountId = tmp[4]
    region = tmp[3]
    ApiId = apiGatewayArnTmp[0]
    stage = apiGatewayArnTmp[1]
    route = apiGatewayArnTmp[2]

    # Perform authorization to return the Allow policy for correct parameters
    # and the 'Unauthorized' error, otherwise.

    authResponse = {}
    condition = {}
    condition['IpAddress'] = {}

    if (headers['HeaderAuth1'] ==
            "headerValue1" and queryStringParameters["QueryString1"] == "queryValue1"):
        response = generateAllow('me', event['methodArn'])
        print('authorized')
        return json.loads(response)
    else:
        response = generateDeny('me', event['methodArn'])
        print('unauthorized')
        return json.loads(response)

    # Help function to generate IAM policy


def generatePolicy(principalId, effect, resource):
    authResponse = {}
    authResponse['principalId'] = principalId
    if (effect and resource):
        policyDocument = {}
        policyDocument['Version'] = '2012-10-17		 	 	 '
        policyDocument['Statement'] = []
        statementOne = {}
        statementOne['Action'] = 'execute-api:Invoke'
        statementOne['Effect'] = effect
        statementOne['Resource'] = resource
        policyDocument['Statement'] = [statementOne]
        authResponse['policyDocument'] = policyDocument

    authResponse['context'] = {
        "stringKey": "stringval",
        "numberKey": 123,
        "booleanKey": True
    }

    authResponse_JSON = json.dumps(authResponse)

    return authResponse_JSON


def generateAllow(principalId, resource):
    return generatePolicy(principalId, 'Allow', resource)


def generateDeny(principalId, resource):
    return generatePolicy(principalId, 'Deny', resource)
```

------

앞의 Lambda 함수를 WebSocket API에 대한 `REQUEST`권한 부여자 함수로 구성하려면 [REST API](configure-api-gateway-lambda-authorization.md#configure-api-gateway-lambda-authorization-with-console)와 같은 절차를 따르세요.

콘솔에서 이 Lambda 권한 부여자를 사용하도록 `$connect` 라우팅을 구성하려면 `$connect` 라우팅을 선택하거나 만듭니다. **경로 요청 설정** 섹션에서 **편집**을 선택합니다. **권한 부여** 드롭다운 메뉴에서 권한 부여자를 선택한 다음 **변경 사항 저장**을 선택합니다.

권한 부여자를 테스트하려면 새 연결을 생성해야 합니다. `$connect`에서 권한 부여자를 변경해도 이미 연결된 클라이언트에는 영향을 미치지 않습니다. WebSocket API에 연결할 때 구성된 모든 자격 증명 소스에 값을 제공해야 합니다. 예를 들어 다음 예제와 같이 `wscat`를 사용하여 유효한 쿼리 문자열과 헤더를 보내 연결할 수 있습니다.

```
wscat -c 'wss://myapi.execute-api.us-east-1.amazonaws.com/beta?QueryString1=queryValue1' -H HeaderAuth1:headerValue1
```

유효한 자격 증명 값 없이 연결을 시도하면 `401` 응답을 받게 됩니다.

```
wscat -c wss://myapi.execute-api.us-east-1.amazonaws.com/beta
error: Unexpected server response: 401
```

# API Gateway의 WebSocket API 통합
<a name="apigateway-websocket-api-integrations"></a>

API 라우팅을 설정한 후 이를 백엔드의 엔드포인트와 통합해야 합니다. 백엔드 엔드포인트는 통합 엔드포인트라고도 하며, Lambda 함수, HTTP 엔드포인트 또는 AWS 서비스 작업일 수 있습니다. API 통합에는 통합 요청 및 통합 응답이 있습니다.

이 섹션에서는 WebSocket API에 대한 통합 요청 및 통합 응답을 설정하는 방법에 대해 알아볼 수 있습니다.

**Topics**
+ [API Gateway에서 WebSocket API 통합 요청 설정](apigateway-websocket-api-integration-requests.md)
+ [API Gateway에서 WebSocket API 통합 응답 설정](apigateway-websocket-api-integration-responses.md)

# API Gateway에서 WebSocket API 통합 요청 설정
<a name="apigateway-websocket-api-integration-requests"></a>

통합 요청을 설정하려면 다음 단계를 수행합니다.
+ 백엔드에 통합할 경로 키를 선택합니다.
+ 호출할 백엔드 엔드포인트 지정. WebSocket API는 다음과 같은 통합 유형을 지원합니다.
  + `AWS_PROXY`
  + `AWS`
  + `HTTP_PROXY`
  + `HTTP`
  + `MOCK`

  통합 유형에 대한 자세한 내용은 API Gateway V2 REST API의 [IntegrationType](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations-integrationid.html#apis-apiid-integrations-integrationid-prop-integration-integrationtype)을 참조하세요.
+ 필요할 경우 하나 이상의 요청 템플릿을 지정하여 라우팅 요청 데이터를 어떻게 통합 요청 데이터로 변환할 것인지 구성합니다.

## API Gateway 콘솔을 사용하여 WebSocket API 통합 요청을 설정
<a name="apigateway-websocket-api-integration-request-using-console"></a>

**API Gateway 콘솔을 사용하여 WebSocket API의 라우팅에 통합 요청을 추가하려면**

1. API Gateway 콘솔에 로그인하고 API를 선택한 다음 **라우팅**을 선택하세요.

1. **라우팅**에서 라우팅을 선택합니다.

1. **통합 요청** 탭을 선택한 다음 **통합 요청 설정** 섹션에서 **편집**을 선택합니다.

1. **통합 유형**에서 다음 중 하나를 선택합니다.
   + API가 이 계정 또는 다른 계정에서 이미 생성한 AWS Lambda 함수와 통합되는 경우에만 **Lambda 함수**를 선택합니다.

     AWS Lambda에서 새로운 Lambda 함수를 생성하거나 Lambda 함수에 대한 리소스 권한을 설정하거나 다른 Lambda 서비스 작업을 수행하려면 대신 **AWS 서비스**를 선택하세요.
   + API가 기존 HTTP 엔드포인트와 통합될 예정이라면 **HTTP**를 선택합니다. 자세한 내용은 [API Gateway의 REST API에 대한 HTTP 통합](setup-http-integrations.md) 단원을 참조하세요.
   + 통합 백엔드 없이 직접 API Gateway에서 API 응답을 생성하려면 **모의(Mock)**를 선택하세요. 자세한 내용은 [API Gateway의 REST API 모의 통합](how-to-mock-integration.md) 단원을 참조하세요.
   + API가 AWS 서비스와 직접 통합될 예정이라면 **AWS 서비스**를 선택합니다.
   + API가 프라이빗 통합 엔드포인트로 `VpcLink`를 사용할 경우 **VPC 링크**를 선택합니다. 자세한 내용은 [프라이빗 통합 설정](set-up-private-integration.md) 단원을 참조하세요.

1. **Lambda 함수**를 선택한 경우 다음을 수행합니다.

   1. **Lambda 프록시 통합 사용**의 경우, [Lambda 프록시 통합](set-up-lambda-proxy-integrations.md#api-gateway-create-api-as-simple-proxy) 또는 [교차 계정 Lambda 프록시 통합](apigateway-cross-account-lambda-integrations.md)을 사용하려면 해당 확인란을 선택합니다.

   1. **Lambda 함수**의 경우, 다음 방법 중 하나로 함수를 지정합니다.
      + Lambda 함수가 동일한 계정에 있으면 함수 이름을 입력한 후 드롭다운 목록에서 해당 함수를 선택합니다.
**참고**  
함수 이름은 `HelloWorld`, `HelloWorld:1` 또는 `HelloWorld:alpha`에서와 같이, 별칭 또는 버전 사양을 선택적으로 포함할 수 있습니다.
      + 함수가 다른 계정에 있으면 함수의 ARN을 입력합니다.

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

1. **HTTP**를 선택한 경우, [API Gateway 콘솔을 사용하여 API 통합 요청 설정](how-to-method-settings-console.md)의 4단계 지침을 따릅니다.

1. **Mock(모의)**을 선택한 경우 **Request Templates(요청 템플릿)** 단계로 진행하십시오.

1. **AWS 서비스**를 선택한 경우, [API Gateway 콘솔을 사용하여 API 통합 요청 설정](how-to-method-settings-console.md)의 6단계 지침을 따릅니다.

1. **VPC 링크**를 선택한 경우 다음을 수행합니다.

   1. **프록시 통합 사용**에서 요청이 `VPCLink`의 엔드포인트로 프록시되도록 하려면 확인란을 선택합니다.

   1. **HTTP 메서드(HTTP method)**에서 HTTP 백엔드의 메서드와 가장 가까운 HTTP 메서드 유형을 선택합니다.

   1. **VPC 링크** 드롭다운 목록에서 VPC 링크를 선택합니다. `[Use Stage Variables]`를 선택하고 목록 아래의 텍스트 상자에 **\$1\$1stageVariables.vpcLinkId\$1**를 입력할 수 있습니다.

      API를 스테이지에 배포한 후 `vpcLinkId` 스테이지 변수를 정의하고, 그 값을 `VpcLink`의 ID로 설정할 수 있습니다.

   1. **Endpoint URL(엔드포인트 URL)**에서 이 통합을 사용하고자 하는 HTTP 백엔드의 URL을 입력합니다.

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

1. **Save changes**(변경 사항 저장)를 선택합니다.

1. **요청 템플릿**에서 다음의 작업을 수행합니다.

   1. **템플릿 선택 표현식**을 입력하려면 **요청 템플릿**에서 **편집**을 선택합니다.

   1. **템플릿 선택 표현식**을 입력합니다. 메시지 페이로드에서 API Gateway가 찾는 표현식을 사용합니다. 검색되면 평가가 이루어지고, 그 결과는 메시지 페이로드의 데이터에 적용할 데이터 매핑 템플릿을 선택하는 데 사용되는 템플릿 키 값입니다. 다음 단계에서는 데이터 매핑 템플릿을 생성합니다. **편집**을 선택하여 변경 사항을 저장합니다.

   1. **템플릿 생성**을 선택하여 데이터 매핑 템플릿을 생성합니다. **템플릿 키**에는 메시지 페이로드의 데이터에 적용할 데이터 매핑 템플릿을 선택하는 데 사용되는 템플릿 키 값을 입력합니다. 그런 다음 매핑 템플릿을 입력합니다. **템플릿 생성**을 선택합니다.

      템플릿 선택 표현식에 대한 내용은 [템플릿 선택 표현식](websocket-api-data-transformations.md#apigateway-websocket-api-template-selection-expressions) 단원을 참조하십시오.

## AWS CLI를 사용하여 통합 요청 설정
<a name="apigateway-websocket-api-integration-request-using-awscli"></a>

모의 통합을 생성하는 다음 예제와 같이 AWS CLI를 사용하여 WebSocket API에서 라우팅에 대한 통합 요청을 설정할 수 있습니다.

1. 다음 콘텐츠를 통해 `integration-params.json`이라는 파일을 생성합니다.

   ```
   {"PassthroughBehavior": "WHEN_NO_MATCH", "TimeoutInMillis": 29000, "ConnectionType": "INTERNET", "RequestTemplates": {"application/json": "{\"statusCode\":200}"}, "IntegrationType": "MOCK"}
   ```

1. 다음 [create-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-integration.html) 명령을 사용하여 모의 통합을 생성합니다.

   ```
   aws apigatewayv2 --region us-east-1 create-integration --api-id aabbccddee --cli-input-json file://integration-params.json
   ```

   출력은 다음과 같습니다.

   ```
   {
       "PassthroughBehavior": "WHEN_NO_MATCH",
       "TimeoutInMillis": 29000,
       "ConnectionType": "INTERNET",
       "IntegrationResponseSelectionExpression": "${response.statuscode}",
       "RequestTemplates": {
           "application/json": "{\"statusCode\":200}"
       },
       "IntegrationId": "0abcdef",
       "IntegrationType": "MOCK"
   }
   ```

또는 AWS CLI를 사용하여 프록시 통합에 대한 통합 요청을 설정할 수 있습니다.

1. Lambda 콘솔에서 Lambda 함수를 생성하고 기본 Lambda 실행 역할을 부여하세요.

1. 다음 [create-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-integration.html) 명령을 사용하여 통합을 생성합니다.

   ```
   aws apigatewayv2 create-integration --api-id aabbccddee --integration-type AWS_PROXY --integration-method POST --integration-uri arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:123412341234:function:simpleproxy-echo-e2e/invocations
   ```

출력은 다음과 같습니다.

```
{
    "PassthroughBehavior": "WHEN_NO_MATCH",
    "IntegrationMethod": "POST",
    "TimeoutInMillis": 29000,
    "ConnectionType": "INTERNET",
    "IntegrationUri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:123412341234:function:simpleproxy-echo-e2e/invocations",
    "IntegrationId": "abcdefg",
    "IntegrationType": "AWS_PROXY"
}
```

## WebSocket API의 프록시 통합에 대한 Lambda 함수의 입력 형식
<a name="api-gateway-simple-proxy-for-lambda-input-format-websocket"></a>

Lambda 프록시 통합을 사용할 경우 API Gateway에서 전체 클라이언트 요청을 백엔드 Lambda 함수의 입력 `event` 파라미터에 매핑합니다. 다음 예제에서는 API Gateway가 Lambda 프록시 통합으로 보내는 `$connect` 경로의 입력 이벤트와 `$disconnect` 경로의 입력 이벤트의 구조를 보여줍니다.

------
#### [ Input from the \$1connect route ]

```
{
    headers: {
      Host: 'abcd123.execute-api.us-east-1.amazonaws.com',
      'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
      'Sec-WebSocket-Key': '...',
      'Sec-WebSocket-Version': '13',
      'X-Amzn-Trace-Id': '...',
      'X-Forwarded-For': '192.0.2.1',
      'X-Forwarded-Port': '443',
      'X-Forwarded-Proto': 'https'
    },
    multiValueHeaders: {
      Host: [ 'abcd123.execute-api.us-east-1.amazonaws.com' ],
      'Sec-WebSocket-Extensions': [ 'permessage-deflate; client_max_window_bits' ],
      'Sec-WebSocket-Key': [ '...' ],
      'Sec-WebSocket-Version': [ '13' ],
      'X-Amzn-Trace-Id': [ '...' ],
      'X-Forwarded-For': [ '192.0.2.1' ],
      'X-Forwarded-Port': [ '443' ],
      'X-Forwarded-Proto': [ 'https' ]
    },
    requestContext: {
      routeKey: '$connect',
      eventType: 'CONNECT',
      extendedRequestId: 'ABCD1234=',
      requestTime: '09/Feb/2024:18:11:43 +0000',
      messageDirection: 'IN',
      stage: 'prod',
      connectedAt: 1707502303419,
      requestTimeEpoch: 1707502303420,
      identity: { sourceIp: '192.0.2.1' },
      requestId: 'ABCD1234=',
      domainName: 'abcd1234.execute-api.us-east-1.amazonaws.com',
      connectionId: 'AAAA1234=',
      apiId: 'abcd1234'
    },
    isBase64Encoded: false
  }
```

------
#### [ Input from the \$1disconnect route ]

```
{
    headers: {
      Host: 'abcd1234.execute-api.us-east-1.amazonaws.com',
      'x-api-key': '',
      'X-Forwarded-For': '',
      'x-restapi': ''
    },
    multiValueHeaders: {
      Host: [ 'abcd1234.execute-api.us-east-1.amazonaws.com' ],
      'x-api-key': [ '' ],
      'X-Forwarded-For': [ '' ],
      'x-restapi': [ '' ]
    },
    requestContext: {
      routeKey: '$disconnect',
      disconnectStatusCode: 1005,
      eventType: 'DISCONNECT',
      extendedRequestId: 'ABCD1234=',
      requestTime: '09/Feb/2024:18:23:28 +0000',
      messageDirection: 'IN',
      disconnectReason: 'Client-side close frame status not set',
      stage: 'prod',
      connectedAt: 1707503007396,
      requestTimeEpoch: 1707503008941,
      identity: { sourceIp: '192.0.2.1' },
      requestId: 'ABCD1234=',
      domainName: 'abcd1234.execute-api.us-east-1.amazonaws.com',
      connectionId: 'AAAA1234=',
      apiId: 'abcd1234'
    },
    isBase64Encoded: false
  }
```

------

# API Gateway에서 WebSocket API 통합 응답 설정
<a name="apigateway-websocket-api-integration-responses"></a>

다음 섹션에서는 WebSocket API 통합 응답에 대한 간략한 개요와 WebSocket API 통합 응답을 설정하는 방법을 제공합니다.

**Topics**
+ [통합 응답 개요](#apigateway-websocket-api-integration-response-overview)
+ [양방향 커뮤니케이션을 위한 통합 응답](#apigateway-websocket-api-integration-response-for-two-way-communication)
+ [API Gateway 콘솔을 사용하여 통합 응답 설정](#apigateway-websocket-api-integration-response-using-console)
+ [AWS CLI를 사용하여 통합 응답 설정](#apigateway-websocket-api-integration-response-using-awscli)

## 통합 응답 개요
<a name="apigateway-websocket-api-integration-response-overview"></a>

API Gateway의 통합 응답은 백엔드 서비스의 응답을 모델링하고 조작하는 한 방법입니다. WebSocket API 통합 응답과 REST API 설정을 비교한 아래 설명을 보면 몇 가지 차이점이 있지만 개념상 동작은 같습니다.

WebSocket 라우팅은 양방향 또는 단방향 통신으로 구성할 수 있습니다.
+ 라우팅이 양방향 통신을 위해 구성되면 통합 응답을 통해 REST API에 대한 통합 응답과 마찬가지로 반환된 메시지 페이로드에 대한 변환을 구성할 수 있습니다.
+ 라우팅이 단방향 통신을 위해 구성된 경우, 통합 응답 구성에 관계없이 메시지가 처리된 후 WebSocket 채널을 통해 응답이 반환되지 않습니다.

 경로 응답을 설정하지 않으면 API Gateway가 경로 응답을 통해 백엔드 응답을 전달하지 않습니다. 경로 응답 설정에 대한 자세한 내용은 [API Gateway에서 WebSocket API에 대한 라우팅 응답 설정](apigateway-websocket-api-route-response.md) 섹션을 참조하세요.

## 양방향 커뮤니케이션을 위한 통합 응답
<a name="apigateway-websocket-api-integration-response-for-two-way-communication"></a>

통합은 *프록시* 통합과 *비 프록시* 통합으로 나눌 수 있습니다.

**중요**  
*프록시 통합*의 경우, API Gateway가 자동으로 백엔드 출력을 호출자에게 전체 페이로드로 전달합니다. 통합 응답이 없습니다.

*비 프록시 통합*의 경우 최소한 하나의 통합 응답을 설정해야 합니다.
+ 명시적 선택을 할 수 없을 때 통합 응답 중 하나가 catch-all 역할을 하는 것이 이상적입니다. 이 기본 경우는 통합 응답 키 `$default` 설정으로 표현됩니다.
+ 다른 모든 경우에는 통합 응답 키가 정규 표현식으로 사용됩니다. `"/expression/"` 형식을 따라야 합니다.

비 프록시 HTTP 통합의 경우:
+ API Gateway가 백엔드 응답의 HTTP 상태 코드와 일치시키려고 합니다. 이 경우 통합 응답 키가 정규식으로 사용됩니다. 일치 항목을 찾을 수 없으면 `$default`가 통합 응답으로 선택됩니다.
+ 템플릿 선택 표현식은 위에서 설명한 대로 작동합니다. 예:
  + `/2\d\d/`: 성공적인 응답 수신 및 변환
  + `/4\d\d/`: 잘못된 요청 오류 수신 및 변환
  + `$default`: 예기치 않은 모든 응답 수신 및 변환

템플릿 선택 표현식에 대한 자세한 내용은 [템플릿 선택 표현식](websocket-api-data-transformations.md#apigateway-websocket-api-template-selection-expressions) 섹션을 참조하세요.

## API Gateway 콘솔을 사용하여 통합 응답 설정
<a name="apigateway-websocket-api-integration-response-using-console"></a>

API Gateway 콘솔을 사용하여 WebSocket API에 대한 라우팅 통합 응답을 설정하려면 다음을 수행하세요.

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

1.  WebSocket API를 선택하고 경로를 선택합니다.

1. **통합 요청** 탭을 선택한 다음 **통합 응답 설정** 섹션에서 **통합 응답 생성**을 선택합니다.

1. **응답 키**에 응답 선택 표현식을 평가한 후 보내는 메시지에 있는 응답 키에서 찾을 수 있는 값을 입력합니다. 예를 들어 잘못된 요청 오류를 수신하고 변환하려면 **/4\$1d\$1d/**를 입력하고 템플릿 선택 표현식과 일치하는 모든 응답을 수신하고 변환하려면 **\$1default**를 입력할 수 있습니다.

1. **템플릿 선택 표현식**에 보내는 메시지를 평가하기 위한 선택 표현식을 입력합니다.

1. **응답 생성**을 선택합니다.

1. 매핑 템플릿을 정의하여 반환된 메시지 페이로드의 변환을 구성할 수도 있습니다. **템플릿 생성**을 선택합니다.

1. 키 이름을 입력합니다. 기본 템플릿 선택 표현식을 선택하는 경우 **\$1\$1default**를 입력합니다.

1. **응답 템플릿**에서 코드 편집기에 매핑 템플릿을 입력합니다.

1. **템플릿 생성**을 선택합니다.

1. **API 배포**를 선택하여 API를 배포합니다.

 API에 연결하려면 다음 [ wscat](https://www.npmjs.com/package/wscat) 명령을 사용합니다. `wscat`에 대한 자세한 정보는 [`wscat`를 사용하여 WebSocket API에 연결하고 메시지 보내기](apigateway-how-to-call-websocket-api-wscat.md) 섹션을 참조하십시오.

```
wscat -c wss://api-id.execute-api.us-east-2.amazonaws.com/test
```

 경로를 호출하면 반환된 메시지 페이로드가 반환됩니다.

## AWS CLI를 사용하여 통합 응답 설정
<a name="apigateway-websocket-api-integration-response-using-awscli"></a>

다음 [create-integration-response](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-integration-response.html) 명령은 `$default` 통합 응답을 생성합니다.

```
aws apigatewayv2 create-integration-response \
    --api-id vaz7da96z6 \
    --integration-id a1b2c3 \
    --integration-response-key '$default'
```

# API Gateway의 WebSocket API 검증 요청
<a name="websocket-api-request-validation"></a>

통합 요청을 진행하기 전에 라우팅 요청의 확인을 수행하도록 API Gateway를 구성할 수 있습니다. 유효성 검사가 실패하면 API Gateway는 백엔드를 호출하지 않고 요청을 실패 처리하고, 클라이언트에 “잘못된 요청 본문” 게이트웨이 응답을 전송한 다음 CloudWatch Logs에 유효성 검사 결과를 게시합니다. 이런 식으로 유효성 검사를 이용하면 API 백엔드에 대한 불필요한 호출을 줄일 수 있습니다.

## 모델 선택 표현식
<a name="apigateway-websocket-api-model-selection-expressions"></a>

모델 선택 표현식을 사용하여 동일한 라우팅 내에서 요청을 동적으로 유효성 검사할 수 있습니다. 프록시 또는 비프록시 통합에 대한 모델 선택 표현식을 제공하는 경우 모델 유효성 검사가 수행됩니다. 일치하는 모델이 없으면 `$default` 모델을 폴백으로 정의해야 할 수도 있습니다. 일치하는 모델이 없고 `$default`가 정의되지 않으면 유효성 검사가 실패합니다. 선택 표현식은 `Route.ModelSelectionExpression`과 같고, `Route.RequestModels`의 키를 평가합니다.

WebSocket API에 대해 라우팅을 정의할 때 선택적으로 *모델 선택 표현식*을 지정할 수 있습니다. 이 표현식은 요청이 수신될 때 본문 확인에 사용될 모델을 선택하기 위해 평가됩니다. 표현식은 라우팅의 [https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-routes.html#apis-apiid-routes-prop-route-requestmodels](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-routes.html#apis-apiid-routes-prop-route-requestmodels)에서 항목 중 하나를 평가합니다.

모델은 [JSON 스키마](https://datatracker.ietf.org/doc/html/draft-zyp-json-schema-04)로 표시되고 요청 본문의 데이터 구조를 설명합니다. 이 선택 표현식의 속성상, 실행 시간에 특정 라우팅을 기준으로 유효성 검사를 수행할 모델을 동적으로 선택할 수 있습니다. 모델 생성에 대한 자세한 내용은 [REST API에 대한 데이터 모델](models-mappings-models.md) 단원을 참조하십시오.

## API Gateway 콘솔을 사용하여 요청 확인 설정
<a name="apigateway-websocket-api-model-selection-expression-example"></a>

다음 예시에서는 라우팅에서 요청 검증을 설정하는 방법을 보여줍니다.

 먼저 모델을 생성한 다음 라우팅을 생성합니다. 다음으로 방금 생성한 경로에 요청 검증을 구성합니다. 마지막으로, API를 배포 및 테스트합니다. 이 자습서를 완료하려면 경로 선택 표현식으로 `$request.body.action`을 사용하는 WebSocket API와 새 경로에 대한 통합 엔드포인트가 필요합니다.

또한 API에 연결하기 위해 `wscat`가 필요합니다. 자세한 내용은 [`wscat`를 사용하여 WebSocket API에 연결하고 메시지 보내기](apigateway-how-to-call-websocket-api-wscat.md) 섹션을 참조하세요.

**모델을 생성하는 방법**

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

1. WebSocket API를 선택합니다.

1. 기본 탐색 창에서 **모델**을 선택합니다.

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

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

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

1. **모델 스키마**에서 다음 모델을 입력합니다.

   ```
   {
       "$schema": "http://json-schema.org/draft-04/schema#",
       "type" : "object",
       "required" : [ "address"],
       "properties" : {
           "address": {
               "type": "string"
           }
       }
   }
   ```

   이 모델에서는 요청에 이메일 주소가 포함되어야 합니다.

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

이 단계에서는 WebSocket API에 대한 라우팅을 생성합니다.

**경로 생성**

1. 기본 탐색 창에서 **경로**를 선택합니다.

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

1. **경로 키(Route key)**에 **sendMessage**를 입력합니다.

1. 통합 유형을 선택하고 통합 엔드포인트를 지정합니다. 자세한 내용은 [API Gateway의 WebSocket API 통합](apigateway-websocket-api-integrations.md)을 참조하세요.

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

이 단계에서는 `sendMessage` 경로에 대한 요청 검증을 설정합니다.

**요청 검증을 설정하려면**

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

1. **모델 선택 표현식**에는 **\$1\$1request.body.messageType\$1**을 입력합니다.

   API Gateway는 `messageType` 속성을 사용하여 수신 요청을 검증합니다.

1. **요청 모델 추가**를 선택합니다.

1. **모델 키**에 **email**을 입력합니다.

1. **모델**에서는 **이메일** 모델을 선택합니다.

   API 게이트웨이는 이 모델에 대해 `messageType` 속성이 `email`로 설정된 수신 메시지의 유효성을 검사합니다.
**참고**  
API Gateway가 모델 선택 표현식을 모델 키와 일치시킬 수 없는 경우 `$default` 모델을 선택합니다. `$default` 모델이 없으면 유효성 검사가 실패합니다. 프로덕션 API의 경우 `$default` 모델을 생성하는 것이 좋습니다.

1. **변경 사항 저장**을 선택합니다.

이 단계에서는 API를 배포 및 테스트합니다.

**API 배포 및 테스트하기**

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

1. 드롭다운 목록에서 원하는 스테이지를 선택하거나 새 스테이지의 이름을 입력하십시오.

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

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

1. API의 WebSocket URL을 복사합니다. URL은 `wss://abcdef123.execute-api.us-east-2.amazonaws.com/production`와 같아야 합니다.

1. 새 터미널을 열고 다음 파라미터를 사용하여 **wscat** 명령을 실행합니다.

   ```
   wscat -c wss://abcdef123.execute-api.us-west-2.amazonaws.com/production
   ```

   ```
   Connected (press CTRL+C to quit)
   ```

1. 다음 명령을 사용하여 API를 테스트합니다.

   ```
   {"action": "sendMessage", "messageType": "email"}
   ```

   ```
   {"message": "Invalid request body", "connectionId":"ABCD1=234", "requestId":"EFGH="}
   ```

   API Gateway는 해당 요청을 실패시킵니다.

   다음 명령어를 사용하여 API에 유효한 요청을 보냅니다.

   ```
   {"action": "sendMessage", "messageType": "email", "address": "mary_major@example.com"}
   ```

# API Gateway에서 WebSocket API의 데이터 변환
<a name="websocket-api-data-transformations"></a>

API Gateway에서 WebSocket API 메서드 요청은 백엔드의 요구에 따라 해당하는 통합 요청 페이로드에서 여러 유형의 페이로드를 취할 수 있습니다. 마찬가지로 백엔드에서는 프런트 엔드에서 기대하는 메서드 응답 페이로드가 아니라 통합 응답 페이로드를 반환할 수 있습니다.

API Gateway에서는 매핑 템플릿 변환을 사용하여 메서드 요청에서 해당 통합 요청으로, 통합 응답에서 해당 메서드 응답으로 페이로드를 매핑할 수 있습니다. 매핑 템플릿을 만들고 템플릿 선택 표현식을 지정하여 필요한 데이터 변환을 수행하는 데 사용할 템플릿을 결정합니다.

데이터 매핑을 사용하면 [라우팅 요청](api-gateway-basic-concept.md#apigateway-definition-route-request)의 데이터를 백엔드 통합에 매핑할 수 있습니다. 자세한 내용은 [API Gateway에서 WebSocket API에 대한 데이터 매핑 설정](websocket-api-data-mapping.md) 단원을 참조하십시오.

## 매핑 템플릿 및 모델
<a name="apigateway-websocket-api-mapping-templats-and-models"></a>

 *매핑 템플릿*이란 [VTL(Velocity Template Language)](https://velocity.apache.org/engine/devel/vtl-reference.html)로 표현된 스크립트로, [JSONPath 표현식](https://goessner.net/articles/JsonPath/)을 사용하여 페이로드에 적용됩니다. API Gateway 매핑 템플릿에 대한 자세한 내용은 [API Gateway에서 REST API의 데이터 변환 매핑](models-mappings.md) 단원을 참조하세요.

페이로드는 [JSON 스키마 draft 4](https://datatracker.ietf.org/doc/html/draft-zyp-json-schema-04)에 따라 *데이터 모델*을 가질 수 있습니다. 매핑 템플릿을 생성하기 위해 모델을 정의할 필요는 없습니다. 그러나 API Gateway에서는 제공된 모델에 따라 템플릿 블루프린트를 생성하기 때문에 모델이 있으면 템플릿을 생성하는 데 도움이 됩니다. API Gateway 모델에 대한 자세한 내용은 [REST API에 대한 데이터 모델](models-mappings-models.md) 단원을 참조하세요.

## 템플릿 선택 표현식
<a name="apigateway-websocket-api-template-selection-expressions"></a>

매핑 템플릿을 사용하여 페이로드를 변환하려면 [통합 요청](apigateway-websocket-api-integration-requests.md) 또는 [통합 응답](apigateway-websocket-api-integration-responses.md)에서 WebSocket API 템플릿 선택 표현식을 지정합니다. 이 표현식은 요청 본문을 (입력 템플릿을 통해) 요청 본문으로 변환하거나 통합 응답 본문을 (출력 템플릿을 통해) 라우팅 응답 본문으로 변환하는 데 사용할 입력 또는 출력 템플릿(있는 경우)를 판별하기 위해 평가됩니다.

`Integration.TemplateSelectionExpression`은 `${request.body.jsonPath}`와 정적 값을 지원합니다.

`IntegrationResponse.TemplateSelectionExpression`은 `${request.body.jsonPath}`, `${integration.response.statuscode}`, `${integration.response.header.headerName}`, `${integration.response.multivalueheader.headerName}` 및 정적 값을 지원합니다.

## 통합 응답 선택 표현식
<a name="apigateway-websocket-api-integration-response-selection-expressions"></a>

WebSocket API에 대해 [통합 응답을 설정](apigateway-websocket-api-integration-responses.md)할 때 선택적으로 통합 응답 선택 표현식을 지정할 수 있습니다. 이 표현식은 통합이 반환될 때 어떤 `[https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations-integrationid-integrationresponses-integrationresponseid.html](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations-integrationid-integrationresponses-integrationresponseid.html)`가 선택되어야 하는지 결정합니다. 이 표현식의 값은 현재 아래에 정의된 대로 API 게이트웨이에 의해 제한됩니다. 이 표현식은 *비 프록시 통합*에만 해당한다는 점에 유의하십시오. 프록시 통합은 모델링이나 수정 없이 단순히 응답 페이로드를 호출자에게 다시 전달하기만 합니다.

이전의 다른 선택 표현식과 달리 이 표현식은 현재 *패턴 일치* 형식을 지원합니다. 표현식은 슬래시로 래핑해야 합니다.

현재 이 값은 `[https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations-integrationid.html#apis-apiid-integrations-integrationid-prop-integration-integrationtype](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations-integrationid.html#apis-apiid-integrations-integrationid-prop-integration-integrationtype)`에 따라 고정됩니다.
+ Lambda 기반 통합의 경우 `$integration.response.body.errorMessage`입니다.
+ `HTTP` 및 `MOCK` 통합의 경우 `$integration.response.statuscode`입니다.
+ `HTTP_PROXY` 및 `AWS_PROXY`의 경우 페이로드가 호출자에게 패스스루 되도록 요청하기 때문에 표현식이 사용되지 않습니다.

# API Gateway에서 WebSocket API에 대한 데이터 매핑 설정
<a name="websocket-api-data-mapping"></a>

*데이터 매핑*을 사용하면 [라우팅 요청](api-gateway-basic-concept.md#apigateway-definition-route-request)의 데이터를 백엔드 통합에 매핑할 수 있습니다.

**참고**  
웹 소켓 API에 대한 데이터 매핑은 에서 지원되지 않습니다AWS Management Console 데이터 매핑을 구성하려면 AWS CLI, AWS CloudFormation 또는 SDK를 사용해야 합니다.

**Topics**
+ [통합 요청 파라미터에 라우팅 요청 데이터 매핑](#websocket-mapping-request-parameters)
+ [예시](#websocket-data-mapping-examples)

## 통합 요청 파라미터에 라우팅 요청 데이터 매핑
<a name="websocket-mapping-request-parameters"></a>

통합 요청 파라미터는 정의된 라우팅 요청 파라미터, 요청 본문, [`context` 또는 ](api-gateway-mapping-template-reference.md#context-variable-reference) [`stage`](api-gateway-mapping-template-reference.md#stagevariables-template-reference) 변수 및 정적 값에서 매핑될 수 있습니다.

다음 표에는 통합 요청 데이터 매핑 표현식이 나와 있습니다. 이 표에서 *`PARAM_NAME`*은 지정된 파라미터 유형의 라우팅 요청 파라미터 이름입니다. 정규식 `'^[a-zA-Z0-9._$-]+$]'`와 일치해야 합니다. *JSONPath\$1EXPRESSION*은 요청 본문의 JSON 필드에 대한 JSONPath 표현식입니다.


| 매핑된 데이터 소스 | 매핑 표현식 | 
| --- | --- | 
| 요청 쿼리 문자열(\$1connect 라우팅의 경우에만 지원) | route.request.querystring.PARAM\$1NAME | 
| 요청 헤더(\$1connect 라우팅의 경우에만 지원) | route.request.header.PARAM\$1NAME | 
| 다중 값 요청 쿼리 문자열(\$1connect 라우팅의 경우에만 지원) | route.request.multivaluequerystring.PARAM\$1NAME | 
| 다중 값 요청 헤더(\$1connect 라우팅의 경우에만 지원) | route.request.multivalueheader.PARAM\$1NAME | 
| 요청 본문 | route.request.body.JSONPath\$1EXPRESSION | 
| 단계 변수 | stageVariables.VARIABLE\$1NAME | 
| 컨텍스트 변수 | context.VARIABLE\$1NAME은 [지원되는 컨텍스트 변수](api-gateway-mapping-template-reference.md#context-variable-reference) 중 하나여야 합니다. | 
| 정적 값 | 'STATIC\$1VALUE'. STATIC\$1VALUE는 문자열 리터럴이며 작은따옴표로 묶여야 합니다. | 

AWS CLI로 데이터 매핑을 생성할 때 AWS CLI에서 문자열 리터럴을 사용하는 올바른 형식을 따라야 합니다. 자세한 내용은 *AWS Command Line Interface 사용 설명서*의 [AWS CLI에서 문자열에 따옴표 및 리터럴 사용](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-quoting-strings.html)을 참조하세요.

## 예시
<a name="websocket-data-mapping-examples"></a>

다음 AWS CLI 예제에서는 데이터 매핑을 구성합니다. CloudFormation 템플릿 예시를 보려면 [samples/websocket-data-mapping.zip](samples/websocket-data-mapping.zip) 단원을 참조하세요.

### 통합 요청의 헤더에 클라이언트의 connectionId 매핑
<a name="websocket-data-mapping-examples.connectionId"></a>

다음 [update-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-integration.html) 명령은 백엔드 통합에 대한 요청의 `connectionId` 헤더에 클라이언트의 `connectionId`를 매핑합니다.

```
aws apigatewayv2 update-integration \
    --integration-id abc123 \
    --api-id a1b2c3d4 \ 
    --request-parameters 'integration.request.header.connectionId'='context.connectionId'
```

### 통합 요청의 헤더에 쿼리 문자열 파라미터 매핑
<a name="websocket-data-mapping-examples.querystring"></a>

다음 예제 명령은 통합 요청의 `authToken` 헤더에 `authToken` 쿼리 문자열 파라미터를 매핑합니다.

1. 다음 [update-route](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-route.html) 명령을 사용하여 `authToken` 쿼리 문자열 파라미터를 경로의 요청 파라미터에 추가합니다.

   ```
   aws apigatewayv2 update-route --route-id 0abcdef \
       --api-id a1b2c3d4 \
       --request-parameters '{"route.request.querystring.authToken": {"Required": false}}'
   ```

1.  다음 [update-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-integration.html) 명령을 사용하여 쿼리 문자열 파라미터를 백엔드 통합 요청의 `authToken` 헤더에 매핑합니다.

   ```
   aws apigatewayv2 update-integration \
       --integration-id abc123 \
       --api-id a1b2c3d4 \
       --request-parameters 'integration.request.header.authToken'='route.request.querystring.authToken'
   ```

1. (선택 사항) 필요한 경우 다음 [delete-route-request-parameter](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/delete-route-request-parameter.html)를 사용하여 경로의 요청 파라미터에서 `authToken` 쿼리 문자열 파라미터를 삭제합니다.

   ```
   aws apigatewayv2 delete-route-request-parameter \
       --route-id 0abcdef \
       --api-id a1b2c3d4 \
       --request-parameter-key 'route.request.querystring.authToken'
   ```

# API Gateway용 WebSocket API 매핑 템플릿 참조
<a name="apigateway-websocket-api-mapping-template-reference"></a>

이 섹션에서는 현재 API Gateway에서 WebSocket API에 대해 지원되는 변수 집합을 요약합니다.


| 파라미터 | 설명 | 
| --- | --- | 
| \$1context.connectionId |  클라이언트에 대한 콜백을 만드는 데 사용할 수 있는 고유한 연결 ID입니다.  | 
| \$1context.connectedAt |  [Epoch](https://en.wikipedia.org/wiki/Unix_time) 형식 연결 시간입니다.  | 
| \$1context.domainName |  WebSocket API의 도메인 이름입니다. 하드 코딩된 값 대신 클라이언트에 콜백하는 데 사용할 수 있습니다.  | 
| \$1context.eventType |  이벤트 유형: `CONNECT`, `MESSAGE` 또는 `DISCONNECT`.  | 
| \$1context.messageId |  메시지의 고유 서버 측 ID. `$context.eventType`이 `MESSAGE`인 경우에만 사용 가능합니다.  | 
| \$1context.routeKey |  선택한 라우팅 키.  | 
| \$1context.requestId |  `$context.extendedRequestId`와 동일합니다.  | 
| \$1context.extendedRequestId | API 호출에 대해 자동으로 생성된 ID로 디버깅/문제 해결에 유용한 정보가 포함합니다. | 
| \$1context.apiId |  식별자 API Gateway가 API에 할당합니다.  | 
| \$1context.authorizer.principalId |  클라이언트가 전송한 토큰과 연결되고 API Gateway Lambda 권한 부여자(이전에는 사용자 지정 권한 부여자라고 함) Lambda 함수에서 반환한 보안 주체 사용자 식별입니다.  | 
| \$1context.authorizer.property |  API Gateway Lambda 권한 부여자 함수에서 반환된 `context` 맵의 지정된 키-값 페어의 문자열화된 값입니다. 예를 들어, 권한 부여자는 다음 `context` 맵을 반환합니다. <pre>"context" : {<br />  "key": "value",<br />  "numKey": 1,<br />  "boolKey": true<br />}</pre> `$context.authorizer.key`를 호출하면 `"value"` 문자열이 반환되고, `$context.authorizer.numKey`를 호출하면 `"1"` 문자열이 반환되고, `$context.authorizer.boolKey`를 호출하면 `"true"` 문자열이 반환됩니다.  | 
| \$1context.error.messageString | \$1context.error.message의 따옴표 붙은 값, 즉 "\$1context.error.message"입니다. | 
| \$1context.error.validationErrorString |  세부적인 검증 오류 메시지를 포함하는 문자열입니다.  | 
| \$1context.identity.accountId |  요청과 연결된 AWS 계정 ID입니다.  | 
| \$1context.identity.apiKey |  키가 활성화된 API 요청에 연결된 API 소유자 키입니다.  | 
| \$1context.identity.apiKeyId | 키가 활성화된 API 요청에 연결된 API 키 ID입니다. | 
| \$1context.identity.caller |  요청을 작성한 호출자의 보안 주체 ID입니다.  | 
| \$1context.identity.cognitoAuthenticationProvider |  요청을 작성한 직접 호출자가 사용한 모든 Amazon Cognito 인증 공급자의 쉼표로 구분된 목록입니다. Amazon Cognito 자격 증명으로 요청을 서명한 경우에만 사용할 수 있습니다. 예를 들어, Amazon Cognito 사용자 풀의 자격 증명의 경우 `cognito-idp. region.amazonaws.com/user_pool_id,cognito-idp.region.amazonaws.com/user_pool_id:CognitoSignIn:token subject claim` 사용 가능한 Amazon Cognito 인증 공급자에 대한 자세한 내용은 Amazon Cognito 개발자 안내서**의 [페더레이션 자격 증명 사용](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html)을 참조하세요. | 
| \$1context.identity.cognitoAuthenticationType |  요청을 작성한 호출자의 Amazon Cognito 인증 유형입니다. Amazon Cognito 자격 증명으로 요청을 서명한 경우에만 사용할 수 있습니다. 가능한 값에는 인증 자격 증명에 대한 `authenticated` 및 미인증 자격 증명에 대한 `unauthenticated`이(가) 포함됩니다. | 
| \$1context.identity.cognitoIdentityId |  요청을 작성한 호출자의 Amazon Cognito 자격 증명 ID입니다. Amazon Cognito 자격 증명으로 요청을 서명한 경우에만 사용할 수 있습니다.  | 
| \$1context.identity.cognitoIdentityPoolId |  요청을 작성한 호출자의 Amazon Cognito 자격 증명 풀 ID입니다. Amazon Cognito 자격 증명으로 요청을 서명한 경우에만 사용할 수 있습니다.  | 
| \$1context.identity.sourceIp |  API Gateway 엔드포인트를 요청하는 즉시 TCP 연결의 소스 IP 주소입니다.  | 
| \$1context.identity.user |  요청을 작성한 사용자의 보안 주체 ID입니다.  | 
| \$1context.identity.userAgent |  API 호출자의 사용자 에이전트입니다.  | 
| \$1context.identity.userArn |  인증 후 식별된 실제 사용자의 ARN(Amazon Resource Name)입니다.  | 
| \$1context.requestTime | [CLF](https://httpd.apache.org/docs/current/logs.html#common) 형식 요청 시간(dd/MMM/yyyy:HH:mm:ss \$1-hhmm)입니다. | 
| \$1context.requestTimeEpoch | [Epoch](https://en.wikipedia.org/wiki/Unix_time) 형식 요청 시간(밀리초)입니다. | 
| \$1context.stage |  API 호출의 개발 단계입니다(예: 베타 또는 프로덕션).  | 
| \$1context.status |  응답 상태입니다.  | 
| \$1input.body | 원시 페이로드를 문자열로 반환합니다. | 
| \$1input.json(x) | 이 함수는 JSONPath 표현식을 평가하고 결과를 JSON 문자열로 반환합니다. 예를 들어, `$input.json('$.pets')`은 반려 동물 구조를 나타내는 JSON 문자열을 반환합니다. JSONPath에 대한 자세한 내용은 [JSONPath](https://goessner.net/articles/JsonPath/) 또는 [Java용 JSONPath](https://github.com/json-path/JsonPath)를 참조하십시오. | 
| \$1input.path(x) | JSONPath 표현식 문자열 (`x`)을 가져와서 결과의 JSON 객체로 반환합니다. 이를 통해 기본적으로 [Apache Velocity Template Language(VTL)](https://velocity.apache.org/engine/devel/vtl-reference.html)에서 페이로드 요소에 액세스하고 조작할 수 있습니다. 예를 들어, `$input.path('$.pets')` 표현식이 다음과 같은 객체를 반환할 경우: <pre>[<br />  { <br />    "id": 1, <br />    "type": "dog", <br />    "price": 249.99 <br />  }, <br />  { <br />    "id": 2, <br />    "type": "cat", <br />    "price": 124.99 <br />  }, <br />  { <br />    "id": 3, <br />    "type": "fish", <br />    "price": 0.99 <br />  } <br />]</pre> `$input.path('$.pets').count()`는 `"3"`을 반환합니다. JSONPath에 대한 자세한 내용은 [JSONPath](http://goessner.net/articles/JsonPath/) 또는 [Java용 JSONPath](https://github.com/jayway/JsonPath)를 참조하십시오. | 
| \$1stageVariables.<variable\$1name> |  *<variable\$1name>*은 단계 변수 이름을 나타냅니다.  | 
| \$1stageVariables['<variable\$1name>'] |  *<variable\$1name>*은 모든 단계 변수 이름을 나타냅니다.  | 
| \$1\$1stageVariables['<variable\$1name>']\$1 |  *<variable\$1name>*은 모든 단계 변수 이름을 나타냅니다.  | 
| \$1util.escapeJavaScript() |  JavaScript 문자열 규칙을 사용하여 문자열의 문자를 이스케이프합니다.  이 함수는 일반 작은따옴표(`'`)를 이스케이프된 작은따옴표(`\'`)로 변환합니다. 그러나 이스케이프된 작은따옴표는 JSON에서 유효하지 않습니다. 따라서 이 함수의 결과를 JSON 속성에서 사용할 경우 이스케이프된 작은따옴표(`\'`)를 다시 일반 작은따옴표(`'`)로 변환해야 합니다. 방법은 다음 예제와 같습니다:  <pre> $util.escapeJavaScript(data).replaceAll("\\'","'")</pre>   | 
| \$1util.parseJson() |   "문자열화된" JSON을 가져와서 결과의 객체 표현을 반환합니다. 이 함수의 결과를 사용하여 기본적으로 Apache VTL(Velocity Template Language)에서 페이로드 요소에 액세스하고 조작할 수 있습니다. 예를 들어 다음과 같은 페이로드가 있고  <pre>{"errorMessage":"{\"key1\":\"var1\",\"key2\":{\"arr\":[1,2,3]}}"}</pre>  다음 매핑 템플릿을 사용하는 경우  <pre>#set ($errorMessageObj = $util.parseJson($input.path('$.errorMessage')))<br />{<br />   "errorMessageObjKey2ArrVal" : $errorMessageObj.key2.arr[0]<br />}<br /></pre> 출력은 다음과 같습니다. <pre>{<br />   "errorMessageObjKey2ArrVal" : 1<br />}<br /></pre>  | 
| \$1util.urlEncode() | 문자열을 "application/x-www-form-urlencoded" 형식으로 변환합니다. | 
| \$1util.urlDecode() | "application/x-www-form-urlencoded" 문자열을 디코딩합니다. | 
| \$1util.base64Encode() | 데이터를 base64 인코딩 문자열로 인코딩합니다. | 
| \$1util.base64Decode() | 데이터를 base64 인코딩 문자열에서 디코딩합니다. | 

# API Gateway의 WebSocket API에 대한 이진 미디어 유형
<a name="websocket-api-develop-binary-media-types"></a>

API Gateway WebSocket API는 현재 수신 메시지 페이로드에 이진 프레임을 지원하지 않습니다. 클라이언트 앱에서 이진 프레임을 보내면 API Gateway가 거부하고 코드 1003과 함께 클라이언트와의 연결을 끊습니다.

이 동작의 차선책이 있습니다. 클라이언트가 텍스트 인코딩된 이진 데이터(예: Base64)를 텍스트 프레임으로 보내는 경우, 통합의 `contentHandlingStrategy` 속성을 `CONVERT_TO_BINARY`로 설정하여 페이로드를 Base64 인코딩 문자열에서 이진으로 변환할 수 있습니다.

비 프록시 통합에서 이진 페이로드에 대한 라우팅 응답을 반환하기 위해 통합 응답의 `contentHandlingStrategy` 속성을 `CONVERT_TO_TEXT`로 설정하여 페이로드를 이진에서 Base64 인코딩 문자열로 변환할 수 있습니다.

# WebSocket API 간접 호출
<a name="apigateway-how-to-call-websocket-api"></a>

WebSocket API를 배포하고 나면 클라이언트 애플리케이션이 WebSocket API에 연결하여 메시지를 보낼 수 있으며, 백엔드는 연결된 클라이언트 애플리케이션에 메시지를 보낼 수 있습니다.
+ `wscat`를 사용하여 WebSocket API에 연결하고 메시지를 보내 클라이언트 동작을 시뮬레이션할 수 있습니다. [`wscat`를 사용하여 WebSocket API에 연결하고 메시지 보내기](apigateway-how-to-call-websocket-api-wscat.md)을(를) 참조하세요.
+ 백엔드 서비스의 @connections API를 사용하여 연결된 클라이언트에 콜백 메시지를 보내거나 연결 정보를 얻거나 클라이언트 연결을 끊을 수 있습니다. [백엔드 서비스에서 `@connections` 명령 사용](apigateway-how-to-call-websocket-api-connections.md)을(를) 참조하세요.
+ 클라이언트 애플리케이션은 자체 WebSocket 라이브러리를 사용하여 WebSocket API를 호출할 수 있습니다.

# `wscat`를 사용하여 WebSocket API에 연결하고 메시지 보내기
<a name="apigateway-how-to-call-websocket-api-wscat"></a>

`[wscat](https://www.npmjs.com/package/wscat)` 유틸리티는 API Gateway에서 만들고 배포한 WebSocket API를 테스트할 수 있는 편리한 도구입니다. 다음과 같이 `wscat`를 설치하여 사용할 수 있습니다.

1. [https://www.npmjs.com/package/wscat](https://www.npmjs.com/package/wscat)에서 `wscat`를 다운로드합니다.

1. 다음 명령을 실행하여 `wscat`을 설치합니다.

   ```
   npm install -g wscat
   ```

1. API에 연결하려면 다음 예와 같이 `wscat` 명령을 실행하십시오. 이 예제에서는 `Authorization` 설정이 `NONE`이라고 가정합니다.

   ```
   wscat -c wss://aabbccddee.execute-api.us-east-1.amazonaws.com/test/
   ```

   `aabbccddee`를 실제 API ID, 즉 API Gateway 콘솔에 표시되거나 AWS CLI [https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html) 명령에서 반환하는 ID로 바꿔야 합니다.

   또한 API가 `us-east-1` 이외의 리전에 있는 경우, 올바른 리전으로 대체해야 합니다.

1. API를 테스트하려면 연결된 상태에서 다음과 같은 메시지를 입력하십시오.

   ```
   {"{jsonpath-expression}":"{route-key}"}
   ```

   여기에서 *\$1jsonpath-expression\$1*은 JSONPath 표현식이고 *\$1route-key\$1*는 API에 대한 라우팅 키입니다. 예:

   ```
   {"action":"action1"}
   {"message":"test response body"}
   ```

   JSONPath에 대한 자세한 내용은 [JSONPath](https://goessner.net/articles/JsonPath/) 또는 [Java용 JSONPath](https://github.com/json-path/JsonPath)를 참조하십시오.

1. API 연결을 해제하려면 `ctrl-C`를 입력합니다.

# 백엔드 서비스에서 `@connections` 명령 사용
<a name="apigateway-how-to-call-websocket-api-connections"></a>

백엔드 서비스는 다음 WebSocket 연결 HTTP 요청을 사용하여 연결된 클라이언트에 콜백 메시지를 보내거나 연결 정보를 얻거나 클라이언트 연결을 끊을 수 있습니다.

**중요**  
이러한 요청은 [IAM 권한 부여](apigateway-websocket-control-access-iam.md)를 사용하므로 [서명 버전 4(SigV4)](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html)로 서명해야 합니다. 이를 수행하기 위해 API Gateway 관리 API를 사용할 수 있습니다. 자세한 내용은 [ApiGatewayManagementApi](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigatewaymanagementapi.html)를 참조하십시오.

다음 명령에서 `{api-id}`를 실제 API ID, 즉 API Gateway 콘솔에 표시되거나 AWS CLI [create-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html) 명령에서 반환하는 ID로 바꿔야 합니다. 이 명령을 사용하기 전에 연결을 설정해야 합니다.

클라이언트에게 콜백 메시지를 전송하려면 다음을 사용합니다.

```
POST https://{api-id}.execute-api.us-east-1.amazonaws.com/{stage}/@connections/{connection_id}
```

`[Postman](https://www.postman.com/)`을 사용하거나 다음 예와 같이 `[awscurl](https://github.com/okigan/awscurl)`를 호출하여 이 요청을 테스트할 수 있습니다.

```
awscurl --service execute-api -X POST -d "hello world" https://{prefix}.execute-api.us-east-1.amazonaws.com/{stage}/@connections/{connection_id}
```

다음 예제와 같이 명령을 URL 인코딩해야 합니다.

```
awscurl --service execute-api -X POST -d "hello world" https://aabbccddee.execute-api.us-east-1.amazonaws.com/prod/%40connections/R0oXAdfD0kwCH6w%3D
```

클라이언트의 가장 최신 연결 상태를 얻으려면 다음을 사용합니다.

```
GET https://{api-id}.execute-api.us-east-1.amazonaws.com/{stage}/@connections/{connection_id}
```

클라이언트의 연결을 해제하려면 다음을 사용합니다.

```
DELETE https://{api-id}.execute-api.us-east-1.amazonaws.com/{stage}/@connections/{connection_id}
```

통합에 `$context` 변수를 사용하여 동적으로 콜백 URL을 구성할 수 있습니다. 예를 들어 Lambda 프록시 통합과 `Node.js` Lambda 함수를 사용하는 경우 다음과 같이 URL을 구성하고 연결된 클라이언트에 메시지를 보낼 수 있습니다.

```
import {
  ApiGatewayManagementApiClient,
  PostToConnectionCommand,
} from "@aws-sdk/client-apigatewaymanagementapi";

export const handler = async (event) => {
  const domain = event.requestContext.domainName;
  const stage = event.requestContext.stage;
  const connectionId = event.requestContext.connectionId;
  const callbackUrl = `https://${domain}/${stage}`;
  const client = new ApiGatewayManagementApiClient({ endpoint: callbackUrl });

  const requestParams = {
    ConnectionId: connectionId,
    Data: "Hello!",
  };

  const command = new PostToConnectionCommand(requestParams);

  try {
    await client.send(command);
  } catch (error) {
    console.log(error);
  }

  return {
    statusCode: 200,
  };
};
```

WebSocket API에 사용자 지정 도메인 이름을 사용하는 경우 함수 코드에서 `stage` 변수를 제거합니다.

콜백 메시지를 보낼 때는 Lambda 함수에 API Gateway Management API를 직접 호출할 권한이 있어야 합니다. 연결이 설정되기 전 또는 클라이언트 연결이 끊긴 후에 메시지를 게시하면 `GoneException`을 포함하는 오류가 발생할 수 있습니다.