

# Create routes for WebSocket APIs in API Gateway
<a name="websocket-api-develop-routes"></a>

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 name="apigateway-websocket-api-route-selection-expressions"></a>

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
<a name="apigateway-websocket-api-routes"></a>

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
<a name="apigateway-websocket-api-route-using-console"></a>

**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
<a name="apigateway-websocket-api-route-using-awscli"></a>

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`
<a name="apigateway-websocket-api-route-request-connect"></a>

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
<a name="apigateway-websocket-api-connect-route-request-using-console"></a>

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
<a name="apigateway-websocket-api-route-response"></a>

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
<a name="apigateway-websocket-api-route-response-using-console"></a>

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
<a name="apigateway-websocket-api-route-response-using-awscli"></a>

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
<a name="websocket-connect-route-subprotocol"></a>

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).