Repository: amplify-education/serverless-domain-manager (ts)

Issue:
A Record (Alias) not being created
<!--- Please keep this note for the community --->

### Community Note

* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request
* Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
* If you are interested in working on this issue or have submitted a pull request, please leave a comment

<!--- Thank you for keeping this note for the community --->

## Bug Report

**Error Description**
The custom domain is created and mapped to my API Gateway but the needed A Record in Route 53 is not being created.


**Command Run**
`sls deploy`

**Console Output**
No errors reported

**Domain Manager Configuration**
Replace this with your own `serverless.yml` file (anonymized, of course) to help us better resolve your issue.
```yaml
customDomain:
    domainName: my-domain.com
    stage: ${self:provider.stage}
    apiType: rest
    basePath: v1
    certificateName: my-cert
    createRoute53Record: true
    endpointType: regional
```

**Versions**
- Domain Manager version(s): 4.1.1
- Node/npm version: Node 12
- Serverless Version: 1.73.1
- Lambda Code JavaScript

**Possible Solution**
<!--- Only if you have suggestions on a fix for the bug -->

**Additional context/Screenshots**
Add any other context about the problem here. If applicable, add screenshots to help explain.


Pull request description:
Fix route53 creation for `create_domain` command
<!--- Information about referencing Github Issues: https://help.github.com/articles/basic-writing-and-formatting-syntax/#referencing-issues-and-pull-requests --->
Fixes #361 #346

**Description of Issue Fixed**

Update `createDomain` logic to create route53 before creating API gateway


**Changes proposed in this pull request**:

* Update `create_domain` method with route53 creation at first

<!--- Please remember to allow edits from maintainers: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork --->


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d2d7ce0..0ec6db7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,11 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
-## [5.3.0] - 2021-12-20
+## [5.3.1] - 2021-01-18
+- Updated output for `compiledCloudFormationTemplate`. Thank you @nalbion ([442](https://github.com/amplify-education/serverless-domain-manager/pull/442))
+- Fixed Route53 creation for `create_domain` action.
+
+## [5.3.0] - 2021-01-14
 - Added support of Serverless version 3. Thank you @medikoo ([449](https://github.com/amplify-education/serverless-domain-manager/pull/449))
 - Integration test refactoring
 
diff --git a/package.json b/package.json
index 0b4391d..e145839 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "serverless-domain-manager",
-  "version": "5.3.0",
+  "version": "5.3.1",
   "engines": {
     "node": ">=12"
   },
diff --git a/src/aws/cloud-formation-wrapper.ts b/src/aws/cloud-formation-wrapper.ts
index 9f64689..2fd4870 100644
--- a/src/aws/cloud-formation-wrapper.ts
+++ b/src/aws/cloud-formation-wrapper.ts
@@ -18,14 +18,7 @@ class CloudFormationWrapper {
      * Gets rest API id from CloudFormation stack or nested stack
      */
     public async getApiId(domain: DomainConfig, stackName: string): Promise<string> {
-        let logicalResourceId = "ApiGatewayRestApi";
-        if (domain.apiType === Globals.apiTypes.http) {
-            logicalResourceId = "HttpApi";
-        }
-        if (domain.apiType === Globals.apiTypes.websocket) {
-            logicalResourceId = "WebsocketsApi";
-        }
-
+        const logicalResourceId = Globals.CFResourceIds[domain.apiType];
         let response;
         try {
             // trying to get information for specified stack name
@@ -100,16 +93,16 @@ class CloudFormationWrapper {
         // filter stacks by given stackName and check by nested stack RootId
         const regex = new RegExp(`\/${stackName}\/`);
         const filteredStackNames = stacks
-          .reduce((acc, stack) => {
-              if (!stack.RootId) {
-                  return acc;
-              }
-              const match = stack.RootId.match(regex);
-              if (match) {
-                  acc.push(stack.StackName);
-              }
-              return acc;
-          }, []);
+            .reduce((acc, stack) => {
+                if (!stack.RootId) {
+                    return acc;
+                }
+                const match = stack.RootId.match(regex);
+                if (match) {
+                    acc.push(stack.StackName);
+                }
+                return acc;
+            }, []);
 
         let response;
         for (const name of filteredStackNames) {
diff --git a/src/globals.ts b/src/globals.ts
index 39e527a..644d53e 100644
--- a/src/globals.ts
+++ b/src/globals.ts
@@ -27,6 +27,13 @@ export default class Globals {
         [Globals.apiTypes.websocket]: "websocketApiId",
     };
 
+    // Cloud Formation Resource Ids
+    public static CFResourceIds = {
+        [Globals.apiTypes.http]: "HttpApi",
+        [Globals.apiTypes.rest]: "ApiGatewayRestApi",
+        [Globals.apiTypes.websocket]: "WebsocketsApi",
+    };
+
     public static tlsVersions = {
         tls_1_0: "TLS_1_0",
         tls_1_2: "TLS_1_2",
@@ -92,7 +99,7 @@ export default class Globals {
      */
 
     public static printDomainSummary(domain: DomainConfig): void {
-        Globals.cliLog( chalk.yellow.underline("Summary:"), chalk.yellow("Distribution Domain Name"));
+        Globals.cliLog(chalk.yellow.underline("Summary:"), chalk.yellow("Distribution Domain Name"));
         Globals.cliLog("", `  Domain Name: ${domain.givenDomainName}`);
         Globals.cliLog("", `  Target Domain: ${domain.domainInfo.domainName}`);
         Globals.cliLog("", `  Hosted Zone Id: ${domain.domainInfo.hostedZoneId}`);
diff --git a/src/index.ts b/src/index.ts
index 3619f40..ac669b2 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -73,7 +73,7 @@ class ServerlessCustomDomain {
         // setup AWS resources
         this.initAWSResources();
 
-        return await lifecycleFunc.call(this);
+        return lifecycleFunc.call(this);
     }
 
     /**
@@ -186,20 +186,16 @@ class ServerlessCustomDomain {
         domain.domainInfo = await this.apiGatewayWrapper.getCustomDomainInfo(domain);
         try {
             if (!domain.domainInfo) {
-
                 domain.certificateArn = await this.getCertArn(domain);
-
                 await this.apiGatewayWrapper.createCustomDomain(domain);
-
-                await this.changeResourceRecordSet("UPSERT", domain);
-
-                Globals.logInfo(
-                    `Custom domain ${domain.givenDomainName} was created.
-                        New domains may take up to 40 minutes to be initialized.`,
-                );
             } else {
                 Globals.logInfo(`Custom domain ${domain.givenDomainName} already exists.`);
             }
+            await this.changeResourceRecordSet("UPSERT", domain);
+            Globals.logInfo(
+                `Custom domain ${domain.givenDomainName} was created.
+                        New domains may take up to 40 minutes to be initialized.`,
+            );
         } catch (err) {
             Globals.logError(err, domain.givenDomainName);
             throw new Error(`Unable to create domain ${domain.givenDomainName}`);
@@ -423,8 +419,7 @@ class ServerlessCustomDomain {
                 Action must be either UPSERT or DELETE.\n`);
         }
 
-        const createRoute53Record = domain.createRoute53Record;
-        if (createRoute53Record !== undefined && createRoute53Record === false) {
+        if (domain.createRoute53Record === false) {
             Globals.logInfo(`Skipping ${action === "DELETE" ? "removal" : "creation"} of Route53 record.`);
             return;
         }
@@ -433,12 +428,16 @@ class ServerlessCustomDomain {
         const route53HostedZoneId = await this.getRoute53HostedZoneId(domain);
         const route53Params = domain.route53Params;
         const route53healthCheck = route53Params.healthCheckId ? {HealthCheckId: route53Params.healthCheckId} : {};
+        const domainInfo = domain.domainInfo ?? {
+            domainName: domain.givenDomainName,
+            hostedZoneId: route53HostedZoneId,
+        }
 
         let routingOptions = {}
         if (route53Params.routingPolicy === Globals.routingPolicies.latency) {
             routingOptions = {
                 Region: domain.region,
-                SetIdentifier: domain.route53Params.setIdentifier ?? domain.domainInfo.domainName,
+                SetIdentifier: domain.route53Params.setIdentifier ?? domainInfo.domainName,
                 ...route53healthCheck,
             }
         }
@@ -446,7 +445,7 @@ class ServerlessCustomDomain {
         if (route53Params.routingPolicy === Globals.routingPolicies.weighted) {
             routingOptions = {
                 Weight: domain.route53Params.weight,
-                SetIdentifier: domain.route53Params.setIdentifier ?? domain.domainInfo.domainName,
+                SetIdentifier: domain.route53Params.setIdentifier ?? domainInfo.domainName,
                 ...route53healthCheck,
             }
         }
@@ -455,9 +454,9 @@ class ServerlessCustomDomain {
             Action: action,
             ResourceRecordSet: {
                 AliasTarget: {
-                    DNSName: domain.domainInfo.domainName,
+                    DNSName: domainInfo.domainName,
                     EvaluateTargetHealth: false,
-                    HostedZoneId: domain.domainInfo.hostedZoneId,
+                    HostedZoneId: domainInfo.hostedZoneId,
                 },
                 Name: domain.givenDomainName,
                 Type,


Test patch:
diff --git a/test/integration-tests/deploy/custom-apigateway/serverless.yml b/test/integration-tests/deploy/custom-apigateway/serverless.yml
index 4bc069e..fb874b5 100644
--- a/test/integration-tests/deploy/custom-apigateway/serverless.yml
+++ b/test/integration-tests/deploy/custom-apigateway/serverless.yml
@@ -8,6 +8,7 @@ provider:
   stage: test
   apiGateway:
     restApiId: ${env:REST_API_ID}
+    restApiRootResourceId: ${env:RESOURCE_ID}
     restApiResources:
       'hello-world': ${env:RESOURCE_ID}
 functions:
diff --git a/test/unit-tests/index.test.ts b/test/unit-tests/index.test.ts
index ac59b96..9169abc 100644
--- a/test/unit-tests/index.test.ts
+++ b/test/unit-tests/index.test.ts
@@ -1199,6 +1199,7 @@ describe("Custom Domain Plugin", () => {
             });
             await plugin.createDomains();
             expect(consoleOutput[0]).to.equal(`Custom domain test_domain already exists.`);
+            expect(consoleOutput[1]).to.contains(`Custom domain test_domain was created.`);
         });
 
         afterEach(() => {