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
- scope Construct
- id string
- props WebSocketApiProps
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
- scope Construct
- routes Record<string, string | Function | WebSocketApiFunctionRouteProps>
Add routes to an already created WebSocket API
api.addRoutes(stack, {
"$connect": "src/connect.main",
})
attachPermissions
attachPermissions(permissions)
Parameters
- permissions Permissions
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
- routeKey string
- permissions Permissions
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"