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"