-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathweb-socket-api.ts
More file actions
132 lines (128 loc) · 4.38 KB
/
web-socket-api.ts
File metadata and controls
132 lines (128 loc) · 4.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import * as path from "node:path"
import * as cdk from "aws-cdk-lib"
import * as apigwv2 from "aws-cdk-lib/aws-apigatewayv2"
import type * as apigwv2Authorizers from "aws-cdk-lib/aws-apigatewayv2-authorizers"
import * as apigwv2Integrations from "aws-cdk-lib/aws-apigatewayv2-integrations"
import type * as cm from "aws-cdk-lib/aws-certificatemanager"
import * as dynamodb from "aws-cdk-lib/aws-dynamodb"
import * as lambda from "aws-cdk-lib/aws-lambda"
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"
import * as logs from "aws-cdk-lib/aws-logs"
import * as route53 from "aws-cdk-lib/aws-route53"
import * as route53targets from "aws-cdk-lib/aws-route53-targets"
import * as constructs from "constructs"
type Props = {
/**
* An optional authorizer that will be used for
* the intial WebSocket handshake.
*/
authorizer?: apigwv2Authorizers.WebSocketLambdaAuthorizer
/**
* The hosted zone to create the A record
* for the domain name
*/
hostedZone: route53.IHostedZone
/**
* The domain name to use for the WebSocket API.
*/
domainName: string
/**
* A certificate for the domain name. The certificate has to have
* been created in the current region.
*/
certificate: cm.ICertificate
/**
* Whether to store the properties under `$context.authorizer` together
* with the connection ID in DynamoDB.
*/
storeAuthorizerProperties?: boolean
}
/**
* API Gateway WebSocket API with a custom domain name,
* connection table in DynamoDB and Lambda handlers for
* the $connect and $disconnect routes.
*/
export class WebSocketApi extends constructs.Construct {
public readonly connectionTable
public readonly domainName
public readonly api
constructor(scope: constructs.Construct, id: string, props: Props) {
super(scope, id)
this.connectionTable = new dynamodb.Table(this, "ConnectionTable", {
partitionKey: {
name: "connectionId",
type: dynamodb.AttributeType.STRING,
},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY,
})
const connectFn = new NodejsFunction(this, "ConnectLambda", {
entry: path.join(__dirname, "../assets/web-socket-api/connect.ts"),
handler: "handler",
runtime: lambda.Runtime.NODEJS_24_X,
timeout: cdk.Duration.seconds(10),
logRetention: logs.RetentionDays.ONE_MONTH,
environment: {
TABLE_NAME: this.connectionTable.tableName,
STORE_AUTHORIZER_PROPERTIES: props.storeAuthorizerProperties
? "true"
: "false",
},
})
const disconnectFn = new NodejsFunction(this, "DisconnectLambda", {
entry: path.join(__dirname, "../assets/web-socket-api/disconnect.ts"),
handler: "handler",
runtime: lambda.Runtime.NODEJS_24_X,
timeout: cdk.Duration.seconds(10),
logRetention: logs.RetentionDays.ONE_MONTH,
environment: {
TABLE_NAME: this.connectionTable.tableName,
},
})
this.connectionTable.grantReadWriteData(connectFn)
this.connectionTable.grantReadWriteData(disconnectFn)
this.api = new apigwv2.WebSocketApi(this, "WebSocketApi", {
connectRouteOptions: {
authorizer: props.authorizer,
integration: new apigwv2Integrations.WebSocketLambdaIntegration(
"ConnectIntegration",
connectFn,
),
},
disconnectRouteOptions: {
integration: new apigwv2Integrations.WebSocketLambdaIntegration(
"DisconnectIntegration",
disconnectFn,
),
},
})
;(this.api.node.defaultChild as apigwv2.CfnApi).addPropertyOverride(
"DisableExecuteApiEndpoint",
true,
)
const stage = new apigwv2.WebSocketStage(this, "Stage", {
webSocketApi: this.api,
stageName: "prod",
autoDeploy: true,
})
this.domainName = new apigwv2.DomainName(this, "DomainName", {
certificate: props.certificate,
domainName: props.domainName,
})
const _apiMapping = new apigwv2.ApiMapping(this, "ApiMapping", {
api: this.api,
domainName: this.domainName,
stage: stage,
})
new route53.ARecord(this, "Record", {
recordName: props.domainName,
zone: props.hostedZone,
target: route53.RecordTarget.fromAlias(
new route53targets.ApiGatewayv2DomainProperties(
this.domainName.regionalDomainName,
this.domainName.regionalHostedZoneId,
),
),
})
}
}