@aws/nx-plugin 1.0.4 → 1.0.5
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/LICENSE-THIRD-PARTY +2 -2
- package/migrations.json +6 -1
- package/package.json +1 -1
- package/src/migrations/latest/api-custom-domain-runtime-config/metadata.json +3 -0
- package/src/migrations/latest/api-custom-domain-runtime-config/migration.d.ts +6 -0
- package/src/migrations/latest/api-custom-domain-runtime-config/migration.js +362 -0
- package/src/migrations/latest/api-custom-domain-runtime-config/migration.js.map +1 -0
- package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +54 -6
- package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +378 -6
- package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +252 -4
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +432 -12
- package/src/utils/api-constructs/files/cdk/core/api/http/http-api.ts.template +34 -4
- package/src/utils/api-constructs/files/cdk/core/api/rest/rest-api.ts.template +20 -2
- package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +63 -1
- package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +63 -1
|
@@ -7,10 +7,12 @@ import {
|
|
|
7
7
|
} from './utils<% if (esm) { %>.js<% } %>';
|
|
8
8
|
import { CfnOutput, Stack } from 'aws-cdk-lib';
|
|
9
9
|
import {
|
|
10
|
+
DomainMappingOptions,
|
|
10
11
|
HttpApi as _HttpApi,
|
|
11
12
|
HttpApiProps as _HttpApiProps,
|
|
12
13
|
HttpMethod,
|
|
13
14
|
HttpStage,
|
|
15
|
+
IDomainName,
|
|
14
16
|
LogGroupLogDestination,
|
|
15
17
|
ThrottleSettings,
|
|
16
18
|
} from 'aws-cdk-lib/aws-apigatewayv2';
|
|
@@ -28,7 +30,7 @@ import { suppressRules } from '../checkov<% if (esm) { %>.js<% } %>';
|
|
|
28
30
|
export interface HttpApiProps<
|
|
29
31
|
TIntegrations extends ApiIntegrations<TOperation, HttpApiIntegration>,
|
|
30
32
|
TOperation extends string,
|
|
31
|
-
> extends _HttpApiProps {
|
|
33
|
+
> extends Omit<_HttpApiProps, 'defaultDomainMapping'> {
|
|
32
34
|
/**
|
|
33
35
|
* Unique name for the API, used in runtime configuration
|
|
34
36
|
*/
|
|
@@ -47,6 +49,12 @@ export interface HttpApiProps<
|
|
|
47
49
|
* @default { rateLimit: 10000, burstLimit: 5000 }
|
|
48
50
|
*/
|
|
49
51
|
readonly throttle?: ThrottleSettings;
|
|
52
|
+
/**
|
|
53
|
+
* Custom domain mapped to the API's default stage
|
|
54
|
+
*/
|
|
55
|
+
readonly defaultDomainMapping?: DomainMappingOptions & {
|
|
56
|
+
readonly domainName: IDomainName;
|
|
57
|
+
};
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
/**
|
|
@@ -70,6 +78,9 @@ export class HttpApi<
|
|
|
70
78
|
/** Default auto-deployed stage */
|
|
71
79
|
public readonly defaultStage: HttpStage;
|
|
72
80
|
|
|
81
|
+
/** The URL clients call: the custom domain's if one is mapped, otherwise the stage's */
|
|
82
|
+
private readonly apiUrl: string;
|
|
83
|
+
|
|
73
84
|
/** Map of operation names to their API Gateway integrations */
|
|
74
85
|
public readonly integrations: TIntegrations;
|
|
75
86
|
|
|
@@ -81,6 +92,7 @@ export class HttpApi<
|
|
|
81
92
|
operations,
|
|
82
93
|
integrations,
|
|
83
94
|
throttle = { rateLimit: 10000, burstLimit: 5000 },
|
|
95
|
+
defaultDomainMapping,
|
|
84
96
|
...props
|
|
85
97
|
}: HttpApiProps<TIntegrations, TOperation>,
|
|
86
98
|
) {
|
|
@@ -113,12 +125,16 @@ export class HttpApi<
|
|
|
113
125
|
|
|
114
126
|
this.defaultStage = new HttpStage(this, 'DefaultStage', {
|
|
115
127
|
httpApi: this.api,
|
|
128
|
+
domainMapping: defaultDomainMapping,
|
|
116
129
|
autoDeploy: true,
|
|
117
130
|
throttle,
|
|
118
131
|
accessLogSettings: {
|
|
119
132
|
destination: new LogGroupLogDestination(accessLogGroup),
|
|
120
133
|
},
|
|
121
134
|
});
|
|
135
|
+
this.apiUrl = defaultDomainMapping
|
|
136
|
+
? this.defaultStage.domainUrl
|
|
137
|
+
: this.defaultStage.url!;
|
|
122
138
|
|
|
123
139
|
// Resolve the integration for a given operation.
|
|
124
140
|
// If the operation has a dedicated integration, use it; otherwise fall back to $router.
|
|
@@ -151,21 +167,35 @@ export class HttpApi<
|
|
|
151
167
|
);
|
|
152
168
|
|
|
153
169
|
new CfnOutput(this, `${apiName}Url`, {
|
|
154
|
-
value: this.
|
|
170
|
+
value: this.apiUrl,
|
|
155
171
|
});
|
|
156
172
|
|
|
157
173
|
// Register the API URL in runtime configuration for client discovery
|
|
158
174
|
const rc = RuntimeConfig.ensure(this);
|
|
159
175
|
rc.set('connection', 'apis', {
|
|
160
176
|
...rc.get('connection').apis,
|
|
161
|
-
[apiName]: this.
|
|
177
|
+
[apiName]: this.apiUrl,
|
|
162
178
|
});
|
|
179
|
+
|
|
180
|
+
// Target for the custom domain's DNS record
|
|
181
|
+
if (defaultDomainMapping) {
|
|
182
|
+
new CfnOutput(this, `${apiName}DomainNameAlias`, {
|
|
183
|
+
value: defaultDomainMapping.domainName.regionalDomainName,
|
|
184
|
+
description:
|
|
185
|
+
'Regional domain name to point a CNAME record at for the custom domain, with any DNS provider',
|
|
186
|
+
});
|
|
187
|
+
new CfnOutput(this, `${apiName}DomainNameAliasHostedZoneId`, {
|
|
188
|
+
value: defaultDomainMapping.domainName.regionalHostedZoneId,
|
|
189
|
+
description:
|
|
190
|
+
'Hosted zone ID of the regional domain name, needed only for a Route 53 alias record',
|
|
191
|
+
});
|
|
192
|
+
}
|
|
163
193
|
}
|
|
164
194
|
|
|
165
195
|
/**
|
|
166
196
|
* Return the API url
|
|
167
197
|
*/
|
|
168
198
|
public get url() {
|
|
169
|
-
return this.
|
|
199
|
+
return this.apiUrl;
|
|
170
200
|
}
|
|
171
201
|
}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
Stage,
|
|
11
11
|
ThrottleSettings,
|
|
12
12
|
} from 'aws-cdk-lib/aws-apigateway';
|
|
13
|
-
import { IAspect, RemovalPolicy, Stack } from 'aws-cdk-lib';
|
|
13
|
+
import { CfnOutput, IAspect, RemovalPolicy, Stack } from 'aws-cdk-lib';
|
|
14
14
|
import {
|
|
15
15
|
CfnLoggingConfiguration,
|
|
16
16
|
CfnWebACL,
|
|
@@ -99,6 +99,7 @@ export class RestApi<
|
|
|
99
99
|
integrations,
|
|
100
100
|
enableWaf = true,
|
|
101
101
|
throttle = { rateLimit: 10000, burstLimit: 5000 },
|
|
102
|
+
domainName,
|
|
102
103
|
...props
|
|
103
104
|
}: RestApiProps<TIntegrations, TOperation>,
|
|
104
105
|
) {
|
|
@@ -124,6 +125,7 @@ export class RestApi<
|
|
|
124
125
|
// Create the API Gateway REST API
|
|
125
126
|
this.api = new _RestApi(this, 'Api', {
|
|
126
127
|
...props,
|
|
128
|
+
domainName,
|
|
127
129
|
deployOptions: {
|
|
128
130
|
accessLogDestination: new LogGroupLogDestination(accessLogs),
|
|
129
131
|
accessLogFormat: AccessLogFormat.jsonWithStandardFields(),
|
|
@@ -265,8 +267,24 @@ export class RestApi<
|
|
|
265
267
|
const rc = RuntimeConfig.ensure(this);
|
|
266
268
|
rc.set('connection', 'apis', {
|
|
267
269
|
...rc.get('connection').apis,
|
|
268
|
-
[apiName]:
|
|
270
|
+
[apiName]: domainName
|
|
271
|
+
? `https://${domainName.domainName}/${domainName.basePath ? `${domainName.basePath}/` : ''}`
|
|
272
|
+
: this.api.url!,
|
|
269
273
|
});
|
|
274
|
+
|
|
275
|
+
// Target for the custom domain's DNS record
|
|
276
|
+
if (domainName) {
|
|
277
|
+
new CfnOutput(this, `${apiName}DomainNameAlias`, {
|
|
278
|
+
value: this.api.domainName!.domainNameAliasDomainName,
|
|
279
|
+
description:
|
|
280
|
+
'Domain name of the API Gateway endpoint (regional or edge) to point a CNAME record at for the custom domain, with any DNS provider',
|
|
281
|
+
});
|
|
282
|
+
new CfnOutput(this, `${apiName}DomainNameAliasHostedZoneId`, {
|
|
283
|
+
value: this.api.domainName!.domainNameAliasHostedZoneId,
|
|
284
|
+
description:
|
|
285
|
+
'Hosted zone ID of that domain name, needed only for a Route 53 alias record',
|
|
286
|
+
});
|
|
287
|
+
}
|
|
270
288
|
}
|
|
271
289
|
|
|
272
290
|
/**
|
|
@@ -125,6 +125,19 @@ variable "tags" {
|
|
|
125
125
|
default = {}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
# Custom domain configuration
|
|
129
|
+
variable "custom_domain_name" {
|
|
130
|
+
description = "Custom domain name for the API. Requires acm_certificate_arn."
|
|
131
|
+
type = string
|
|
132
|
+
default = null
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
variable "acm_certificate_arn" {
|
|
136
|
+
description = "ARN of an ACM certificate (in the API's region) for the custom domain name."
|
|
137
|
+
type = string
|
|
138
|
+
default = null
|
|
139
|
+
}
|
|
140
|
+
|
|
128
141
|
# Get current AWS region and account ID
|
|
129
142
|
data "aws_region" "current" {}
|
|
130
143
|
data "aws_caller_identity" "current" {}
|
|
@@ -431,6 +444,10 @@ locals {
|
|
|
431
444
|
<%_ } _%>
|
|
432
445
|
}
|
|
433
446
|
|
|
447
|
+
locals {
|
|
448
|
+
api_url = var.custom_domain_name == null ? module.http_api.stage_invoke_url : "https://${var.custom_domain_name}/"
|
|
449
|
+
}
|
|
450
|
+
|
|
434
451
|
# CloudWatch Log Group for Lambda
|
|
435
452
|
resource "aws_cloudwatch_log_group" "lambda_logs" {
|
|
436
453
|
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
@@ -674,11 +691,41 @@ module "add_url_to_runtime_config" {
|
|
|
674
691
|
|
|
675
692
|
namespace = "connection"
|
|
676
693
|
key = "apis"
|
|
677
|
-
value = { "<%- apiNameClassName %>" =
|
|
694
|
+
value = { "<%- apiNameClassName %>" = local.api_url }
|
|
678
695
|
|
|
679
696
|
depends_on = [module.http_api]
|
|
680
697
|
}
|
|
681
698
|
|
|
699
|
+
# Custom domain for the API
|
|
700
|
+
resource "aws_apigatewayv2_domain_name" "custom_domain" {
|
|
701
|
+
count = var.custom_domain_name == null ? 0 : 1
|
|
702
|
+
|
|
703
|
+
domain_name = var.custom_domain_name
|
|
704
|
+
|
|
705
|
+
domain_name_configuration {
|
|
706
|
+
certificate_arn = var.acm_certificate_arn
|
|
707
|
+
endpoint_type = "REGIONAL"
|
|
708
|
+
security_policy = "TLS_1_2"
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
tags = var.tags
|
|
712
|
+
|
|
713
|
+
lifecycle {
|
|
714
|
+
precondition {
|
|
715
|
+
condition = var.acm_certificate_arn != null
|
|
716
|
+
error_message = "acm_certificate_arn is required when custom_domain_name is set."
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
resource "aws_apigatewayv2_api_mapping" "custom_domain" {
|
|
722
|
+
count = var.custom_domain_name == null ? 0 : 1
|
|
723
|
+
|
|
724
|
+
api_id = module.http_api.api_id
|
|
725
|
+
stage = module.http_api.stage_id
|
|
726
|
+
domain_name = aws_apigatewayv2_domain_name.custom_domain[0].domain_name
|
|
727
|
+
}
|
|
728
|
+
|
|
682
729
|
# Lambda permission for API Gateway to invoke the function<% if (backend.type === 'fastapi') { %> via alias<% } %>
|
|
683
730
|
resource "aws_lambda_permission" "api_gateway_invoke" {
|
|
684
731
|
<%_ if (backend.integrationPattern === 'isolated') { _%>
|
|
@@ -738,6 +785,21 @@ output "stage_invoke_url" {
|
|
|
738
785
|
value = module.http_api.stage_invoke_url
|
|
739
786
|
}
|
|
740
787
|
|
|
788
|
+
output "api_url" {
|
|
789
|
+
description = "URL clients should call: the custom domain if configured, otherwise the stage invoke URL"
|
|
790
|
+
value = local.api_url
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
output "custom_domain_target_domain_name" {
|
|
794
|
+
description = "Target domain name to point a DNS alias or CNAME record at for the custom domain"
|
|
795
|
+
value = var.custom_domain_name == null ? null : aws_apigatewayv2_domain_name.custom_domain[0].domain_name_configuration[0].target_domain_name
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
output "custom_domain_hosted_zone_id" {
|
|
799
|
+
description = "Hosted zone ID to use for a Route 53 alias record for the custom domain"
|
|
800
|
+
value = var.custom_domain_name == null ? null : aws_apigatewayv2_domain_name.custom_domain[0].domain_name_configuration[0].hosted_zone_id
|
|
801
|
+
}
|
|
802
|
+
|
|
741
803
|
output "stage_arn" {
|
|
742
804
|
description = "ARN of the API Gateway stage"
|
|
743
805
|
value = module.http_api.stage_arn
|
|
@@ -121,6 +121,19 @@ variable "tags" {
|
|
|
121
121
|
default = {}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
# Custom domain configuration
|
|
125
|
+
variable "custom_domain_name" {
|
|
126
|
+
description = "Custom domain name for the API. Requires acm_certificate_arn."
|
|
127
|
+
type = string
|
|
128
|
+
default = null
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
variable "acm_certificate_arn" {
|
|
132
|
+
description = "ARN of an ACM certificate (in the API's region) for the custom domain name."
|
|
133
|
+
type = string
|
|
134
|
+
default = null
|
|
135
|
+
}
|
|
136
|
+
|
|
124
137
|
# Get current AWS region and account ID
|
|
125
138
|
data "aws_region" "current" {}
|
|
126
139
|
data "aws_caller_identity" "current" {}
|
|
@@ -485,6 +498,10 @@ locals {
|
|
|
485
498
|
<%_ } _%>
|
|
486
499
|
}
|
|
487
500
|
|
|
501
|
+
locals {
|
|
502
|
+
api_url = var.custom_domain_name == null ? "${aws_api_gateway_stage.api_stage.invoke_url}/" : "https://${var.custom_domain_name}/"
|
|
503
|
+
}
|
|
504
|
+
|
|
488
505
|
# CloudWatch Log Group for Lambda
|
|
489
506
|
resource "aws_cloudwatch_log_group" "lambda_logs" {
|
|
490
507
|
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
@@ -1139,11 +1156,41 @@ module "add_url_to_runtime_config" {
|
|
|
1139
1156
|
|
|
1140
1157
|
namespace = "connection"
|
|
1141
1158
|
key = "apis"
|
|
1142
|
-
value = { "<%- apiNameClassName %>" =
|
|
1159
|
+
value = { "<%- apiNameClassName %>" = local.api_url }
|
|
1143
1160
|
|
|
1144
1161
|
depends_on = [aws_api_gateway_stage.api_stage]
|
|
1145
1162
|
}
|
|
1146
1163
|
|
|
1164
|
+
# Custom domain for the API, served without the stage path prefix
|
|
1165
|
+
resource "aws_api_gateway_domain_name" "custom_domain" {
|
|
1166
|
+
count = var.custom_domain_name == null ? 0 : 1
|
|
1167
|
+
|
|
1168
|
+
domain_name = var.custom_domain_name
|
|
1169
|
+
regional_certificate_arn = var.acm_certificate_arn
|
|
1170
|
+
security_policy = "TLS_1_2"
|
|
1171
|
+
|
|
1172
|
+
endpoint_configuration {
|
|
1173
|
+
types = ["REGIONAL"]
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
tags = var.tags
|
|
1177
|
+
|
|
1178
|
+
lifecycle {
|
|
1179
|
+
precondition {
|
|
1180
|
+
condition = var.acm_certificate_arn != null
|
|
1181
|
+
error_message = "acm_certificate_arn is required when custom_domain_name is set."
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
resource "aws_api_gateway_base_path_mapping" "custom_domain" {
|
|
1187
|
+
count = var.custom_domain_name == null ? 0 : 1
|
|
1188
|
+
|
|
1189
|
+
api_id = module.rest_api.api_id
|
|
1190
|
+
stage_name = aws_api_gateway_stage.api_stage.stage_name
|
|
1191
|
+
domain_name = aws_api_gateway_domain_name.custom_domain[0].domain_name
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1147
1194
|
# Outputs
|
|
1148
1195
|
|
|
1149
1196
|
# API Gateway Outputs (from core module)
|
|
@@ -1172,6 +1219,21 @@ output "stage_invoke_url" {
|
|
|
1172
1219
|
value = aws_api_gateway_stage.api_stage.invoke_url
|
|
1173
1220
|
}
|
|
1174
1221
|
|
|
1222
|
+
output "api_url" {
|
|
1223
|
+
description = "URL clients should call: the custom domain if configured, otherwise the stage invoke URL"
|
|
1224
|
+
value = local.api_url
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
output "custom_domain_target_domain_name" {
|
|
1228
|
+
description = "Target domain name to point a DNS alias or CNAME record at for the custom domain"
|
|
1229
|
+
value = var.custom_domain_name == null ? null : aws_api_gateway_domain_name.custom_domain[0].regional_domain_name
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
output "custom_domain_hosted_zone_id" {
|
|
1233
|
+
description = "Hosted zone ID to use for a Route 53 alias record for the custom domain"
|
|
1234
|
+
value = var.custom_domain_name == null ? null : aws_api_gateway_domain_name.custom_domain[0].regional_zone_id
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1175
1237
|
output "stage_arn" {
|
|
1176
1238
|
description = "ARN of the API Gateway stage"
|
|
1177
1239
|
value = aws_api_gateway_stage.api_stage.arn
|