

# Develop WebSocket APIs in API Gateway
Develop

This section provides details about API Gateway capabilities that you need while you're developing your API Gateway APIs.

As you're developing your API Gateway API, you decide on a number of characteristics of your API. These characteristics depend on the use case of your API. For example, you might want to only allow certain clients to call your API, or you might want it to be available to everyone. You might want an API call to execute a Lambda function, make a database query, or call an application.

**Topics**
+ [

# Create WebSocket APIs in API Gateway
](apigateway-websocket-api-create-empty-api.md)
+ [

# IP address types for WebSocket APIs in API Gateway
](websocket-api-ip-address-type.md)
+ [

# Create routes for WebSocket APIs in API Gateway
](websocket-api-develop-routes.md)
+ [

# Control and manage access to WebSocket APIs in API Gateway
](apigateway-websocket-api-control-access.md)
+ [

# Integrations for WebSocket APIs in API Gateway
](apigateway-websocket-api-integrations.md)
+ [

# Request validation for WebSocket APIs in API Gateway
](websocket-api-request-validation.md)
+ [

# Data transformations for WebSocket APIs in API Gateway
](websocket-api-data-transformations.md)
+ [

# Binary media types for WebSocket APIs in API Gateway
](websocket-api-develop-binary-media-types.md)
+ [

# Invoke WebSocket APIs
](apigateway-how-to-call-websocket-api.md)

# Create WebSocket APIs in API Gateway
Create and configure

You can create a WebSocket API in the API Gateway console, by using the AWS CLI [create-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html) command, or by using the `CreateApi` command in an AWS SDK. The following procedures show how to create a new WebSocket API.

**Note**  
WebSocket APIs only support TLS 1.2 and TLS 1.3. Earlier TLS versions are not supported.

## Create a WebSocket API using AWS CLI commands


The following [create-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html) command creates an API with the `$request.body.action` route selection expression:

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

The output looks like the following:

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

## Create a WebSocket API using the API Gateway console


You can create a WebSocket API in the console by choosing the WebSocket protocol and giving the API a name.

**Important**  
Once you have created the API, you cannot change the protocol you have chosen for it. There is no way to convert a WebSocket API into a REST API or vice versa.

**To create a WebSocket API using the API Gateway console**

1. Sign in to the API Gateway console and choose **Create API**.

1. Under **WebSocket API**, choose **Build**. Only Regional endpoints are supported.

1. For **API name**, enter the name of your API.

1. For **Route selection expression**, enter a value. For example, `$request.body.action`. 

   For more information about route selection expressions, see [Route selection expressions](websocket-api-develop-routes.md#apigateway-websocket-api-route-selection-expressions).

1. Do one of the following:
   + Choose **Create blank API** to create an API with no routes.
   + Choose **Next** to attach routes to your API.

   You can attach routes after you create your API.

# IP address types for WebSocket APIs in API Gateway


When you create an API, you specify the type of IP addresses that can invoke your API. You can choose IPv4 to resolve IPv4 addresses to invoke your API, or you can choose dualstack to allow both IPv4 and IPv6 addresses to invoke your API. We recommend that you set the IP address type to dualstack to alleviate IP space exhaustion or for your security posture. For more information about the benefits of a dualstack IP address type, see [IPv6 on AWS](https://docs.aws.amazon.com/whitepapers/latest/ipv6-on-aws/internet-protocol-version-6.html).

## Considerations for IP address types


The following considerations might impact your use of IP address types:
+ The default IP address type for all WebSocket APIs is IPv4.
+ If you change the IP address type for an existing API from IPv4 to dualstack, confirm that any policies controlling access to your APIs have been updated to account for IPv6 calls. When you change the IP address type, the change takes effect immediately.
+ Your API can be mapped to a custom domain name with a different IP address type than your API. If you disable your default API endpoint, this might affect how callers can invoke your API.

## Change the IP address type of an WebSocket API


You can change the IP address type by updating the API’s configuration. You can update the API's configuration by using the AWS Management Console, the AWS CLI, CloudFormation, or an AWS SDK. If you change the API’s IP address type, you don't redeploy your API for the changes to take effect. 

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

**To change the IP address type of a WebSocket API**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose a WebSocket API.

1. Choose **API settings**, and then choose **Edit**.

1. For IP address type, select either **IPv4** or **Dualstack**.

1. Choose **Save**.

   The change to your API's configuration will take effect immediately.

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

The following [update-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-api.html) command updates an API to have an IP address type of dualstack:

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

The output will look like the following:

```
{
    "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"
}
```

------

# Create routes for WebSocket APIs in API Gateway
Routes

In your WebSocket API, incoming JSON messages are directed to backend integrations based on routes that you configure. (Non-JSON messages are directed to a `$default` route that you configure.)

A *route* includes a *route key*, which is the value that is expected once a *route selection expression* is evaluated. The `routeSelectionExpression` is an attribute defined at the API level. It specifies a JSON property that is expected to be present in the message payload. For more information about route selection expressions, see [Route selection expressions](#apigateway-websocket-api-route-selection-expressions).

For example, if your JSON messages contain an `action` property and you want to perform different actions based on this property, your route selection expression might be `${request.body.action}`. Your routing table would specify which action to perform by matching the value of the `action` property against the custom route key values that you have defined in the table.

There are three predefined routes that can be used: `$connect`, `$disconnect`, and `$default`. In addition, you can create custom routes.
+ API Gateway calls the `$connect` route when a persistent connection between the client and a WebSocket API is being initiated.
+ API Gateway calls the `$disconnect` route when the client or the server disconnects from the API.
+ API Gateway calls a custom route after the route selection expression is evaluated against the message if a matching route is found; the match determines which integration is invoked.
+ API Gateway calls the `$default` route if the route selection expression cannot be evaluated against the message or if no matching route is found.

## Route selection expressions


A *route selection expression* is evaluated when the service is selecting the route to follow for an incoming message. The service uses the route whose `routeKey` exactly matches the evaluated value. If none match and a route with the `$default` route key exists, that route is selected. If no routes match the evaluated value and there is no `$default` route, the service returns an error. For WebSocket-based APIs, the expression should be of the form `$request.body.{path_to_body_element}`.

For example, suppose you are sending the following JSON message:

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

You might want to select your API's behavior based on the `action` property. In that case, you might define the following route selection expression:

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

In this example, `request.body` refers to your message's JSON payload, and `.action` is a [JSONPath](https://goessner.net/articles/JsonPath/) expression. You can use any JSON path expression after `request.body`, but keep in mind that the result will be stringified. For example, if your JSONPath expression returns an array of two elements, that will be presented as the string `"[item1, item2]"`. For this reason, it's a good practice to have your expression evaluate to a value and not an array or an object.

You can simply use a static value, or you can use multiple variables. The following table shows examples and their evaluated results against the preceding payload.


| Expression | Evaluated result | Description | 
| --- | --- | --- | 
| \$1request.body.action | join | An unwrapped variable | 
| \$1\$1request.body.action\$1 | join | A wrapped variable | 
| \$1\$1request.body.service\$1/\$1\$1request.body.action\$1 | chat/join | Multiple variables with static values | 
| \$1\$1request.body.action\$1-\$1\$1request.body.invalidPath\$1  | join- | If the JSONPath is not found, the variable is resolved as "". | 
| action | action | Static value | 
| \$1\$1default | \$1default | Static value | 

The evaluated result is used to find a route. If there is a route with a matching route key, the route is selected to process the message. If no matching route is found, then API Gateway tries to find the `$default` route if available. If the `$default` route is not defined, then API Gateway returns an error.

## Set up routes for a WebSocket API in API Gateway
Set up WebSocket API routes

When you first create a new WebSocket API, there are three predefined routes: `$connect`, `$disconnect`, and `$default`. You can create them by using the console, API, or AWS CLI. If desired, you can create custom routes. For more information, see [Overview of WebSocket APIs in API Gateway](apigateway-websocket-api-overview.md).

**Note**  
In the CLI, you can create routes before or after you create integrations, and you can reuse the same integration for multiple routes.

### Create a route using the API Gateway console


**To create a route using the API Gateway console**

1. Sign in to the API Gateway console, choose the API, and choose **Routes**.

1. Choose **Create route**

1. For **Route key**, enter the route key name. You can create the predefined routes (`$connect`, `$disconnect`, and `$default`), or a custom route.
**Note**  
When you create a custom route, do not use the `$` prefix in the route key name. This prefix is reserved for predefined routes.

1. Select and configure the integration type for the route. For more information, see [Set up a WebSocket API integration request using the API Gateway console](apigateway-websocket-api-integration-requests.md#apigateway-websocket-api-integration-request-using-console).

### Create a route using the AWS CLI


The following [create-route](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-route.html) command creates a route:

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

The output will look like a following:

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

### Specify route request settings for `$connect`


When you set up the `$connect` route for your API, the following optional settings are available to enable authorization for your API. For more information, see [The `$connect` route](apigateway-websocket-api-route-keys-connect-disconnect.md#apigateway-websocket-api-routes-about-connect).
+ **Authorization**: If no authorization is needed, you can specify `NONE`. Otherwise, you can specify: 
  + `AWS_IAM` to use standard AWS IAM policies to control access to your API. 
  + `CUSTOM` to implement authorization for an API by specifying a Lambda authorizer function that you have previously created. The authorizer can reside in your own AWS account or a different AWS account. For more information about Lambda authorizers, see [Use API Gateway Lambda authorizers](apigateway-use-lambda-authorizer.md).
**Note**  
In the API Gateway console, the `CUSTOM` setting is visible only after you have set up an authorizer function as described in [Configure a Lambda authorizer (console)](configure-api-gateway-lambda-authorization.md#configure-api-gateway-lambda-authorization-with-console).
**Important**  
The **Authorization** setting is applied to the entire API, not just the `$connect` route. The `$connect` route protects the other routes, because it is called on every connection.
+ **API key required**: You can optionally require an API key for an API's `$connect` route. You can use API keys together with usage plans to control and track access to your APIs. For more information, see [Usage plans and API keys for REST APIs in API Gateway](api-gateway-api-usage-plans.md).

### Set up the `$connect` route request using the API Gateway console


To set up the `$connect` route request for a WebSocket API using the API Gateway console:

1. Sign in to the API Gateway console, choose the API, and choose **Routes**.

1. Under **Routes**, choose `$connect`, or create a `$connect` route by following [Create a route using the API Gateway console](#apigateway-websocket-api-route-using-console).

1. In the **Route request settings** section, choose **Edit**.

1. For **Authorization**, select an authorization type.

1. To require an API for the `$connect` route, select **Require API key**.

1. Choose **Save changes**.

# Set up route responses for WebSocket APIs in API Gateway
Set up WebSocket API route responses

WebSocket routes can be configured for two-way or one-way communication. API Gateway will not pass the backend response through to the route response, unless you set up a route response. 

**Note**  
You can only define the `$default` route response for WebSocket APIs. You can use an integration response to manipulate the response from a backend service. For more information, see [Overview of integration responses](apigateway-websocket-api-integration-responses.md#apigateway-websocket-api-integration-response-overview). 

You can configure route responses and response selection expressions by using the API Gateway console or the AWS CLI or an AWS SDK. 

For more information about route response selection expressions, see [Route response selection expressions](apigateway-websocket-api-selection-expressions.md#apigateway-websocket-api-route-response-selection-expressions).

**Topics**
+ [

## Set up a route response using the API Gateway console
](#apigateway-websocket-api-route-response-using-console)
+ [

## Set up a route response using the AWS CLI
](#apigateway-websocket-api-route-response-using-awscli)

## Set up a route response using the API Gateway console


After you have created a WebSocket API and attached a proxy Lambda function to the default route, you can set up route response using the API Gateway console:

1. Sign in to the API Gateway console, choose a WebSocket API with a proxy Lambda function integration on the `$default` route.

1. Under **Routes**, choose the `$default` route.

1. Choose **Enable two-way communication**. 

1. Choose **Deploy API**.

1. Deploy your API to a stage.

 Use the following [ wscat](https://www.npmjs.com/package/wscat) command to connect to your API. For more information about `wscat`, see [Use `wscat` to connect to a WebSocket API and send messages to it](apigateway-how-to-call-websocket-api-wscat.md). 

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

 Press the enter button to call the default route. The body of your Lambda function should return.

## Set up a route response using the AWS CLI


The following [create-route-response](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-route-response.html) command creates a route response for the `$default` route. You can identify the API ID and route ID by using the [get-apis](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/get-apis.html) and [get-routes](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/get-routes.html) commands.

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

The output will look like the following:

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

# Set up a `$connect` route that requires a WebSocket subprotocol
Subprotocol support

Clients can use the `Sec-WebSocket-Protocol` field to request a [WebSocket subprotocol](https://datatracker.ietf.org/doc/html/rfc6455#page-12) during the connection to your WebSocket API. You can set up an integration for the `$connect` route to allow connections only if a client requests a subprotocol that your API supports.

The following example Lambda function returns the `Sec-WebSocket-Protocol` header to clients. The function establishes a connection to your API only if the client specifies the `myprotocol` subprotocol.

For an CloudFormation template that creates this example API and Lambda proxy integration, see [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;
}
```

You can use [https://www.npmjs.com/package/wscat](https://www.npmjs.com/package/wscat) to test that your API allows connections only if a client requests a subprotocol that your API supports. The following commands use the `-s` flag to specify subprotocols during the connection.

The following command attempts a connection with an unsupported subprotocol. Because the client specified the `chat1` subprotocol, the Lambda integration returns a 400 error, and the connection is unsuccessful.

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

The following command includes a supported subprotocol in the connection request. The Lambda integration allows the connection.

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

To learn more about invoking WebSocket APIs, see [Invoke WebSocket APIs](apigateway-how-to-call-websocket-api.md).

# Control and manage access to WebSocket APIs in API Gateway
Access control

API Gateway supports multiple mechanisms for controlling and managing access to your WebSocket API.

You can use the following mechanisms for authentication and authorization:
+ **Standard AWS IAM roles and policies** offer flexible and robust access controls. You can use IAM roles and policies for controlling who can create and manage your APIs, as well as who can invoke them. For more information, see [Control access to WebSocket APIs with IAM authorization](apigateway-websocket-control-access-iam.md).
+ **IAM tags** can be used together with IAM policies to control access. For more information, see [Using tags to control access to API Gateway REST API resources](apigateway-tagging-iam-policy.md).
+ **Lambda authorizers** are Lambda functions that control access to APIs. For more information, see [Control access to WebSocket APIs with AWS Lambda REQUEST authorizers](apigateway-websocket-api-lambda-auth.md).

To improve your security posture, we recommend that you configure an authorizer for the `$connect` route on all your WebSocket APIs. You might need to do this to comply with various compliance frameworks. For more information, see [Amazon API Gateway controls](https://docs.aws.amazon.com/securityhub/latest/userguide/apigateway-controls.html) in the *AWS Security Hub User Guide*.

**Topics**
+ [

# Control access to WebSocket APIs with IAM authorization
](apigateway-websocket-control-access-iam.md)
+ [

# Control access to WebSocket APIs with AWS Lambda REQUEST authorizers
](apigateway-websocket-api-lambda-auth.md)

# Control access to WebSocket APIs with IAM authorization


IAM authorization in WebSocket APIs is similar to that for [REST APIs](api-gateway-control-access-using-iam-policies-to-invoke-api.md), with the following exceptions:
+ The `execute-api` action supports `ManageConnections` in addition to existing actions (`Invoke`, `InvalidateCache`). `ManageConnections` controls access to the @connections API.
+ WebSocket routes use a different ARN format:

  ```
  arn:aws:execute-api:region:account-id:api-id/stage-name/route-key
  ```
+ The `@connections` API uses the same ARN format as REST APIs:

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

**Important**  
When you use [IAM authorization](#apigateway-websocket-control-access-iam), you must sign requests with [Signature Version 4 (SigV4)](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html).

For example, you could set up the following policy to the client. This example allows everyone to send a message (`Invoke`) for all routes except for a secret route in the `prod` stage and prevents everyone from sending a message back to connected clients (`ManageConnections`) for all stages.

------
#### [ 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/*"
            ]
        }
    ]
}
```

------

# Control access to WebSocket APIs with AWS Lambda REQUEST authorizers


A Lambda authorizer function in WebSocket APIs is similar to that for [REST APIs](apigateway-use-lambda-authorizer.md#api-gateway-lambda-authorizer-lambda-function-create), with the following exceptions:
+  You can only use a Lambda authorizer function for the `$connect` route. 
+ You cannot use path variables (`event.pathParameters`), because the path is fixed.
+ `event.methodArn` is different from its REST API equivalent, because it has no HTTP method. In the case of `$connect`, `methodArn` ends with `"$connect"`:

  ```
  arn:aws:execute-api:region:account-id:api-id/stage-name/$connect
  ```
+ The context variables in `event.requestContext` are different from those for REST APIs.

 The following example shows an input to a `REQUEST` authorizer for a WebSocket API:

```
{
    "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"
    }
}
```

The following example Lambda authorizer function is a WebSocket version of the Lambda authorizer function for REST APIs in [Additional examples of Lambda authorizer functions](apigateway-use-lambda-authorizer.md#api-gateway-lambda-authorizer-lambda-function-create):

------
#### [ 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)
```

------

To configure the preceding Lambda function as a `REQUEST` authorizer function for a WebSocket API, follow the same procedure as for [REST APIs](configure-api-gateway-lambda-authorization.md#configure-api-gateway-lambda-authorization-with-console).

To configure the `$connect` route to use this Lambda authorizer in the console, select or create the `$connect` route. In the **Route request settings** section, choose **Edit**. Select your authorizer in the **Authorization** dropdown menu, and then choose **Save changes**.

To test the authorizer, you need to create a new connection. Changing authorizer in `$connect` doesn't affect the already connected client. When you connect to your WebSocket API, you need to provide values for any configured identity sources. For example, you can connect by sending a valid query string and header using `wscat` as in the following example:

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

If you attempt to connect without a valid identity value, you'll receive a `401` response:

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

# Integrations for WebSocket APIs in API Gateway
Integrations

After setting up an API route, you must integrate it with an endpoint in the backend. A backend endpoint is also referred to as an integration endpoint and can be a Lambda function, an HTTP endpoint, or an AWS service action. The API integration has an integration request and an integration response.

In this section, you can learn how to set up integration requests and integration responses for your WebSocket API. 

**Topics**
+ [

# Set up a WebSocket API integration request in API Gateway
](apigateway-websocket-api-integration-requests.md)
+ [

# Set up a WebSocket API integration response in API Gateway
](apigateway-websocket-api-integration-responses.md)

# Set up a WebSocket API integration request in API Gateway
Integration request

Setting up an integration request involves the following:
+ Choosing a route key to integrate to the backend.
+ Specifying the backend endpoint to invoke. WebSocket APIs support the following integration types:
  + `AWS_PROXY`
  + `AWS`
  + `HTTP_PROXY`
  + `HTTP`
  + `MOCK`

  For more information about integration types, see [IntegrationType](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations-integrationid.html#apis-apiid-integrations-integrationid-prop-integration-integrationtype) in the API Gateway V2 REST API.
+ Configuring how to transform the route request data, if necessary, into integration request data by specifying one or more request templates.

## Set up a WebSocket API integration request using the API Gateway console


**To add an integration request to a route in a WebSocket API using the API Gateway console**

1. Sign in to the API Gateway console, choose the API, and choose **Routes**.

1. Under **Routes**, choose the route.

1. Choose the **Integration request** tab, and then in the **Integration request settings** section, choose **Edit**.

1. For **Integration type**, select one of the following:
   + Choose **Lambda function** only if your API will be integrated with an AWS Lambda function that you have already created in this account or in another account.

     To create a new Lambda function in AWS Lambda, to set a resource permission on the Lambda function, or to perform any other Lambda service actions, choose **AWS Service** instead.
   + Choose **HTTP** if your API will be integrated with an existing HTTP endpoint. For more information, see [HTTP integrations for REST APIs in API Gateway](setup-http-integrations.md).
   + Choose **Mock** if you want to generate API responses from API Gateway directly, without the need for an integration backend. For more information, see [Mock integrations for REST APIs in API Gateway](how-to-mock-integration.md).
   + Choose **AWS service** if your API will be integrated with an AWS service.
   + Choose **VPC link** if your API will use a `VpcLink` as a private integration endpoint. For more information, see [Set up a private integration](set-up-private-integration.md).

1. If you chose **Lambda function**, do the following:

   1. For **Use Lambda proxy integration**, choose the check box if you intend to use [Lambda proxy integration](set-up-lambda-proxy-integrations.md#api-gateway-create-api-as-simple-proxy) or [cross-account Lambda proxy integration](apigateway-cross-account-lambda-integrations.md).

   1. For **Lambda function**, specify the function in one of the following ways:
      + If your Lambda function is in the same account, enter the function name and then select the function from the dropdown list.
**Note**  
The function name can optionally include its alias or version specification, as in `HelloWorld`, `HelloWorld:1`, or `HelloWorld:alpha`.
      + If the function is in a different account, enter the ARN for the function.

   1. To use the default timeout value of 29 seconds, keep **Default timeout** turned on. To set a custom timeout, choose **Default timeout** and enter a timeout value between `50` and `29000` milliseconds.

1. If you chose **HTTP**, follow the instructions in step 4 of [Set up an API integration request using the API Gateway console](how-to-method-settings-console.md).

1. If you chose **Mock**, proceed to the **Request Templates** step.

1. If you chose **AWS service**, follow the instructions in step 6 of [Set up an API integration request using the API Gateway console](how-to-method-settings-console.md).

1. If you chose **VPC link**, do the following:

   1. For **VPC proxy integration**, choose the check box if you want your requests to be proxied to your `VPCLink`'s endpoint.

   1. For **HTTP method**, choose the HTTP method type that most closely matches the method in the HTTP backend.

   1. From the **VPC link** dropdown list, select a VPC link. You can select `[Use Stage Variables]` and enter **\$1\$1stageVariables.vpcLinkId\$1** in the text box below the list.

      You can define the `vpcLinkId` stage variable after deploying the API to a stage and set its value to the ID of the `VpcLink`.

   1. For **Endpoint URL**, enter the URL of the HTTP backend you want this integration to use.

   1. To use the default timeout value of 29 seconds, keep **Default timeout** turned on. To set a custom timeout, choose **Default timeout** and enter a timeout value between `50` and `29000` milliseconds.

1. Choose **Save changes**.

1. Under **Request templates**, do the following:

   1. To enter a **Template selection expression**, under **Request templates**, choose **Edit**.

   1. Enter a **Template selection expression**. Use an expression that API Gateway looks for in the message payload. If it is found, it is evaluated, and the result is a template key value that is used to select the data mapping template to be applied to the data in the message payload. You create the data mapping template in the next step. Choose **Edit** to save your changes.

   1. Choose **Create template** to create the data mapping template. For **Template key**, enter a template key value that is used to select the data mapping template to be applied to the data in the message payload. Then, enter a mapping template. Choose **Create template**.

      For information about template selection expressions, see [Template selection expressions](websocket-api-data-transformations.md#apigateway-websocket-api-template-selection-expressions).

## Set up an integration request using the AWS CLI


You can set up an integration request for a route in a WebSocket API by using the AWS CLI as in the following example, which creates a mock integration:

1. Create a file named `integration-params.json`, with the following contents:

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

1. Use the following [create-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-integration.html) command to create the mock integration.

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

   The output will look like the following:

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

Alternatively, you can set up an integration request for a proxy integration by using the AWS CLI.

1. Create a Lambda function in the Lambda console and give it a basic Lambda execution role.

1. Use the following [create-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-integration.html) command to create the integration.

   ```
   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
   ```

The output will look like the following:

```
{
    "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"
}
```

## Input format of a Lambda function for proxy integration for WebSocket APIs


In Lambda proxy integration, API Gateway maps the entire client request to the input `event` parameter of the backend Lambda function. The following example shows the structure of the input event from the `$connect` route and the input event from the `$disconnect` route that API Gateway sends to a Lambda proxy integration.

------
#### [ 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
  }
```

------

# Set up a WebSocket API integration response in API Gateway
Integration responses

The following section provides a brief overview of integration responses for WebSocket API and how to set up an integration response for a WebSocket API. 

**Topics**
+ [

## Overview of integration responses
](#apigateway-websocket-api-integration-response-overview)
+ [

## Integration responses for two-way communication
](#apigateway-websocket-api-integration-response-for-two-way-communication)
+ [

## Set up an integration response using the API Gateway console
](#apigateway-websocket-api-integration-response-using-console)
+ [

## Set up an integration response using the AWS CLI
](#apigateway-websocket-api-integration-response-using-awscli)

## Overview of integration responses


API Gateway's integration response is a way of modeling and manipulating the response from a backend service. There are some differences in setup of a REST API versus a WebSocket API integration response, but conceptually the behavior is the same.

WebSocket routes can be configured for two-way or one-way communication.
+ When a route is configured for two-way communication, an integration response allows you to configure transformations on the returned message payload, similar to integration responses for REST APIs.
+ If a route is configured for one-way communication, then regardless of any integration response configuration, no response will be returned over the WebSocket channel after the message is processed.

 API Gateway will not pass the backend response through to the route response, unless you set up a route response. To learn about setting up a route response, see [Set up route responses for WebSocket APIs in API Gateway](apigateway-websocket-api-route-response.md).

## Integration responses for two-way communication


Integrations can be divided into *proxy* integrations and *non-proxy* integrations.

**Important**  
For *proxy integrations*, API Gateway automatically passes the backend output to the caller as the complete payload. There is no integration response.

For *non-proxy integrations*, you must set up at least one integration response:
+ Ideally, one of your integration responses should act as a catch-all when no explicit choice can be made. This default case is represented by setting an integration response key of `$default`.
+ In all other cases, the integration response key functions as a regular expression. It should follow a format of `"/expression/"`.

For non-proxy HTTP integrations:
+ API Gateway will attempt to match the HTTP status code of the backend response. The integration response key will function as a regular expression in this case. If a match cannot be found, then `$default` is chosen as the integration response.
+ The template selection expression, as described above, functions identically. For example:
  + `/2\d\d/`: Receive and transform successful responses
  + `/4\d\d/`: Receive and transform bad request errors
  + `$default`: Receive and transform all unexpected responses

For more information about template selection expressions, see [Template selection expressions](websocket-api-data-transformations.md#apigateway-websocket-api-template-selection-expressions).

## Set up an integration response using the API Gateway console


To set up a route integration response for a WebSocket API using the API Gateway console:

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1.  Choose your WebSocket API and choose your route.

1. Choose the **Integration request** tab, and then in the **Integration response settings** section, choose **Create integration response**.

1. For **Response key**, enter a value that will be found in the response key in the outgoing message after evaluating the response selection expression. For instance, you can enter **/4\$1d\$1d/** to receive and transform bad request errors or enter **\$1default** to receive and transform all responses that match the template selection expression. 

1. For **Template selection expression**, enter a selection expression to evaluate the outgoing message.

1. Choose **Create response**.

1. You can also define a mapping template to configure transformations of your returned message payload. Choose **Create template**.

1. Enter a key name. If you are choosing the default template selection expression, enter **\$1\$1default**.

1. For **Response template**, enter your mapping template in the code editor.

1. Choose **Create template**.

1. Choose **Deploy API** to deploy your API.

 Use the following [ wscat](https://www.npmjs.com/package/wscat) command to connect to your API. For more information about `wscat`, see [Use `wscat` to connect to a WebSocket API and send messages to it](apigateway-how-to-call-websocket-api-wscat.md). 

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

 When you call your route, the returned message payload should return. 

## Set up an integration response using the AWS CLI


The following [create-integration-response](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-integration-response.html) command creates a `$default` integration response:

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

# Request validation for WebSocket APIs in API Gateway
Request validation

You can configure API Gateway to perform validation on a route request before proceeding with the integration request. If the validation fails, API Gateway fails the request without calling your backend, sends a "Bad request body" gateway response to the client, and publishes the validation results in CloudWatch Logs. Using validation this way reduces unnecessary calls to your API backend.

## Model selection expressions


You can use a model selection expression to dynamically validate requests within the same route. Model validation occurs if you provide a model selection expression for either proxy or non-proxy integrations. You might need to define the `$default` model as a fallback when no matching model is found. If there is no matching model and `$default` isn't defined, the validation fails. The selection expression looks like `Route.ModelSelectionExpression` and evaluates to the key for `Route.RequestModels`.

When you define a route for a WebSocket API, you can optionally specify a *model selection expression*. This expression is evaluated to select the model to be used for body validation when a request is received. The expression evaluates to one of the entries in a route's [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).

A model is expressed as a [JSON schema](https://datatracker.ietf.org/doc/html/draft-zyp-json-schema-04) and describes the data structure of the request body. The nature of this selection expression enables you to dynamically choose the model to validate against at runtime for a particular route. For information about how to create a model, see [Data models for REST APIs](models-mappings-models.md). 

## Set up request validation using the API Gateway console


The following example shows you how to set up request validation on a route.

 First, you create a model, and then you create a route. Next, you configure request validation on the route you just created. Lastly, you deploy and test your API. To complete this tutorial, you need a WebSocket API with `$request.body.action` as the route selection expression and an integration endpoint for your new route.

You also need `wscat` to connect to your API. For more information, see [Use `wscat` to connect to a WebSocket API and send messages to it](apigateway-how-to-call-websocket-api-wscat.md).

**To create a model**

1. Sign in to the API Gateway console at [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway).

1. Choose a WebSocket API.

1. In the main navigation pane, choose **Models**.

1. Choose **Create model**.

1. For **Name**, enter **emailModel**.

1. For **Content type**, enter **application/json**.

1. For **Model schema**, enter the following model:

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

   This model requires that the request contains an email address.

1. Choose **Save**.

In this step, you create a route for your WebSocket API.

**To create a route**

1. In the main navigation pane, choose **Routes**.

1. Choose **Create route**.

1. For **Route key**, enter **sendMessage**.

1. Choose an integration type and specify an integration endpoint. For more information see [Integrations for WebSocket APIs in API Gateway](apigateway-websocket-api-integrations.md).

1. Choose **Create route**.

In this step, you set up request validation for the `sendMessage` route.

**To set up request validation**

1. On the **Route request** tab, under **Route request settings**, choose **Edit**.

1. For **Model selection expression**, enter **\$1\$1request.body.messageType\$1**.

   API Gateway uses the `messageType` property to validate the incoming request.

1. Choose **Add request model**.

1. For **Model key**, enter **email**.

1. For **Model**, choose **emailModel**.

   API Gateway validates incoming messages with the `messageType` property set to `email` against this model.
**Note**  
If API Gateway can't match the model selection expression to a model key, then it selects the `$default` model. If there is no `$default` model, then the validation fails. For production APIs, we recommend that you create a `$default` model.

1. Choose **Save changes**.

In this step, you deploy and test your API.

**To deploy and test your API**

1. Choose **Deploy API**.

1. Choose the desired stage from the dropdown list or enter the name of a new stage.

1. Choose **Deploy**.

1. In the main navigation pane, choose **Stages**.

1. Copy your API's WebSocket URL. The URL should look like `wss://abcdef123.execute-api.us-east-2.amazonaws.com/production`.

1. Open a new terminal and run the **wscat** command with the following parameters.

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

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

1. Use the following command to test your API.

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

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

   API Gateway will fail the request.

   Use the next command to send a valid request to your API.

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

# Data transformations for WebSocket APIs in API Gateway
Data transformations

In API Gateway, a WebSocket API's method request can take a payload in a different format from the corresponding integration request payload, as required in the backend. Similarly, the backend may return an integration response payload different from the method response payload, as expected by the frontend. 

API Gateway lets you use mapping template transformations to map the payload from a method request to the corresponding integration request and from an integration response to the corresponding method response. You create a mapping template and You specify a template selection expression to determine which template to use to perform the necessary data transformations.

You can use data mappings to map data from a [route request](api-gateway-basic-concept.md#apigateway-definition-route-request) to a backend integration. To learn more, see [Set up data mapping for WebSocket APIs in API Gateway](websocket-api-data-mapping.md).

## Mapping templates and models


 A *mapping template* is a script expressed in [Velocity Template Language (VTL)](https://velocity.apache.org/engine/devel/vtl-reference.html) and applied to the payload using [JSONPath expressions](https://goessner.net/articles/JsonPath/). For more information about API Gateway mapping templates, see [Mapping template transformations for REST APIs in API Gateway](models-mappings.md).

The payload can have a *data model* according to the [JSON schema draft 4](https://datatracker.ietf.org/doc/html/draft-zyp-json-schema-04). You do not have to define a model to create a mapping template. However, a model can help you create a template because API Gateway generates a template blueprint based on a provided model. For more information about API Gateway models, see [Data models for REST APIs](models-mappings-models.md).

## Template selection expressions


To transform a payload with a mapping template, you specify a WebSocket API template selection expression in an [integration request](apigateway-websocket-api-integration-requests.md) or [integration response](apigateway-websocket-api-integration-responses.md). This expression is evaluated to determine the input or output template (if any) to use to transform either the request body into the integration request body (via an input template) or the integration response body to the route response body (via an output template).

`Integration.TemplateSelectionExpression` supports `${request.body.jsonPath}` and static values.

`IntegrationResponse.TemplateSelectionExpression` supports `${request.body.jsonPath}`, `${integration.response.statuscode}`, `${integration.response.header.headerName}`, `${integration.response.multivalueheader.headerName}`, and static values.

## Integration response selection expressions


When you [set up an integration response](apigateway-websocket-api-integration-responses.md) for a WebSocket API, you can optionally specify an integration response selection expression. This expression determines what `[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)` should be selected when an integration returns. The value of this expression is currently restricted by API Gateway, as defined below. Realize that this expression is only relevant for *non-proxy integrations*; a proxy integration simply passes the response payload back to the caller without modeling or modification.

Unlike the other preceding selection expressions, this expression currently supports a *pattern-matching* format. The expression should be wrapped with forward slashes.

Currently the value is fixed depending on the `[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)`:
+ For Lambda-based integrations, it is `$integration.response.body.errorMessage`.
+ For `HTTP` and `MOCK` integrations, it is `$integration.response.statuscode`.
+ For `HTTP_PROXY` and `AWS_PROXY`, the expression isn't utilized because you're requesting that the payload pass through to the caller.

# Set up data mapping for WebSocket APIs in API Gateway
Data mapping

*Data mapping* enables you to map data from a [route request](api-gateway-basic-concept.md#apigateway-definition-route-request) to a backend integration.

**Note**  
Data mapping for WebSocket APIs isn't supported in the AWS Management Console. You must use the AWS CLI, AWS CloudFormation, or an SDK to configure data mapping.

**Topics**
+ [

## Map route request data to integration request parameters
](#websocket-mapping-request-parameters)
+ [

## Examples
](#websocket-data-mapping-examples)

## Map route request data to integration request parameters


Integration request parameters can be mapped from any defined route request parameters, the request body, [`context` or ](api-gateway-mapping-template-reference.md#context-variable-reference) [`stage`](api-gateway-mapping-template-reference.md#stagevariables-template-reference) variables, and static values.

The following table shows integration request data mapping expressions. In the table, *`PARAM_NAME`* is the name of a route request parameter of the given parameter type. It must match the regular expression `'^[a-zA-Z0-9._$-]+$]'`. *JSONPath\$1EXPRESSION* is a JSONPath expression for a JSON field of the request body.


| Mapped data source | Mapping expression | 
| --- | --- | 
| Request query string (supported only for the \$1connect route) | route.request.querystring.PARAM\$1NAME | 
| Request header (supported only for the \$1connect route) | route.request.header.PARAM\$1NAME | 
| Multi-value request query string (supported only for the \$1connect route) | route.request.multivaluequerystring.PARAM\$1NAME | 
| Multi-value request header (supported only for the \$1connect route) | route.request.multivalueheader.PARAM\$1NAME | 
| Request body | route.request.body.JSONPath\$1EXPRESSION | 
| Stage variables | stageVariables.VARIABLE\$1NAME | 
| Context variables | context.VARIABLE\$1NAME that must be one of the [supported context variables](api-gateway-mapping-template-reference.md#context-variable-reference). | 
| Static value | 'STATIC\$1VALUE'. The STATIC\$1VALUE is a string literal and must be enclosed in single quotes. | 

When you create a data mapping, using the AWS CLI make sure to follow the correct format for using literals with strings in the AWS CLI. For more information, see [Using quotation marks and literals with strings in the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-quoting-strings.html) in the *AWS Command Line Interface User Guide*.

## Examples


The following AWS CLI examples configure data mappings. For an example CloudFormation template, see [samples/websocket-data-mapping.zip](samples/websocket-data-mapping.zip).

### Map a client's connectionId to a header in an integration request


The following [update-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-integration.html) command maps a client's `connectionId` to a `connectionId` header in the request to a backend integration:

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

### Map a query string parameter to a header in an integration request


The following example maps an `authToken` query string parameter to an `authToken` header in the integration request.

1. Use the following [update-route](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-route.html) command to add the `authToken` query string parameter to the route's request parameters.

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

1.  Use the following [update-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-integration.html) command to map the query string parameter to the `authToken` header in the request to the backend integration.

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

1. (Optional) If necessary, use the following [delete-route-request-parameter](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/delete-route-request-parameter.html) to delete the `authToken` query string parameter from the route's request parameters.

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

# WebSocket API mapping template reference for API Gateway
WebSocket mapping template reference

This section summarizes the set of variables that are currently supported for WebSocket APIs in API Gateway.


| Parameter | Description | 
| --- | --- | 
| \$1context.connectionId |  A unique ID for the connection that can be used to make a callback to the client.  | 
| \$1context.connectedAt |  The [Epoch](https://en.wikipedia.org/wiki/Unix_time)-formatted connection time.  | 
| \$1context.domainName |  A domain name for the WebSocket API. This can be used to make a callback to the client (instead of a hard-coded value).  | 
| \$1context.eventType |  The event type: `CONNECT`, `MESSAGE`, or `DISCONNECT`.  | 
| \$1context.messageId |  A unique server-side ID for a message. Available only when the `$context.eventType` is `MESSAGE`.  | 
| \$1context.routeKey |  The selected route key.  | 
| \$1context.requestId |  Same as `$context.extendedRequestId`.  | 
| \$1context.extendedRequestId | An automatically generated ID for the API call, which contains more useful information for debugging/troubleshooting. | 
| \$1context.apiId |  The identifier API Gateway assigns to your API.  | 
| \$1context.authorizer.principalId |  The principal user identification associated with the token sent by the client and returned from an API Gateway Lambda authorizer (formerly known as a custom authorizer) Lambda function.  | 
| \$1context.authorizer.property |  The stringified value of the specified key-value pair of the `context` map returned from an API Gateway Lambda authorizer function. For example, if the authorizer returns the following `context` map:  <pre>"context" : {<br />  "key": "value",<br />  "numKey": 1,<br />  "boolKey": true<br />}</pre> calling `$context.authorizer.key` returns the `"value"` string, calling `$context.authorizer.numKey` returns the `"1"` string, and calling `$context.authorizer.boolKey` returns the `"true"` string.  | 
| \$1context.error.messageString | The quoted value of \$1context.error.message, namely "\$1context.error.message". | 
| \$1context.error.validationErrorString |  A string containing a detailed validation error message.  | 
| \$1context.identity.accountId |  The AWS account ID associated with the request.  | 
| \$1context.identity.apiKey |  The API owner key associated with key-enabled API request.  | 
| \$1context.identity.apiKeyId | The API key ID associated with the key-enabled API request | 
| \$1context.identity.caller |  The principal identifier of the caller making the request.  | 
| \$1context.identity.cognitoAuthenticationProvider |  A comma-separated list of all the Amazon Cognito authentication providers used by the caller making the request. Available only if the request was signed with Amazon Cognito credentials.  For example, for an identity from an Amazon Cognito user pool, `cognito-idp. region.amazonaws.com/user_pool_id,cognito-idp.region.amazonaws.com/user_pool_id:CognitoSignIn:token subject claim` For information about the available Amazon Cognito authentication providers, see [Using Federated Identities](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html) in the *Amazon Cognito Developer Guide*. | 
| \$1context.identity.cognitoAuthenticationType |  The Amazon Cognito authentication type of the caller making the request. Available only if the request was signed with Amazon Cognito credentials. Possible values include `authenticated` for authenticated identities and `unauthenticated` for unauthenticated identities. | 
| \$1context.identity.cognitoIdentityId |  The Amazon Cognito identity ID of the caller making the request. Available only if the request was signed with Amazon Cognito credentials.  | 
| \$1context.identity.cognitoIdentityPoolId |  The Amazon Cognito identity pool ID of the caller making the request. Available only if the request was signed with Amazon Cognito credentials.  | 
| \$1context.identity.sourceIp |  The source IP address of the immediate TCP connection making the request to API Gateway endpoint.  | 
| \$1context.identity.user |  The principal identifier of the user making the request.  | 
| \$1context.identity.userAgent |  The User Agent of the API caller.  | 
| \$1context.identity.userArn |  The Amazon Resource Name (ARN) of the effective user identified after authentication.  | 
| \$1context.requestTime | The [CLF](https://httpd.apache.org/docs/current/logs.html#common)-formatted request time (dd/MMM/yyyy:HH:mm:ss \$1-hhmm). | 
| \$1context.requestTimeEpoch | The [Epoch](https://en.wikipedia.org/wiki/Unix_time)-formatted request time, in milliseconds. | 
| \$1context.stage |  The deployment stage of the API call (for example, Beta or Prod).  | 
| \$1context.status |  The response status.  | 
| \$1input.body | Returns the raw payload as a string. | 
| \$1input.json(x) | This function evaluates a JSONPath expression and returns the results as a JSON string. For example, `$input.json('$.pets')` will return a JSON string representing the pets structure. For more information about JSONPath, see [JSONPath](https://goessner.net/articles/JsonPath/) or [JSONPath for Java](https://github.com/json-path/JsonPath). | 
| \$1input.path(x) | Takes a JSONPath expression string (`x`) and returns a JSON object representation of the result. This allows you to access and manipulate elements of the payload natively in [Apache Velocity Template Language (VTL)](https://velocity.apache.org/engine/devel/vtl-reference.html). For example, if the expression `$input.path('$.pets')` returns an object like this: <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()` would return `"3"`. For more information about JSONPath, see [JSONPath](http://goessner.net/articles/JsonPath/) or [JSONPath for Java](https://github.com/jayway/JsonPath). | 
| \$1stageVariables.<variable\$1name> |  *<variable\$1name>* represents a stage variable name.  | 
| \$1stageVariables['<variable\$1name>'] |  *<variable\$1name>* represents any stage variable name.  | 
| \$1\$1stageVariables['<variable\$1name>']\$1 |  *<variable\$1name>* represents any stage variable name.  | 
| \$1util.escapeJavaScript() |  Escapes the characters in a string using JavaScript string rules.  This function will turn any regular single quotes (`'`) into escaped ones (`\'`). However, the escaped single quotes are not valid in JSON. Thus, when the output from this function is used in a JSON property, you must turn any escaped single quotes (`\'`) back to regular single quotes (`'`). This is shown in the following example:  <pre> $util.escapeJavaScript(data).replaceAll("\\'","'")</pre>   | 
| \$1util.parseJson() |   Takes "stringified" JSON and returns an object representation of the result. You can use the result from this function to access and manipulate elements of the payload natively in Apache Velocity Template Language (VTL). For example, if you have the following payload:  <pre>{"errorMessage":"{\"key1\":\"var1\",\"key2\":{\"arr\":[1,2,3]}}"}</pre>  and use the following mapping template  <pre>#set ($errorMessageObj = $util.parseJson($input.path('$.errorMessage')))<br />{<br />   "errorMessageObjKey2ArrVal" : $errorMessageObj.key2.arr[0]<br />}<br /></pre> You will get the following output: <pre>{<br />   "errorMessageObjKey2ArrVal" : 1<br />}<br /></pre>  | 
| \$1util.urlEncode() | Converts a string into "application/x-www-form-urlencoded" format. | 
| \$1util.urlDecode() | Decodes an "application/x-www-form-urlencoded" string. | 
| \$1util.base64Encode() | Encodes the data into a base64-encoded string. | 
| \$1util.base64Decode() | Decodes the data from a base64-encoded string. | 

# Binary media types for WebSocket APIs in API Gateway
Binary media types

API Gateway WebSocket APIs don't currently support binary frames in incoming message payloads. If a client app sends a binary frame, API Gateway rejects it and disconnects the client with code 1003.

There is a workaround for this behavior. If the client sends a text-encoded binary data (e.g., base64) as a text frame, you can set the integration's `contentHandlingStrategy` property to `CONVERT_TO_BINARY` to convert the payload from base64-encoded string to binary. 

To return a route response for a binary payload in non-proxy integrations, you can set the integration response's `contentHandlingStrategy` property to `CONVERT_TO_TEXT` to convert the payload from binary to base64-encoded string.

# Invoke WebSocket APIs
Invoke

After you've deployed your WebSocket API, client applications can connect to it and send messages to it—and your backend service can send messages to connected client applications:
+ You can use `wscat` to connect to your WebSocket API and send messages to it to simulate client behavior. See [Use `wscat` to connect to a WebSocket API and send messages to it](apigateway-how-to-call-websocket-api-wscat.md).
+ You can use the @connections API from your backend service to send a callback message to a connected client, get connection information, or disconnect the client. See [Use `@connections` commands in your backend service](apigateway-how-to-call-websocket-api-connections.md).
+ A client application can use its own WebSocket library to invoke your WebSocket API.

# Use `wscat` to connect to a WebSocket API and send messages to it


The `[wscat](https://www.npmjs.com/package/wscat)` utility is a convenient tool for testing a WebSocket API that you have created and deployed in API Gateway. You can install and use `wscat` as follows:

1. Download `wscat` from [https://www.npmjs.com/package/wscat](https://www.npmjs.com/package/wscat).

1. Install `wscat` by running the following command:

   ```
   npm install -g wscat
   ```

1. To connect to your API, run the `wscat` command as shown in the following example. Note that this example assumes that the `Authorization` setting is `NONE`.

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

   You need to replace `aabbccddee` with the actual API ID, which is displayed in the API Gateway console or returned by the 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) command.

   In addition, if your API is in a Region other than `us-east-1`, you need to substitute the correct Region.

1. To test your API, enter a message such as the following while connected:

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

   where *\$1jsonpath-expression\$1* is a JSONPath expression and *\$1route-key\$1* is a route key for the API. For example:

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

   For more information about JSONPath, see [JSONPath](https://goessner.net/articles/JsonPath/) or [JSONPath for Java](https://github.com/json-path/JsonPath).

1. To disconnect from your API, enter `ctrl-C`.

# Use `@connections` commands in your backend service


Your backend service can use the following WebSocket connection HTTP requests to send a callback message to a connected client, get connection information, or disconnect the client.

**Important**  
These requests use [IAM authorization](apigateway-websocket-control-access-iam.md), so you must sign them with [Signature Version 4 (SigV4)](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html). To do this, you can use the API Gateway Management API. For more information, see [ApiGatewayManagementApi](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigatewaymanagementapi.html).

In the following command, you need to replace `{api-id}` with the actual API ID, which is displayed in the API Gateway console or returned by the AWS CLI [create-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html) command. You must establish the connection before using this command. 

To send a callback message to the client, use:

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

You can test this request by using `[Postman](https://www.postman.com/)` or by calling `[awscurl](https://github.com/okigan/awscurl)` as in the following example:

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

You need to URL-encode the command as in the following example:

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

To get the latest connection status of the client, use:

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

To disconnect the client, use:

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

You can dynamically build a callback URL by using the `$context` variables in your integration. For example, if you use Lambda proxy integration with a `Node.js` Lambda function, you can build the URL and send a message to a connected client as follows:

```
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,
  };
};
```

If you use a custom domain name for your WebSocket API, remove the `stage` variable from your function code.

When sending a callback message, your Lambda function must have permission to call the API Gateway Management API. You might receive an error that contains `GoneException` if you post a message before the connection is established, or after the client has disconnected. 