@gradientedge/cdk-utils 5.13.0 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/lib/construct/api-to-eventbridge-target/index.d.ts +0 -3
- package/dist/src/lib/construct/api-to-eventbridge-target/index.js +0 -3
- package/dist/src/lib/construct/api-to-eventbridge-target/main.d.ts +23 -68
- package/dist/src/lib/construct/api-to-eventbridge-target/main.js +124 -243
- package/dist/src/lib/construct/{api-to-eventbridge-target → api-to-eventbridge-target-with-sns}/api-destined-lambda.d.ts +1 -1
- package/dist/src/lib/construct/{api-to-eventbridge-target → api-to-eventbridge-target-with-sns}/api-destined-lambda.js +1 -1
- package/dist/src/lib/construct/api-to-eventbridge-target-with-sns/index.d.ts +2 -0
- package/dist/src/lib/construct/api-to-eventbridge-target-with-sns/index.js +18 -0
- package/dist/src/lib/construct/api-to-eventbridge-target-with-sns/main.d.ts +193 -0
- package/dist/src/lib/construct/api-to-eventbridge-target-with-sns/main.js +631 -0
- package/dist/src/lib/construct/graphql-api-lambda/main.js +1 -1
- package/dist/src/lib/construct/index.d.ts +1 -0
- package/dist/src/lib/construct/index.js +1 -0
- package/dist/src/lib/construct/site-with-ecs-backend/main.js +1 -1
- package/dist/src/lib/{construct/api-to-eventbridge-target/api-destination-event.d.ts → helper/api-to-eventbridge-target-event.d.ts} +5 -3
- package/dist/src/lib/{construct/api-to-eventbridge-target/api-destination-event.js → helper/api-to-eventbridge-target-event.js} +6 -4
- package/dist/src/lib/{construct/api-to-eventbridge-target/api-destined-rest-api.d.ts → helper/api-to-eventbridge-target-rest-api.d.ts} +4 -4
- package/dist/src/lib/{construct/api-to-eventbridge-target/api-destined-rest-api.js → helper/api-to-eventbridge-target-rest-api.js} +5 -5
- package/dist/src/lib/helper/index.d.ts +2 -0
- package/dist/src/lib/helper/index.js +18 -0
- package/dist/src/lib/manager/aws/ecs-manager.js +5 -0
- package/dist/src/lib/manager/aws/sqs-manager.js +0 -1
- package/dist/src/lib/types/aws/index.d.ts +10 -5
- package/package.json +11 -11
- package/src/lib/construct/api-to-eventbridge-target/index.ts +0 -3
- package/src/lib/construct/api-to-eventbridge-target/main.ts +131 -280
- package/src/lib/construct/{api-to-eventbridge-target → api-to-eventbridge-target-with-sns}/api-destined-lambda.ts +1 -1
- package/src/lib/construct/api-to-eventbridge-target-with-sns/index.ts +2 -0
- package/src/lib/construct/api-to-eventbridge-target-with-sns/main.ts +703 -0
- package/src/lib/construct/graphql-api-lambda/main.ts +1 -1
- package/src/lib/construct/index.ts +1 -0
- package/src/lib/construct/site-with-ecs-backend/main.ts +1 -1
- package/src/lib/{construct/api-to-eventbridge-target/api-destination-event.ts → helper/api-to-eventbridge-target-event.ts} +5 -3
- package/src/lib/{construct/api-to-eventbridge-target/api-destined-rest-api.ts → helper/api-to-eventbridge-target-rest-api.ts} +4 -4
- package/src/lib/helper/index.ts +2 -0
- package/src/lib/manager/aws/ecs-manager.ts +5 -0
- package/src/lib/manager/aws/sqs-manager.ts +0 -2
- package/src/lib/types/aws/index.ts +10 -5
|
@@ -7,7 +7,7 @@ import * as types from '../../types/aws'
|
|
|
7
7
|
* @stability stable
|
|
8
8
|
* @category cdk-utils.api-to-eventbridge-target
|
|
9
9
|
* @subcategory member
|
|
10
|
-
* @classdesc Provides a construct to contain lambda resources for
|
|
10
|
+
* @classdesc Provides a construct to contain lambda resources for ApiToEventBridgeTargetWithSns
|
|
11
11
|
*/
|
|
12
12
|
export class ApiDestinedLambda implements types.ApiDestinedLambdaType {
|
|
13
13
|
destinationFailure: destinations.EventBridgeDestination
|
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
import * as cdk from 'aws-cdk-lib'
|
|
2
|
+
import * as apig from 'aws-cdk-lib/aws-apigateway'
|
|
3
|
+
import * as events from 'aws-cdk-lib/aws-events'
|
|
4
|
+
import * as eventstargets from 'aws-cdk-lib/aws-events-targets'
|
|
5
|
+
import * as iam from 'aws-cdk-lib/aws-iam'
|
|
6
|
+
import * as lambda from 'aws-cdk-lib/aws-lambda'
|
|
7
|
+
import * as destinations from 'aws-cdk-lib/aws-lambda-destinations'
|
|
8
|
+
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager'
|
|
9
|
+
import { Construct } from 'constructs'
|
|
10
|
+
import { CommonConstruct } from '../../common'
|
|
11
|
+
import * as helper from '../../helper'
|
|
12
|
+
import * as types from '../../types'
|
|
13
|
+
import { ApiDestinedLambda } from './api-destined-lambda'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @stability stable
|
|
17
|
+
* @category cdk-utils.api-to-eventbridge-target
|
|
18
|
+
* @subcategory construct
|
|
19
|
+
* @classdesc Provides a construct to create and deploy API Gateway invocations to EventBridge
|
|
20
|
+
*
|
|
21
|
+
* <b>Architecture</b> 
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* import { ApiToEventBridgeTargetWithSns, ApiToEventBridgeTargetProps } '@gradientedge/cdk-utils'
|
|
25
|
+
* import { Construct } from 'constructs'
|
|
26
|
+
*
|
|
27
|
+
* class CustomConstruct extends ApiToEventBridgeTargetWithSns {
|
|
28
|
+
* constructor(parent: Construct, id: string, props: ApiToEventBridgeTargetProps) {
|
|
29
|
+
* super(parent, id, props)
|
|
30
|
+
* this.props = props
|
|
31
|
+
* this.id = id
|
|
32
|
+
* this.initResources()
|
|
33
|
+
* }
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
*/
|
|
37
|
+
export class ApiToEventBridgeTargetWithSns extends CommonConstruct {
|
|
38
|
+
props: types.ApiToEventBridgeTargetProps
|
|
39
|
+
id: string
|
|
40
|
+
|
|
41
|
+
/* application related resources */
|
|
42
|
+
applicationSecrets: secretsmanager.ISecret[]
|
|
43
|
+
|
|
44
|
+
/* destined lambda related resources */
|
|
45
|
+
apiDestinedLambda: types.ApiDestinedLambdaType
|
|
46
|
+
|
|
47
|
+
/* event related resources */
|
|
48
|
+
apiEvent: types.ApiToEventBridgeTargetEventType
|
|
49
|
+
|
|
50
|
+
/* rest restApi related resources */
|
|
51
|
+
apiDestinedRestApi: types.ApiToEventBridgeTargetRestApiType
|
|
52
|
+
apiResource: string
|
|
53
|
+
|
|
54
|
+
constructor(parent: Construct, id: string, props: types.ApiToEventBridgeTargetProps) {
|
|
55
|
+
super(parent, id, props)
|
|
56
|
+
|
|
57
|
+
this.props = props
|
|
58
|
+
this.id = id
|
|
59
|
+
|
|
60
|
+
this.apiDestinedLambda = new ApiDestinedLambda()
|
|
61
|
+
this.apiEvent = new helper.ApiToEventbridgeTargetEvent()
|
|
62
|
+
this.apiDestinedRestApi = new helper.ApiToEventbridgeTargetRestApi()
|
|
63
|
+
this.apiResource = 'notify'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
protected initResources() {
|
|
67
|
+
/* application related resources */
|
|
68
|
+
this.resolveSecrets()
|
|
69
|
+
|
|
70
|
+
/* core resources */
|
|
71
|
+
this.resolveHostedZone()
|
|
72
|
+
this.resolveCertificate()
|
|
73
|
+
|
|
74
|
+
/* optional custom event bus */
|
|
75
|
+
this.createApiDestinedEventBus()
|
|
76
|
+
|
|
77
|
+
/* destined lambda related resources */
|
|
78
|
+
this.createApiDestinedLambdaPolicy()
|
|
79
|
+
this.createApiDestinedLambdaRole()
|
|
80
|
+
this.createApiDestinedLambdaEnvironment()
|
|
81
|
+
this.createApiDestinedLambdaLayers()
|
|
82
|
+
this.createApiDestinedLambdaDestinations()
|
|
83
|
+
this.createApiDestinedLambdaFunction()
|
|
84
|
+
|
|
85
|
+
/* event related resources */
|
|
86
|
+
this.createApiDestinationLogGroupSuccess()
|
|
87
|
+
this.createApiDestinationRuleSuccess()
|
|
88
|
+
this.createApiDestinationLogGroupFailure()
|
|
89
|
+
this.createApiDestinationRuleFailure()
|
|
90
|
+
|
|
91
|
+
/* restApi related resources */
|
|
92
|
+
this.createApiDestinedTopicRole()
|
|
93
|
+
this.createApiDestinedTopic()
|
|
94
|
+
this.createApiDestinedIntegrationRequestParameters()
|
|
95
|
+
this.createApiDestinedIntegrationRequestTemplates()
|
|
96
|
+
this.createApiDestinedIntegrationResponse()
|
|
97
|
+
this.createApiDestinedIntegrationErrorResponse()
|
|
98
|
+
this.createApiDestinedIntegration()
|
|
99
|
+
this.createApiDestinedRestApi()
|
|
100
|
+
this.createApiDestinedResource()
|
|
101
|
+
this.createApiDestinedResponseModel()
|
|
102
|
+
this.createApiDestinedErrorResponseModel()
|
|
103
|
+
this.createApiDestinedMethodResponse()
|
|
104
|
+
this.createApiDestinedMethodErrorResponse()
|
|
105
|
+
this.createApiDestinedResourceMethod()
|
|
106
|
+
this.createApiDomain()
|
|
107
|
+
this.createApiBasePathMapping()
|
|
108
|
+
this.createApiRouteAssets()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @summary Method to resolve secrets from SecretsManager
|
|
113
|
+
* - To be implemented in the overriding method in the implementation class
|
|
114
|
+
* @protected
|
|
115
|
+
*/
|
|
116
|
+
protected resolveSecrets() {
|
|
117
|
+
this.applicationSecrets = []
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @summary Method to resolve a hosted zone based on domain attributes
|
|
122
|
+
* @protected
|
|
123
|
+
*/
|
|
124
|
+
protected resolveHostedZone() {
|
|
125
|
+
this.apiDestinedRestApi.hostedZone = this.route53Manager.withHostedZoneFromFullyQualifiedDomainName(
|
|
126
|
+
`${this.id}-hosted-zone`,
|
|
127
|
+
this,
|
|
128
|
+
this.props.useExistingHostedZone
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @summary Method to resolve a certificate based on attributes
|
|
134
|
+
* @protected
|
|
135
|
+
*/
|
|
136
|
+
protected resolveCertificate() {
|
|
137
|
+
if (this.props.api.useExisting) return
|
|
138
|
+
if (
|
|
139
|
+
this.props.api.certificate.useExistingCertificate &&
|
|
140
|
+
this.props.api.certificate.certificateSsmName &&
|
|
141
|
+
this.props.api.certificate.certificateRegion
|
|
142
|
+
) {
|
|
143
|
+
this.props.api.certificate.certificateArn = this.ssmManager.readStringParameterFromRegion(
|
|
144
|
+
`${this.id}-certificate-param`,
|
|
145
|
+
this,
|
|
146
|
+
this.props.api.certificate.certificateSsmName,
|
|
147
|
+
this.props.api.certificate.certificateRegion
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.apiDestinedRestApi.certificate = this.acmManager.resolveCertificate(
|
|
152
|
+
`${this.id}-certificate`,
|
|
153
|
+
this,
|
|
154
|
+
this.props.api.certificate
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @summary Method to create iam policy for Api Destined Lambda function
|
|
160
|
+
* @protected
|
|
161
|
+
*/
|
|
162
|
+
protected createApiDestinedLambdaPolicy() {
|
|
163
|
+
if (this.props.api.useExisting) return
|
|
164
|
+
this.apiDestinedLambda.policy = new iam.PolicyDocument({
|
|
165
|
+
statements: [this.iamManager.statementForPutEvents([this.apiEvent.eventBus.eventBusArn])],
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @summary Method to create iam role for Api Destined Lambda function
|
|
171
|
+
* @protected
|
|
172
|
+
*/
|
|
173
|
+
protected createApiDestinedLambdaRole() {
|
|
174
|
+
if (this.props.api.useExisting) return
|
|
175
|
+
this.apiDestinedLambda.role = this.iamManager.createRoleForLambda(
|
|
176
|
+
`${this.id}-lambda-destined-role`,
|
|
177
|
+
this,
|
|
178
|
+
this.apiDestinedLambda.policy
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @summary Method to create environment variables for Api Destined Lambda function
|
|
184
|
+
* @protected
|
|
185
|
+
*/
|
|
186
|
+
protected createApiDestinedLambdaEnvironment() {
|
|
187
|
+
if (this.props.api.useExisting) return
|
|
188
|
+
this.apiDestinedLambda.environment = {
|
|
189
|
+
NODE_ENV: this.props.nodeEnv,
|
|
190
|
+
LOG_LEVEL: this.props.logLevel,
|
|
191
|
+
TZ: this.props.timezone,
|
|
192
|
+
SOURCE_ID: this.id,
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @summary Method to create layers for Api Destined Lambda function
|
|
198
|
+
* @protected
|
|
199
|
+
*/
|
|
200
|
+
protected createApiDestinedLambdaLayers() {
|
|
201
|
+
if (this.props.api.useExisting) return
|
|
202
|
+
const layers: lambda.LayerVersion[] = []
|
|
203
|
+
if (this.props.lambda && this.props.lambda.layerSource) {
|
|
204
|
+
layers.push(
|
|
205
|
+
this.lambdaManager.createLambdaLayer(`${this.id}-lambda-destined-layer`, this, this.props.lambda.layerSource)
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
this.apiDestinedLambda.layers = layers
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @summary Method to create destination for Api Destined function
|
|
214
|
+
* @protected
|
|
215
|
+
*/
|
|
216
|
+
protected createApiDestinedLambdaDestinations() {
|
|
217
|
+
if (this.props.api.useExisting) return
|
|
218
|
+
this.apiDestinedLambda.destinationSuccess = new destinations.EventBridgeDestination(this.apiEvent.eventBus)
|
|
219
|
+
this.apiDestinedLambda.destinationFailure = new destinations.EventBridgeDestination(this.apiEvent.eventBus)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @summary Method to create lambda function for Api Destined
|
|
224
|
+
* @protected
|
|
225
|
+
*/
|
|
226
|
+
protected createApiDestinedLambdaFunction() {
|
|
227
|
+
if (this.props.api.useExisting) return
|
|
228
|
+
if (!this.props.lambda || !this.props.lambda.source) throw 'Api Destined Lambda props undefined'
|
|
229
|
+
|
|
230
|
+
this.apiDestinedLambda.function = this.lambdaManager.createLambdaFunction(
|
|
231
|
+
`${this.id}-lambda-destined`,
|
|
232
|
+
this,
|
|
233
|
+
{
|
|
234
|
+
...this.props.lambda.function,
|
|
235
|
+
...{
|
|
236
|
+
onSuccess: this.apiDestinedLambda.destinationSuccess,
|
|
237
|
+
onFailure: this.apiDestinedLambda.destinationFailure,
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
this.apiDestinedLambda.role,
|
|
241
|
+
this.apiDestinedLambda.layers,
|
|
242
|
+
this.props.lambda.source,
|
|
243
|
+
this.props.lambda.handler ?? 'lambda.handler',
|
|
244
|
+
this.apiDestinedLambda.environment
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* @summary Method to create or use an existing eventbus for api destined payload deliveries
|
|
250
|
+
* @protected
|
|
251
|
+
*/
|
|
252
|
+
protected createApiDestinedEventBus() {
|
|
253
|
+
if (this.props.api.useExisting) {
|
|
254
|
+
this.apiEvent.eventBus = events.EventBus.fromEventBusName(
|
|
255
|
+
this,
|
|
256
|
+
`${this.id}-destined-event-bus`,
|
|
257
|
+
`${this.props.event.eventBusName}-${this.props.stage}`
|
|
258
|
+
)
|
|
259
|
+
return
|
|
260
|
+
}
|
|
261
|
+
this.apiEvent.eventBus = this.eventManager.createEventBus(`${this.id}-destined-event-bus`, this, {
|
|
262
|
+
eventBusName: `${this.props.event.eventBusName}`,
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* @summary Method to create a log group for successful api destined payload deliveries
|
|
268
|
+
* @protected
|
|
269
|
+
*/
|
|
270
|
+
protected createApiDestinationLogGroupSuccess() {
|
|
271
|
+
if (this.props.api.useExisting) return
|
|
272
|
+
this.apiEvent.logGroupSuccess = this.logManager.createLogGroup(`${this.id}-destination-success-log`, this, {
|
|
273
|
+
...{
|
|
274
|
+
logGroupName: `/${this.id}/events/api-destination-success`,
|
|
275
|
+
},
|
|
276
|
+
...this.props.event.logGroupSuccess,
|
|
277
|
+
})
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Method to create EventBridge rule with lambda target for success
|
|
282
|
+
* @protected
|
|
283
|
+
*/
|
|
284
|
+
protected createApiDestinationRuleSuccess() {
|
|
285
|
+
if (this.props.api.useExisting) return
|
|
286
|
+
this.props.event.ruleSuccess = {
|
|
287
|
+
...{
|
|
288
|
+
ruleName: `${this.id}-api-destination-success`,
|
|
289
|
+
eventPattern: {
|
|
290
|
+
detail: {
|
|
291
|
+
requestContext: {
|
|
292
|
+
condition: ['Success'],
|
|
293
|
+
},
|
|
294
|
+
responsePayload: {
|
|
295
|
+
source: ['custom:api-destined-lambda'],
|
|
296
|
+
sourceId: [this.id],
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
...this.props.event.ruleSuccess,
|
|
302
|
+
}
|
|
303
|
+
this.apiEvent.ruleSuccess = this.eventManager.createRule(
|
|
304
|
+
`${this.id}-api-destination-rule-success`,
|
|
305
|
+
this,
|
|
306
|
+
this.props.event.ruleSuccess,
|
|
307
|
+
this.apiEvent.eventBus,
|
|
308
|
+
[new eventstargets.CloudWatchLogGroup(this.apiEvent.logGroupSuccess)]
|
|
309
|
+
)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* @summary Method to create a log group for failed api destined payload deliveries
|
|
314
|
+
* @protected
|
|
315
|
+
*/
|
|
316
|
+
protected createApiDestinationLogGroupFailure() {
|
|
317
|
+
if (this.props.api.useExisting) return
|
|
318
|
+
this.apiEvent.logGroupFailure = this.logManager.createLogGroup(`${this.id}-destination-failure-log`, this, {
|
|
319
|
+
...{
|
|
320
|
+
logGroupName: `/${this.id}/events/api-destination-failure`,
|
|
321
|
+
},
|
|
322
|
+
...this.props.event.logGroupFailure,
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Method to create EventBridge rule with lambda target for failure
|
|
328
|
+
* @protected
|
|
329
|
+
*/
|
|
330
|
+
protected createApiDestinationRuleFailure() {
|
|
331
|
+
if (this.props.api.useExisting) return
|
|
332
|
+
this.props.event.ruleFailure = {
|
|
333
|
+
...{
|
|
334
|
+
ruleName: `${this.id}-api-destination-failure`,
|
|
335
|
+
eventPattern: {
|
|
336
|
+
detail: {
|
|
337
|
+
responsePayload: {
|
|
338
|
+
errorType: ['Error'],
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
},
|
|
343
|
+
...this.props.event.ruleFailure,
|
|
344
|
+
}
|
|
345
|
+
this.apiEvent.ruleFailure = this.eventManager.createRule(
|
|
346
|
+
`${this.id}-api-destination-rule-failure`,
|
|
347
|
+
this,
|
|
348
|
+
this.props.event.ruleFailure,
|
|
349
|
+
this.apiEvent.eventBus,
|
|
350
|
+
[new eventstargets.CloudWatchLogGroup(this.apiEvent.logGroupFailure)]
|
|
351
|
+
)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* @summary Method to create a role for sns topic
|
|
356
|
+
* @protected
|
|
357
|
+
*/
|
|
358
|
+
protected createApiDestinedTopicRole() {
|
|
359
|
+
this.apiDestinedRestApi.role = new iam.Role(this, `${this.id}-sns-rest-api-role`, {
|
|
360
|
+
assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'),
|
|
361
|
+
})
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* @summary Method to create API destined SNS topic
|
|
366
|
+
* @protected
|
|
367
|
+
*/
|
|
368
|
+
protected createApiDestinedTopic() {
|
|
369
|
+
if (!this.props.api.withResource) return
|
|
370
|
+
this.apiDestinedRestApi.topic = this.snsManager.createLambdaNotificationService(
|
|
371
|
+
`${this.id}-destined-topic`,
|
|
372
|
+
this,
|
|
373
|
+
{
|
|
374
|
+
topicName: `${this.id}-destined-topic`,
|
|
375
|
+
},
|
|
376
|
+
this.apiDestinedLambda.function
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
if (this.apiDestinedRestApi.role) {
|
|
380
|
+
this.apiDestinedRestApi.topic.grantPublish(this.apiDestinedRestApi.role)
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* @summary Method to create api integration request parameters
|
|
386
|
+
* @protected
|
|
387
|
+
*/
|
|
388
|
+
protected createApiDestinedIntegrationRequestParameters() {
|
|
389
|
+
if (!this.props.api.withResource) return
|
|
390
|
+
this.apiDestinedRestApi.integrationRequestParameters = {
|
|
391
|
+
'integration.request.header.Content-Type': "'application/x-www-form-urlencoded'",
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* @summary Method to create api integration request templates
|
|
397
|
+
* @protected
|
|
398
|
+
*/
|
|
399
|
+
protected createApiDestinedIntegrationRequestTemplates() {
|
|
400
|
+
if (!this.props.api.withResource) return
|
|
401
|
+
if (!this.apiDestinedRestApi.topic) throw 'Topic undefined'
|
|
402
|
+
this.apiDestinedRestApi.integrationRequestTemplates = {
|
|
403
|
+
'application/json': [
|
|
404
|
+
'Action=Publish',
|
|
405
|
+
`TargetArn=$util.urlEncode('${this.apiDestinedRestApi.topic.topicArn}')`,
|
|
406
|
+
'Message=$util.urlEncode($input.body)',
|
|
407
|
+
'Version=2010-03-31',
|
|
408
|
+
].join('&'),
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* @summary Method to create api integration response
|
|
414
|
+
* @protected
|
|
415
|
+
*/
|
|
416
|
+
protected createApiDestinedIntegrationResponse() {
|
|
417
|
+
if (!this.props.api.withResource) return
|
|
418
|
+
this.apiDestinedRestApi.integrationResponse = this.props.api.integrationResponse ?? {
|
|
419
|
+
...{
|
|
420
|
+
statusCode: '200',
|
|
421
|
+
responseTemplates: {
|
|
422
|
+
'application/json': JSON.stringify({ message: 'Payload Submitted' }),
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* @summary Method to create api integration error response
|
|
430
|
+
* @protected
|
|
431
|
+
*/
|
|
432
|
+
protected createApiDestinedIntegrationErrorResponse() {
|
|
433
|
+
if (!this.props.api.withResource) return
|
|
434
|
+
this.apiDestinedRestApi.integrationErrorResponse = {
|
|
435
|
+
...{
|
|
436
|
+
selectionPattern: '^\\[Error\\].*',
|
|
437
|
+
statusCode: '400',
|
|
438
|
+
responseTemplates: {
|
|
439
|
+
'application/json': JSON.stringify({
|
|
440
|
+
state: 'error',
|
|
441
|
+
message: "$util.escapeJavaScript($input.path('$.errorMessage'))",
|
|
442
|
+
}),
|
|
443
|
+
},
|
|
444
|
+
responseParameters: {
|
|
445
|
+
'method.response.header.Content-Type': "'application/json'",
|
|
446
|
+
'method.response.header.Access-Control-Allow-Origin': "'*'",
|
|
447
|
+
'method.response.header.Access-Control-Allow-Credentials': "'true'",
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
...this.props.api.integrationErrorResponse,
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* @summary Method to create api integration
|
|
456
|
+
* @protected
|
|
457
|
+
*/
|
|
458
|
+
protected createApiDestinedIntegration() {
|
|
459
|
+
if (!this.props.api.withResource) return
|
|
460
|
+
this.apiDestinedRestApi.integration = new apig.Integration({
|
|
461
|
+
type: apig.IntegrationType.AWS,
|
|
462
|
+
integrationHttpMethod: 'POST',
|
|
463
|
+
uri: `arn:aws:apigateway:${this.props.region}:sns:path//`,
|
|
464
|
+
options: {
|
|
465
|
+
...{
|
|
466
|
+
credentialsRole: this.apiDestinedRestApi.role,
|
|
467
|
+
requestParameters: this.apiDestinedRestApi.integrationRequestParameters,
|
|
468
|
+
requestTemplates: this.apiDestinedRestApi.integrationRequestTemplates,
|
|
469
|
+
passthroughBehavior: apig.PassthroughBehavior.NEVER,
|
|
470
|
+
integrationResponses: [
|
|
471
|
+
this.apiDestinedRestApi.integrationResponse,
|
|
472
|
+
this.apiDestinedRestApi.integrationErrorResponse,
|
|
473
|
+
],
|
|
474
|
+
},
|
|
475
|
+
...this.props.api.integrationOptions,
|
|
476
|
+
},
|
|
477
|
+
})
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* @summary Method to create api integration method response
|
|
482
|
+
* @protected
|
|
483
|
+
*/
|
|
484
|
+
protected createApiDestinedMethodResponse() {
|
|
485
|
+
if (!this.props.api.withResource) return
|
|
486
|
+
this.apiDestinedRestApi.methodResponse = {
|
|
487
|
+
...{
|
|
488
|
+
statusCode: '200',
|
|
489
|
+
responseParameters: {
|
|
490
|
+
'method.response.header.Content-Type': true,
|
|
491
|
+
'method.response.header.Access-Control-Allow-Origin': true,
|
|
492
|
+
'method.response.header.Access-Control-Allow-Credentials': true,
|
|
493
|
+
},
|
|
494
|
+
responseModels: {
|
|
495
|
+
'application/json': this.apiDestinedRestApi.responseModel,
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
...this.props.api.methodResponse,
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* @summary Method to create api integration method error response
|
|
504
|
+
* @protected
|
|
505
|
+
*/
|
|
506
|
+
protected createApiDestinedMethodErrorResponse() {
|
|
507
|
+
if (!this.props.api.withResource) return
|
|
508
|
+
this.apiDestinedRestApi.methodErrorResponse = {
|
|
509
|
+
...{
|
|
510
|
+
statusCode: '400',
|
|
511
|
+
responseParameters: {
|
|
512
|
+
'method.response.header.Content-Type': true,
|
|
513
|
+
'method.response.header.Access-Control-Allow-Origin': true,
|
|
514
|
+
'method.response.header.Access-Control-Allow-Credentials': true,
|
|
515
|
+
},
|
|
516
|
+
responseModels: {
|
|
517
|
+
'application/json': this.apiDestinedRestApi.errorResponseModel,
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
...this.props.api.methodErrorResponse,
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* @summary Method to create rest restApi for Api
|
|
526
|
+
* @protected
|
|
527
|
+
*/
|
|
528
|
+
protected createApiDestinedRestApi() {
|
|
529
|
+
if (this.props.api.useExisting && this.props.api.importedRestApiRef) {
|
|
530
|
+
this.apiDestinedRestApi.api = apig.RestApi.fromRestApiId(
|
|
531
|
+
this,
|
|
532
|
+
`${this.id}-sns-rest-api`,
|
|
533
|
+
cdk.Fn.importValue(this.props.api.importedRestApiRef)
|
|
534
|
+
)
|
|
535
|
+
return
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const accessLogGroup = this.logManager.createLogGroup(`${this.id}-sns-rest-api-access-log`, this, {
|
|
539
|
+
logGroupName: `/custom/api/${this.id}-destined-rest-api-access`,
|
|
540
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
this.apiDestinedRestApi.api = new apig.RestApi(this, `${this.id}-sns-rest-api`, {
|
|
544
|
+
...{
|
|
545
|
+
defaultIntegration: this.apiDestinedRestApi.integration,
|
|
546
|
+
defaultMethodOptions: {
|
|
547
|
+
methodResponses: [this.apiDestinedRestApi.methodResponse, this.apiDestinedRestApi.methodErrorResponse],
|
|
548
|
+
},
|
|
549
|
+
deployOptions: {
|
|
550
|
+
dataTraceEnabled: true,
|
|
551
|
+
description: `${this.id} - ${this.props.stage} stage`,
|
|
552
|
+
loggingLevel: apig.MethodLoggingLevel.INFO,
|
|
553
|
+
metricsEnabled: true,
|
|
554
|
+
stageName: this.props.stage,
|
|
555
|
+
accessLogDestination: new apig.LogGroupLogDestination(accessLogGroup),
|
|
556
|
+
accessLogFormat: apig.AccessLogFormat.jsonWithStandardFields(),
|
|
557
|
+
},
|
|
558
|
+
endpointConfiguration: {
|
|
559
|
+
types: [apig.EndpointType.REGIONAL],
|
|
560
|
+
},
|
|
561
|
+
defaultCorsPreflightOptions: {
|
|
562
|
+
allowOrigins: apig.Cors.ALL_ORIGINS,
|
|
563
|
+
allowMethods: ['POST'],
|
|
564
|
+
allowHeaders: apig.Cors.DEFAULT_HEADERS,
|
|
565
|
+
},
|
|
566
|
+
restApiName: `${this.id}-destined-rest-api-${this.props.stage}`,
|
|
567
|
+
},
|
|
568
|
+
...this.props.api,
|
|
569
|
+
})
|
|
570
|
+
this.addCfnOutput(`${this.id}-restApiId`, this.apiDestinedRestApi.api.restApiId)
|
|
571
|
+
this.addCfnOutput(`${this.id}-restApiRootResourceId`, this.apiDestinedRestApi.api.root.resourceId)
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* @summary Method to create api integration response model
|
|
576
|
+
* @protected
|
|
577
|
+
*/
|
|
578
|
+
protected createApiDestinedResponseModel() {
|
|
579
|
+
if (!this.props.api.withResource) return
|
|
580
|
+
this.apiDestinedRestApi.responseModel = new apig.Model(this, `${this.id}-response-model`, {
|
|
581
|
+
restApi: this.apiDestinedRestApi.api,
|
|
582
|
+
...{
|
|
583
|
+
contentType: 'application/json',
|
|
584
|
+
modelName: 'ResponseModel',
|
|
585
|
+
schema: {
|
|
586
|
+
schema: apig.JsonSchemaVersion.DRAFT4,
|
|
587
|
+
title: 'pollResponse',
|
|
588
|
+
type: apig.JsonSchemaType.OBJECT,
|
|
589
|
+
properties: { message: { type: apig.JsonSchemaType.STRING } },
|
|
590
|
+
},
|
|
591
|
+
},
|
|
592
|
+
...this.props.api.responseModel,
|
|
593
|
+
})
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* @summary Method to create api integration error response model
|
|
598
|
+
* @protected
|
|
599
|
+
*/
|
|
600
|
+
protected createApiDestinedErrorResponseModel() {
|
|
601
|
+
if (!this.props.api.withResource) return
|
|
602
|
+
this.apiDestinedRestApi.errorResponseModel = new apig.Model(this, `${this.id}-error-response-model`, {
|
|
603
|
+
restApi: this.apiDestinedRestApi.api,
|
|
604
|
+
...{
|
|
605
|
+
contentType: 'application/json',
|
|
606
|
+
modelName: 'ErrorResponseModel',
|
|
607
|
+
schema: {
|
|
608
|
+
schema: apig.JsonSchemaVersion.DRAFT4,
|
|
609
|
+
title: 'errorResponse',
|
|
610
|
+
type: apig.JsonSchemaType.OBJECT,
|
|
611
|
+
properties: {
|
|
612
|
+
state: { type: apig.JsonSchemaType.STRING },
|
|
613
|
+
message: { type: apig.JsonSchemaType.STRING },
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
},
|
|
617
|
+
...this.props.api.errorResponseModel,
|
|
618
|
+
})
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* @summary Method to create api integration resource
|
|
623
|
+
* @protected
|
|
624
|
+
*/
|
|
625
|
+
protected createApiDestinedResource() {
|
|
626
|
+
if (!this.props.api.withResource) return
|
|
627
|
+
|
|
628
|
+
let rootResource
|
|
629
|
+
if (this.props.api.withResource && this.props.api.importedRestApiRootResourceRef) {
|
|
630
|
+
rootResource = apig.Resource.fromResourceAttributes(this, `${this.id}-root-resource`, {
|
|
631
|
+
resourceId: cdk.Fn.importValue(this.props.api.importedRestApiRootResourceRef),
|
|
632
|
+
restApi: this.apiDestinedRestApi.api,
|
|
633
|
+
path: '/',
|
|
634
|
+
})
|
|
635
|
+
} else {
|
|
636
|
+
rootResource = this.apiDestinedRestApi.api.root
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
this.apiDestinedRestApi.resource = rootResource.addResource(this.props.api.resource ?? this.apiResource)
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* @summary Method to create api integration resource method
|
|
644
|
+
* @protected
|
|
645
|
+
*/
|
|
646
|
+
protected createApiDestinedResourceMethod() {
|
|
647
|
+
if (!this.props.api.withResource) return
|
|
648
|
+
this.apiDestinedRestApi.method = this.apiDestinedRestApi.resource.addMethod(
|
|
649
|
+
'POST',
|
|
650
|
+
this.apiDestinedRestApi.integration,
|
|
651
|
+
{
|
|
652
|
+
authorizer: this.apiDestinedRestApi.authoriser,
|
|
653
|
+
methodResponses: [this.apiDestinedRestApi.methodResponse, this.apiDestinedRestApi.methodErrorResponse],
|
|
654
|
+
}
|
|
655
|
+
)
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* @summary Method to create custom restApi domain for Api API
|
|
660
|
+
* @protected
|
|
661
|
+
*/
|
|
662
|
+
protected createApiDomain() {
|
|
663
|
+
if (this.props.api.useExisting) return
|
|
664
|
+
this.apiDestinedRestApi.domain = this.apiManager.createApiDomain(
|
|
665
|
+
`${this.id}-api-domain`,
|
|
666
|
+
this,
|
|
667
|
+
this.isProductionStage() || this.props.skipStageForARecords
|
|
668
|
+
? `${this.props.apiSubDomain}.${this.fullyQualifiedDomainName}`
|
|
669
|
+
: `${this.props.apiSubDomain}-${this.props.stage}.${this.fullyQualifiedDomainName}`,
|
|
670
|
+
this.apiDestinedRestApi.certificate
|
|
671
|
+
)
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* @summary Method to create base path mappings for Api API
|
|
676
|
+
* @protected
|
|
677
|
+
*/
|
|
678
|
+
protected createApiBasePathMapping() {
|
|
679
|
+
if (this.props.api.useExisting) return
|
|
680
|
+
new apig.BasePathMapping(this, `${this.id}-base-bath-mapping`, {
|
|
681
|
+
basePath: '',
|
|
682
|
+
domainName: this.apiDestinedRestApi.domain,
|
|
683
|
+
restApi: this.apiDestinedRestApi.api,
|
|
684
|
+
stage: this.apiDestinedRestApi.api.deploymentStage,
|
|
685
|
+
})
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* @summary Method to create route53 records for Api API
|
|
690
|
+
* @protected
|
|
691
|
+
*/
|
|
692
|
+
protected createApiRouteAssets() {
|
|
693
|
+
if (this.props.api.useExisting) return
|
|
694
|
+
this.route53Manager.createApiGatewayARecord(
|
|
695
|
+
`${this.id}-custom-domain-a-record`,
|
|
696
|
+
this,
|
|
697
|
+
this.props.apiSubDomain,
|
|
698
|
+
this.apiDestinedRestApi.domain,
|
|
699
|
+
this.apiDestinedRestApi.hostedZone,
|
|
700
|
+
this.props.skipStageForARecords
|
|
701
|
+
)
|
|
702
|
+
}
|
|
703
|
+
}
|