Repository: cdklabs/cdk-enterprise-iac (language: python)

Issue:
feat: Add Aspect for overriding API gateway endpoint configuration
In some AWS regions, not all [endpoint configurations](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-restapi-endpointconfiguration.html) are supported, specifically `EDGE` endpoints.

Create an Aspect to set the Endpoint configuration for all `AWS::ApiGateway::RestApi` to use a set Endpoint type (`EDGE`, `REGIONAL` or `PRIVATE`), making `REGIONAL` the default endpoint type if a user doesn't specify


Discussion / hints:

Fix patch:
diff --git a/API.md b/API.md
index 8faf9f5..0605533 100644
--- a/API.md
+++ b/API.md
@@ -118,6 +118,39 @@ Name of the tag property to remove from the resource.
 
 ---
 
+### SetApiGatewayEndpointConfigurationProps <a name="SetApiGatewayEndpointConfigurationProps" id="@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfigurationProps"></a>
+
+#### Initializer <a name="Initializer" id="@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfigurationProps.Initializer"></a>
+
+```typescript
+import { SetApiGatewayEndpointConfigurationProps } from '@cdklabs/cdk-enterprise-iac'
+
+const setApiGatewayEndpointConfigurationProps: SetApiGatewayEndpointConfigurationProps = { ... }
+```
+
+#### Properties <a name="Properties" id="Properties"></a>
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfigurationProps.property.endpointType">endpointType</a></code> | <code>aws-cdk-lib.aws_apigateway.EndpointType</code> | API Gateway endpoint type to override to. |
+
+---
+
+##### `endpointType`<sup>Optional</sup> <a name="endpointType" id="@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfigurationProps.property.endpointType"></a>
+
+```typescript
+public readonly endpointType: EndpointType;
+```
+
+- *Type:* aws-cdk-lib.aws_apigateway.EndpointType
+- *Default:* EndpointType.REGIONAL
+
+API Gateway endpoint type to override to.
+
+Defaults to EndpointType.REGIONAL
+
+---
+
 ## Classes <a name="Classes" id="Classes"></a>
 
 ### AddLambdaEnvironmentVariables <a name="AddLambdaEnvironmentVariables" id="@cdklabs/cdk-enterprise-iac.AddLambdaEnvironmentVariables"></a>
@@ -379,4 +412,58 @@ All aspects can visit an IConstruct.
 
 
 
+### SetApiGatewayEndpointConfiguration <a name="SetApiGatewayEndpointConfiguration" id="@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfiguration"></a>
+
+- *Implements:* aws-cdk-lib.IAspect
+
+Override RestApis to use a set endpoint configuration.
+
+Some regions don't support EDGE endpoints, and some enterprises require
+specific endpoint types for RestApis
+
+#### Initializers <a name="Initializers" id="@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfiguration.Initializer"></a>
+
+```typescript
+import { SetApiGatewayEndpointConfiguration } from '@cdklabs/cdk-enterprise-iac'
+
+new SetApiGatewayEndpointConfiguration(props?: SetApiGatewayEndpointConfigurationProps)
+```
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfiguration.Initializer.parameter.props">props</a></code> | <code><a href="#@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfigurationProps">SetApiGatewayEndpointConfigurationProps</a></code> | *No description.* |
+
+---
+
+##### `props`<sup>Optional</sup> <a name="props" id="@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfiguration.Initializer.parameter.props"></a>
+
+- *Type:* <a href="#@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfigurationProps">SetApiGatewayEndpointConfigurationProps</a>
+
+---
+
+#### Methods <a name="Methods" id="Methods"></a>
+
+| **Name** | **Description** |
+| --- | --- |
+| <code><a href="#@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfiguration.visit">visit</a></code> | All aspects can visit an IConstruct. |
+
+---
+
+##### `visit` <a name="visit" id="@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfiguration.visit"></a>
+
+```typescript
+public visit(node: IConstruct): void
+```
+
+All aspects can visit an IConstruct.
+
+###### `node`<sup>Required</sup> <a name="node" id="@cdklabs/cdk-enterprise-iac.SetApiGatewayEndpointConfiguration.visit.parameter.node"></a>
+
+- *Type:* constructs.IConstruct
+
+---
+
+
+
+
 
diff --git a/src/index.ts b/src/index.ts
index 717b09d..9c33035 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -6,3 +6,4 @@ export * from './patches/addPermissionsBoundary';
 export * from './patches/removeTags';
 export * from './patches/addLambdaEnvironmentVariables';
 export * from './patches/removePublicAccessBlockConfiguration';
+export * from './patches/setApiGatewayEndpointConfiguration';
diff --git a/src/patches/setApiGatewayEndpointConfiguration.ts b/src/patches/setApiGatewayEndpointConfiguration.ts
new file mode 100644
index 0000000..0552d99
--- /dev/null
+++ b/src/patches/setApiGatewayEndpointConfiguration.ts
@@ -0,0 +1,45 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+import { CfnResource, IAspect } from 'aws-cdk-lib';
+import { EndpointType } from 'aws-cdk-lib/aws-apigateway';
+import { IConstruct } from 'constructs';
+
+export interface SetApiGatewayEndpointConfigurationProps {
+  /**
+   * API Gateway endpoint type to override to. Defaults to EndpointType.REGIONAL
+   *
+   * @default EndpointType.REGIONAL
+   */
+  readonly endpointType?: EndpointType;
+}
+
+/**
+ * Override RestApis to use a set endpoint configuration.
+ *
+ * Some regions don't support EDGE endpoints, and some enterprises require
+ * specific endpoint types for RestApis
+ */
+export class SetApiGatewayEndpointConfiguration implements IAspect {
+  private _endpointType: EndpointType;
+
+  constructor(props?: SetApiGatewayEndpointConfigurationProps) {
+    this._endpointType = props?.endpointType || EndpointType.REGIONAL;
+  }
+
+  public visit(node: IConstruct): void {
+    if (node instanceof CfnResource) {
+      const cfnResourceNode: CfnResource = node;
+      if (cfnResourceNode.cfnResourceType == 'AWS::ApiGateway::RestApi') {
+        cfnResourceNode.addPropertyOverride('EndpointConfiguration.Types', [
+          this._endpointType.toString(),
+        ]);
+        cfnResourceNode.addPropertyOverride(
+          'Parameters.endpointConfigurationTypes',
+          this._endpointType.toString()
+        );
+      }
+    }
+  }
+}


Test patch:
diff --git a/test/patches/setApiGatewayEndpointConfiguration.test.ts b/test/patches/setApiGatewayEndpointConfiguration.test.ts
new file mode 100644
index 0000000..e655720
--- /dev/null
+++ b/test/patches/setApiGatewayEndpointConfiguration.test.ts
@@ -0,0 +1,76 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+import { Aspects, Stack } from 'aws-cdk-lib';
+import { Template } from 'aws-cdk-lib/assertions';
+import { EndpointType, RestApi } from 'aws-cdk-lib/aws-apigateway';
+import { SetApiGatewayEndpointConfiguration } from '../../src/patches/setApiGatewayEndpointConfiguration';
+
+let stack: Stack;
+
+beforeEach(() => {
+  stack = new Stack();
+});
+
+describe('Set Api Gateway endpoint configuration', () => {
+  test('Sets API Gateway endpoint to regional when default Edge is selected', () => {
+    const api = new RestApi(stack, 'TestRestApi');
+    api.root.addMethod('ANY');
+    Aspects.of(stack).add(
+      new SetApiGatewayEndpointConfiguration({
+        endpointType: EndpointType.REGIONAL,
+      })
+    );
+
+    const template = Template.fromStack(stack);
+    template.hasResourceProperties('AWS::ApiGateway::RestApi', {
+      EndpointConfiguration: {
+        Types: ['REGIONAL'],
+      },
+      Parameters: {
+        endpointConfigurationTypes: 'REGIONAL',
+      },
+    });
+  });
+
+  test('Sets API Gateway endpoint to regional when endpoint type is specfically selected', () => {
+    const api = new RestApi(stack, 'TestRestApi', {
+      endpointConfiguration: {
+        types: [EndpointType.PRIVATE],
+      },
+    });
+    api.root.addMethod('ANY');
+    Aspects.of(stack).add(new SetApiGatewayEndpointConfiguration());
+
+    const template = Template.fromStack(stack);
+    template.hasResourceProperties('AWS::ApiGateway::RestApi', {
+      EndpointConfiguration: {
+        Types: ['REGIONAL'],
+      },
+      Parameters: {
+        endpointConfigurationTypes: 'REGIONAL',
+      },
+    });
+  });
+
+  test('Sets API Gateway endpoint to private when using default endpoint type', () => {
+    const api = new RestApi(stack, 'TestRestApi');
+    api.root.addMethod('ANY');
+    Aspects.of(stack).add(
+      new SetApiGatewayEndpointConfiguration({
+        endpointType: EndpointType.PRIVATE,
+      })
+    );
+
+    const template = Template.fromStack(stack);
+    template.hasResourceProperties('AWS::ApiGateway::RestApi', {
+      EndpointConfiguration: {
+        Types: ['PRIVATE'],
+      },
+      Parameters: {
+        endpointConfigurationTypes: 'PRIVATE',
+      },
+    });
+  });
+});