diff --git a/packages/aws-cdk-lib/aws-route53-targets/README.md b/packages/aws-cdk-lib/aws-route53-targets/README.md index 032fbe1da54b2..13bc4e92cddcf 100644 --- a/packages/aws-cdk-lib/aws-route53-targets/README.md +++ b/packages/aws-cdk-lib/aws-route53-targets/README.md @@ -32,6 +32,19 @@ This library contains Route53 Alias Record targets for: }); ``` +* AppSync custom domains + + ```ts + import * as appsync from 'aws-cdk-lib/aws-appsync'; + + declare const zone: route53.HostedZone; + declare const graphqlApi: appsync.GraphqlApi; + + new route53.ARecord(this, 'AliasRecord', { + zone, + target: route53.RecordTarget.fromAlias(new targets.AppSync(graphqlApi)) + }); + * CloudFront distributions ```ts diff --git a/packages/aws-cdk-lib/aws-route53-targets/lib/appsync-target.ts b/packages/aws-cdk-lib/aws-route53-targets/lib/appsync-target.ts new file mode 100644 index 0000000000000..60ea65c6c5048 --- /dev/null +++ b/packages/aws-cdk-lib/aws-route53-targets/lib/appsync-target.ts @@ -0,0 +1,23 @@ +import { CloudFrontTarget } from './cloudfront-target'; +import { GraphqlApi } from '../../aws-appsync'; +import { + AliasRecordTargetConfig, + IAliasRecordTarget, + IHostedZone, + IRecordSet, +} from '../../aws-route53'; + +/** + * Defines an AppSync Graphql API as the alias target. Requires that the domain + * name will be defined through `GraphqlApiProps.domainName`. + */ +export class AppSync implements IAliasRecordTarget { + constructor(private readonly graphqlApi: GraphqlApi) {} + + public bind(_record: IRecordSet, _zone?: IHostedZone): AliasRecordTargetConfig { + return { + dnsName: this.graphqlApi.appSyncDomainName, + hostedZoneId: CloudFrontTarget.getHostedZoneId(this.graphqlApi), + }; + } +} diff --git a/packages/aws-cdk-lib/aws-route53-targets/lib/index.ts b/packages/aws-cdk-lib/aws-route53-targets/lib/index.ts index 714719322b883..a25010ba3f27d 100644 --- a/packages/aws-cdk-lib/aws-route53-targets/lib/index.ts +++ b/packages/aws-cdk-lib/aws-route53-targets/lib/index.ts @@ -1,5 +1,6 @@ export * from './api-gateway-domain-name'; export * from './api-gatewayv2-domain-name'; +export * from './appsync-domain-target'; export * from './bucket-website-target'; export * from './elastic-beanstalk-environment-target'; export * from './classic-load-balancer-target'; diff --git a/packages/aws-cdk-lib/aws-route53-targets/test/appsync-target.test.ts b/packages/aws-cdk-lib/aws-route53-targets/test/appsync-target.test.ts new file mode 100644 index 0000000000000..ececa4a61300a --- /dev/null +++ b/packages/aws-cdk-lib/aws-route53-targets/test/appsync-target.test.ts @@ -0,0 +1,54 @@ +import { join } from 'path'; +import { Template } from '../../assertions'; +import * as appsync from '../../aws-appsync'; +import * as acm from '../../aws-certificatemanager'; +import * as route53 from '../../aws-route53'; +import { Stack } from '../../core'; +import * as targets from '../lib'; + +test('targets.AppSync can be used to the default domain of an AppSync GraphqlApi', () => { + // GIVEN + const stack = new Stack(); + const cert = new acm.Certificate(stack, 'cert', { domainName: 'example.com' }); + const api = new appsync.GraphqlApi(stack, 'api', { + definition: appsync.Definition.fromFile(join(__dirname, '..', '..', 'aws-appsync', 'test', 'appsync.test.graphql')), + domainName: { + domainName: 'example.com', + certificate: cert, + }, + name: 'api', + }); + const zone = new route53.HostedZone(stack, 'zone', { + zoneName: 'example.com', + }); + + // WHEN + new route53.ARecord(stack, 'A', { + zone, + target: route53.RecordTarget.fromAlias(new targets.AppSync(api)), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Route53::RecordSet', { + Name: 'example.com.', + Type: 'A', + AliasTarget: { + DNSName: { + 'Fn::GetAtt': [ + 'apiDomainNameBBFE36A4', + 'AppSyncDomainName', + ], + }, + HostedZoneId: { + 'Fn::FindInMap': [ + 'AWSCloudFrontPartitionHostedZoneIdMap', + { Ref: 'AWS::Partition' }, + 'zoneId', + ], + }, + }, + HostedZoneId: { + Ref: 'zoneEB40FF1E', + }, + }); +});