Skip to main content

WebSocketApi

The WebSocketApi construct is a higher level CDK construct that makes it easy to create a WebSocket API. It provides a simple way to define your routes and allows you to configure the specific Lambda functions if necessary. It also allows you to configure authorization and custom domains. See the examples for more details.

Examples

Minimal Config

import { WebSocketApi } from "sst/constructs";

new WebSocketApi(stack, "Api", {
routes: {
$connect: "src/connect.main",
$default: "src/default.main",
$disconnect: "src/disconnect.main",
sendMessage: "src/sendMessage.main",
},
});

Configuring routes

Lazily adding routes

Add routes after the API has been created.

const api = new WebSocketApi(stack, "Api", {
routes: {
$connect: "src/connect.main",
$default: "src/default.main",
$disconnect: "src/disconnect.main",
},
});

api.addRoutes(stack, {
sendMessage: "src/sendMessage.main",
});

Specifying function props for all the routes

You can extend the minimal config, to set some function props and have them apply to all the routes.

new WebSocketApi(stack, "Api", {
defaults: {
function: {
timeout: 20,
permissions: [table],
environment: { tableName: table.tableName },
},
},
routes: {
$connect: "src/connect.main",
$default: "src/default.main",
$disconnect: "src/disconnect.main",
},
});

Configuring an individual route

Configure each Lambda route separately.

new WebSocketApi(stack, "Api", {
routes: {
$default: {
function: {
timeout: 20,
handler: "src/default.main",
permissions: [table],
environment: { tableName: table.tableName },
},
},
},
});

Note that, you can set the defaults.functionProps while using the function per route. The function will just override the defaults.functionProps. Except for the environment, the layers, and the permissions properties, that will be merged.

new WebSocketApi(stack, "Api", {
defaults: {
function: {
timeout: 20,
permissions: [table],
environment: { tableName: table.tableName },
},
},
routes: {
$default: {
function: {
handler: "src/default.main",
timeout: 10,
permissions: [bucket],
environment: { bucketName: bucket.bucketName },
},
},
$connect: "src/connect.main",
},
});

So in the above example, the $default function doesn't use the timeout that is set in the defaults.functionProps. It'll instead use the one that is defined in the function definition (10 seconds). And the function will have both the tableName and the bucketName environment variables set; as well as permissions to both the table and the bucket.

Getting the function for a route

const api = new WebSocketApi(stack, "Api", {
routes: {
$connect: "src/connect.main",
$default: "src/default.main",
$disconnect: "src/disconnect.main",
sendMessage: "src/sendMessage.main",
},
});

const function = api.getFunction("sendMessage");

Custom domains

You can also configure the API with a custom domain. SST currently supports domains that are configured using Route 53. If your domains are hosted elsewhere, you can follow this guide to migrate them to Route 53.

Using the basic config

new WebSocketApi(stack, "Api", {
customDomain: "api.domain.com",
routes: {
$default: "src/default.main",
},
});

Configuring with a wildcard

new WebSocketApi(stack, "Api", {
customDomain: "*.domain.com",
routes: {
$default: "src/default.main",
},
});

Using the full config

new WebSocketApi(stack, "Api", {
customDomain: {
domainName: "api.domain.com",
hostedZone: "domain.com",
path: "v1",
},
routes: {
$default: "src/default.main",
},
});

Mapping multiple APIs to the same domain

const coreApi = new WebSocketApi(stack, "CoreApi", {
customDomain: {
domainName: "api.domain.com",
path: "core",
},
});

new WebSocketApi(stack, "ChatApi", {
customDomain: {
path: "chat",
cdk: {
domainName: coreApi.cdk.domainName,
},
},
});

Note that you can't map WebSocketApis to the same domain name as an Api or ApiGatewayV1Api construct. Read more about AWS API Gateway custom domain name restrictions.

Importing an existing API Gateway custom domain

import { DomainName } from "aws-cdk-lib/aws-apigatewayv2";

new WebSocketApi(stack, "Api", {
customDomain: {
path: "newPath",
cdk: {
domainName: DomainName.fromDomainNameAttributes(stack, "MyDomain", {
name,
regionalDomainName,
regionalHostedZoneId,
}),
},
},
routes: {
$default: "src/default.main",
},
});

Importing an existing certificate

import { Certificate } from "aws-cdk-lib/aws-certificatemanager";

new WebSocketApi(stack, "Api", {
customDomain: {
domainName: "api.domain.com",
cdk: {
certificate: Certificate.fromCertificateArn(stack, "MyCert", certArn),
},
},
routes: {
$default: "src/default.main",
},
});

Using externally hosted domain

import { Certificate } from "aws-cdk-lib/aws-certificatemanager";

new WebSocketApi(stack, "Api", {
customDomain: {
isExternalDomain: true,
domainName: "api.domain.com",
cdk: {
certificate: Certificate.fromCertificateArn(stack, "MyCert", certArn),
},
},
routes: {
$default: "src/default.main",
},
});

Note that you can also migrate externally hosted domains to Route 53 by following this guide.

Authorization

You can use IAM or a Lambda authorizer to add auth to your APIs.

Adding IAM authorization

You can secure all your API routes by setting the defaults.authorizer.

new WebSocketApi(stack, "Api", {
authorizer: "iam",
routes: {
$connect: "src/connect.main",
$default: "src/default.main",
$disconnect: "src/disconnect.main",
},
});

Adding Lambda authorization

You can also use a Lambda function to authorize users to access your API.

import { Function, WebSocketApi } from "sst/constructs";

new WebSocketApi(stack, "Api", {
authorizer: {
type: "lambda",
function: new Function(stack, "Authorizer", {
handler: "src/authorizer.main",
}),
},
routes: {
$connect: "src/connect.main",
$default: "src/default.main",
$disconnect: "src/disconnect.main",
},
});

Using SST Auth

No changes are required for your CDK construct, but inside of your $connect and $default functions, you can access the authenticated user's information using the hooks provided by Auth.

// src/connect.ts
import { WebSocketApiHandler } from 'sst/node/websocket-api';
import { useSession } from 'sst/node/auth';

export const handler = WebSocketApiHandler(async () => {
const session = useSession();
if (session.type === 'public') {
return { statusCode: 401};
}
// Do something here...
return {
statusCode: 200,
};
});

And to connect, remember to set your Sec-WebSocket-Protocol Header. Here's an example using browser WebSocket API.

const connectedAndAuthorizedWebSocket = new WebSocket(websocketApiUrl, authTokenFromSession)

Access log

Configuring the log format

Use a CSV format instead of default JSON format.

new WebSocketApi(stack, "Api", {
accessLog:
"$context.identity.sourceIp,$context.requestTime,$context.httpMethod,$context.routeKey,$context.protocol,$context.status,$context.responseLength,$context.requestId",
routes: {
$default: "src/default.main",
},
});

Configuring the log retention setting

new WebSocketApi(stack, "Api", {
accessLog: {
retention: "one_week",
},
routes: {
$default: "src/default.main",
},
});

Permissions

You can attach a set of permissions to all or some of the routes.

note

By default all routes are granted the execute-api:ManageConnections permission to manage the WebSocket connections.

For example, the route handler functions have the permissions to make the ApiGatewayManagementApi.postToConnection call using the AWS SDK.

Attaching permissions for the entire API

Allow the entire API to access S3.

const api = new WebSocketApi(stack, "Api", {
routes: {
$connect: "src/connect.main",
$default: "src/default.main",
$disconnect: "src/disconnect.main",
sendMessage: "src/sendMessage.main",
},
});

api.attachPermissions(["s3"]);

Attaching permissions for a specific route

Allow one of the routes to access S3.

const api = new WebSocketApi(stack, "Api", {
routes: {
$connect: "src/connect.main",
$default: "src/default.main",
$disconnect: "src/disconnect.main",
sendMessage: "src/sendMessage.main",
},
});

api.attachPermissionsToRoute("$default", ["s3"]);

Advanced examples

Configuring the WebSocket Api

Configure the internally created CDK WebSocketApi instance.

new WebSocketApi(stack, "Api", {
cdk: {
webSocketApi: {
apiName: "chat-app-api",
},
},
routes: {
$default: "src/default.main",
},
});

Constructor

new WebSocketApi(scope, id, props)

Parameters

WebSocketApiProps

accessLog?

Type : string | boolean | WebSocketApiAccessLogProps

Enable CloudWatch access logs for this API

new WebSocketApi(stack, "Api", {
accessLog: true
});
new WebSocketApi(stack, "Api", {
accessLog: {
retention: "one_week",
},
});

authorizer?

Type : "none" | "iam" | WebSocketApiLambdaAuthorizer

The default authorizer for the API.

new WebSocketApi(stack, "Api", {
authorizer: "iam",
});
new WebSocketApi(stack, "Api", {
authorizer: {
type: "lambda",
function: new Function(stack, "Authorizer", {
handler: "test/lambda.handler",
}),
},
});

customDomain?

Type : string | WebSocketApiDomainProps

Specify a custom domain to use in addition to the automatically generated one. SST currently supports domains that are configured using Route 53

new WebSocketApi(stack, "Api", {
customDomain: "api.example.com"
})
new WebSocketApi(stack, "Api", {
customDomain: {
domainName: "api.example.com",
hostedZone: "domain.com",
path: "v1"
}
})

defaults?

Type :

defaults.function?

Type : FunctionProps

The default function props to be applied to all the Lambda functions in the API. The environment , permissions and layers properties will be merged with per route definitions if they are defined.

new WebSocketApi(stack, "Api", {
defaults: {
function: {
timeout: 20,
environment: { tableName: table.tableName },
permissions: [table],
}
},
});

routes?

Type : Record<string, string | Function | WebSocketApiFunctionRouteProps>

The routes for the WebSocket API

new WebSocketApi(stack, "Api", {
routes: {
$connect : "src/connect.main",
$default : "src/default.main",
$disconnect : "src/disconnect.main",
sendMessage : "src/sendMessage.main",
}
})

cdk?

Type :

cdk.id?

Type : string

Allows you to override default id for this construct.

cdk.webSocketApi?

Type : IWebSocketApi | WebSocketApiProps

Override the internally created WebSocket API

new WebSocketApi(stack, "WebSocketApi", {
cdk: {
webSocketApi: {
apiName: "my-websocket-api"
}
}
})

cdk.webSocketStage?

Type : IWebSocketStage | WebSocketApiCdkStageProps

Override the internally created WebSocket Stage

new WebSocketApi(stack, "WebSocketApi", {
cdk: {
webSocketStage: {
autoDeploy: false
}
}
})

Properties

An instance of WebSocketApi has the following properties.

customDomainUrl

Type : undefined | string

Custom domain url if it's configured

id

Type : string

routes

Type : Array<string>

List of routes of the websocket api

url

Type : string

Url of the WebSocket API

cdk

Type :

cdk.accessLogGroup?

Type : LogGroup

The internally created log group

cdk.certificate?

Type : Certificate

The internally created certificate

cdk.domainName?

Type : DomainName

The internally created domain name

cdk.webSocketApi

Type : WebSocketApi

The internally created websocket api

cdk.webSocketStage

Type : WebSocketStage

The internally created websocket stage

Methods

An instance of WebSocketApi has the following methods.

addRoutes

addRoutes(scope, routes)

Parameters

Add routes to an already created WebSocket API

api.addRoutes(stack, {
"$connect": "src/connect.main",
})

attachPermissions

attachPermissions(permissions)

Parameters

Attaches the given list of permissions to all the routes. This allows the functions to access other AWS resources.

api.attachPermissions(["s3"]);

attachPermissionsToRoute

attachPermissionsToRoute(routeKey, permissions)

Parameters

Attaches the given list of permissions to a specific route. This allows that function to access other AWS resources.

api.attachPermissionsToRoute("$connect", ["s3"]);

bind

bind(constructs)

Parameters

  • constructs Array<BindingResource>

Binds the given list of resources to all the routes.

api.bind([STRIPE_KEY, bucket]);

bindToRoute

bindToRoute(routeKey, constructs)

Parameters

  • routeKey string
  • constructs Array<BindingResource>

Binds the given list of resources to a specific route.

api.bindToRoute("$connect", [STRIPE_KEY, bucket]);

getFunction

getFunction(routeKey)

Parameters

  • routeKey string

Get the instance of the internally created Function, for a given route key where the routeKey is the key used to define a route. For example, $connect .

const fn = api.getFunction("$connect");

getRoute

getRoute(routeKey)

Parameters

  • routeKey string

Get the instance of the internally created Route, for a given route key where the routeKey is the key used to define a route. For example, $connect .

const route = api.getRoute("$connect");

WebSocketApiDomainProps

domainName?

Type : string

The domain to be assigned to the API endpoint (ie. api.domain.com)

hostedZone?

Type : string

The hosted zone in Route 53 that contains the domain. By default, SST will look for a hosted zone by stripping out the first part of the domainName that's passed in. So, if your domainName is api.domain.com. SST will default the hostedZone to domain.com.

isExternalDomain?

Type : boolean

Set this option if the domain is not hosted on Amazon Route 53.

path?

Type : string

The base mapping for the custom domain.

For example, by setting the domainName to api.domain.com and the path to v1, the custom domain URL of the API will become https://api.domain.com/v1/. If the path is not set, the custom domain URL will be https://api.domain.com. Note the additional trailing slash in the former case.

cdk?

Type :

cdk.certificate?

Type : ICertificate

Override the internally created certificate

cdk.domainName?

Type : IDomainName

Override the internally created domain name

cdk.hostedZone?

Type : IHostedZone

Override the internally created hosted zone

WebSocketApiCdkStageProps

stageName?

Type : string

WebSocketApiAccessLogProps

destinationArn?

Type : string

format?

Type : string

retention?

Type : "one_day" | "three_days" | "five_days" | "one_week" | "two_weeks" | "one_month" | "two_months" | "three_months" | "four_months" | "five_months" | "six_months" | "one_year" | "thirteen_months" | "eighteen_months" | "two_years" | "three_years" | "five_years" | "six_years" | "seven_years" | "eight_years" | "nine_years" | "ten_years" | "infinite"

WebSocketApiLambdaAuthorizer

Specify a Lambda authorizer and configure additional options.

new WebSocketApi(stack, "Api", {
authorizer: {
type: "lambda",
function: new Function(stack, "Authorizer", {
handler: "test/lambda.handler",
}),
},
});

function?

Type : Function

identitySource?

Type : Array<string>

name?

Type : string

type

Type : "lambda"

cdk?

Type :

cdk.authorizer

Type : WebSocketLambdaAuthorizer

WebSocketApiFunctionRouteProps

Specify a function route handler and configure additional options

api.addRoutes(stack, {
sendMessage : {
function: "src/sendMessage.main",
}
});

function

Type : string | Function | FunctionProps

The function definition used to create the function for this route.

returnResponse?

Type : boolean

Should the route send a response to the client.

type?

Type : "function"