diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/README.md b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/README.md index b6224d2e7..a9e00031d 100755 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/README.md @@ -63,14 +63,17 @@ new ApiGatewayToSqs(this, "ApiGatewayToSqsPattern", new ApiGatewayToSqsProps.Bui |deployDeadLetterQueue?|`boolean`|Whether to deploy a secondary queue to be used as a dead letter queue. Defaults to `true`.| |maxReceiveCount|`number`|The number of times a message can be unsuccessfully dequeued before being moved to the dead-letter queue.| |allowCreateOperation?|`boolean`|Whether to deploy an API Gateway Method for POST HTTP operations on the queue (i.e. sqs:SendMessage).| +|createRequestPath?|`string`| Optional, user provided request path for POST HTTP operations.| |createRequestTemplate?|`string`|API Gateway Request Template for the create method for the default `application/json` content-type. This property is required if the `allowCreateOperation` property is set to true.| |additionalCreateRequestTemplates?|`{ [contentType: string]: string; }`|Optional Create Request Templates for content-types other than `application/json`. Use the `createRequestTemplate` property to set the request template for the `application/json` content-type. This property can only be specified if the `allowCreateOperation` property is set to true.| |createIntegrationResponses?|[`api.IntegrationResponses[]`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.IntegrationResponse.html)|Optional, custom API Gateway Integration Response for the create method. This property can only be specified if the `allowCreateOperation` property is set to true.| |allowReadOperation?|`boolean`|Whether to deploy an API Gateway Method for GET HTTP operations on the queue (i.e. sqs:ReceiveMessage).| +|readRequestPath?|`string`| Optional, user provided request path for GET HTTP operations.| |readRequestTemplate?|`string`|API Gateway Request Template for the read method for the default `application/json` content-type.| |additionalReadRequestTemplates?|`{ [contentType: string]: string; }`|Optional Read Request Templates for content-types other than `application/json`. Use the `readRequestTemplate` property to set the request template for the `application/json` content-type.| |readIntegrationResponses?|[`api.IntegrationResponses[]`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.IntegrationResponse.html)|Optional, custom API Gateway Integration Response for the read method.| -|allowDeleteOperation?|`boolean`|Whether to deploy an API Gateway Method for HTTP DELETE operations on the queue (i.e. sqs:DeleteMessage).| +|allowDeleteOperation?|`boolean`|Whether to deploy an API Gateway Method for DELETE HTTP operations on the queue (i.e. sqs:DeleteMessage).| +|deleteRequestPath?|`string`| Optional, user provided request path for DELETE HTTP operations.| |deleteRequestTemplate?|`string`|API Gateway Request Template for THE delete method for the default `application/json` content-type. This property can only be specified if the `allowDeleteOperation` property is set to true.| |additionalDeleteRequestTemplates?|`{ [contentType: string]: string; }`|Optional Delete request templates for content-types other than `application/json`. Use the `deleteRequestTemplate` property to set the request template for the `application/json` content-type. This property can only be specified if the `allowDeleteOperation` property is set to true.| |deleteIntegrationResponses?|[`api.IntegrationResponses[]`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.IntegrationResponse.html)|Optional, custom API Gateway Integration Response for the delete method. This property can only be specified if the `allowDeleteOperation` property is set to true.| diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts index afd0be495..07db94030 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts @@ -169,6 +169,27 @@ export interface ApiGatewayToSqsProps { * @default - None */ readonly encryptionKeyProps?: kms.KeyProps; + /** + * Optional, custom API Gateway path for the GET method. + * This property can only be specified if the `allowReadOperation` property is not set to false. + * + * @default - "" + */ + readonly readRequestPath?: string; + /** + * Optional, custom API Gateway path for the POST method. + * This property can only be specified if the `allowCreateOperation` property is not set to false. + * + * @default - "" + */ + readonly createRequestPath?: string; + /** + * Optional, custom API Gateway path for the DELETE method. + * This property can only be specif||ied if the `allowDeleteOperation` property is not set to false. + * + * @default - "message" + */ + readonly deleteRequestPath?: string; } /** @@ -200,15 +221,15 @@ export class ApiGatewayToSqs extends Construct { if (this.CheckCreateRequestProps(props)) { throw new Error(`The 'allowCreateOperation' property must be set to true when setting any of the following: ` + - `'createRequestTemplate', 'additionalCreateRequestTemplates', 'createIntegrationResponses'`); + `'createRequestTemplate', 'additionalCreateRequestTemplates', 'createIntegrationResponses', 'createRequestPath'`); } if (this.CheckReadRequestProps(props)) { throw new Error(`The 'allowReadOperation' property must be set to true or undefined when setting any of the following: ` + - `'readRequestTemplate', 'additionalReadRequestTemplates', 'readIntegrationResponses'`); + `'readRequestTemplate', 'additionalReadRequestTemplates', 'readIntegrationResponses', 'readRequestPath'`); } if (this.CheckDeleteRequestProps(props)) { throw new Error(`The 'allowDeleteOperation' property must be set to true when setting any of the following: ` + - `'deleteRequestTemplate', 'additionalDeleteRequestTemplates', 'deleteIntegrationResponses'`); + `'deleteRequestTemplate', 'additionalDeleteRequestTemplates', 'deleteIntegrationResponses', 'deleteRequestPath'`); } // Setup the dead letter queue, if applicable @@ -244,13 +265,14 @@ export class ApiGatewayToSqs extends Construct { // Create const createRequestTemplate = props.createRequestTemplate ?? this.defaultCreateRequestTemplate; if (props.allowCreateOperation && props.allowCreateOperation === true) { + const apiCreateRequestResource = props.createRequestPath ? this.apiGateway.root.addResource(props.createRequestPath) : this.apiGateway.root; this.addActionToPolicy("sqs:SendMessage"); defaults.addProxyMethodToApiResource({ service: "sqs", path: `${cdk.Aws.ACCOUNT_ID}/${this.sqsQueue.queueName}`, apiGatewayRole: this.apiGatewayRole, apiMethod: "POST", - apiResource: this.apiGateway.root, + apiResource: apiCreateRequestResource, requestTemplate: createRequestTemplate, additionalRequestTemplates: props.additionalCreateRequestTemplates, contentType: "'application/x-www-form-urlencoded'", @@ -261,13 +283,14 @@ export class ApiGatewayToSqs extends Construct { // Read const readRequestTemplate = props.readRequestTemplate ?? this.defaultReadRequestTemplate; if (props.allowReadOperation === undefined || props.allowReadOperation === true) { + const apiReadRequestResource = props.readRequestPath ? this.apiGateway.root.addResource(props.readRequestPath) : this.apiGateway.root; this.addActionToPolicy("sqs:ReceiveMessage"); defaults.addProxyMethodToApiResource({ service: "sqs", path: `${cdk.Aws.ACCOUNT_ID}/${this.sqsQueue.queueName}`, apiGatewayRole: this.apiGatewayRole, apiMethod: "GET", - apiResource: this.apiGateway.root, + apiResource: apiReadRequestResource, requestTemplate: readRequestTemplate, additionalRequestTemplates: props.additionalReadRequestTemplates, contentType: "'application/x-www-form-urlencoded'", @@ -278,14 +301,14 @@ export class ApiGatewayToSqs extends Construct { // Delete const deleteRequestTemplate = props.deleteRequestTemplate ?? this.defaultDeleteRequestTemplate; if (props.allowDeleteOperation && props.allowDeleteOperation === true) { - const apiGatewayResource = this.apiGateway.root.addResource('message'); + const apiDeleteRequestResource = this.apiGateway.root.addResource(props.deleteRequestPath ?? 'message'); this.addActionToPolicy("sqs:DeleteMessage"); defaults.addProxyMethodToApiResource({ service: "sqs", path: `${cdk.Aws.ACCOUNT_ID}/${this.sqsQueue.queueName}`, apiGatewayRole: this.apiGatewayRole, apiMethod: "DELETE", - apiResource: apiGatewayResource, + apiResource: apiDeleteRequestResource, requestTemplate: deleteRequestTemplate, additionalRequestTemplates: props.additionalDeleteRequestTemplates, contentType: "'application/x-www-form-urlencoded'", @@ -294,14 +317,14 @@ export class ApiGatewayToSqs extends Construct { } } private CheckReadRequestProps(props: ApiGatewayToSqsProps): boolean { - if ((props.readRequestTemplate || props.additionalReadRequestTemplates || props.readIntegrationResponses) + if ((props.readRequestTemplate || props.additionalReadRequestTemplates || props.readIntegrationResponses || props.readRequestPath) && props.allowReadOperation === false) { return true; } return false; } private CheckDeleteRequestProps(props: ApiGatewayToSqsProps): boolean { - if ((props.deleteRequestTemplate || props.additionalDeleteRequestTemplates || props.deleteIntegrationResponses) + if ((props.deleteRequestTemplate || props.additionalDeleteRequestTemplates || props.deleteIntegrationResponses || props.deleteRequestPath) && props.allowDeleteOperation !== true) { return true; } @@ -309,7 +332,7 @@ export class ApiGatewayToSqs extends Construct { } private CheckCreateRequestProps(props: ApiGatewayToSqsProps): boolean { - if ((props.createRequestTemplate || props.additionalCreateRequestTemplates || props.createIntegrationResponses) + if ((props.createRequestTemplate || props.additionalCreateRequestTemplates || props.createIntegrationResponses || props.createRequestPath) && props.allowCreateOperation !== true) { return true; } diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/apigateway-sqs.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/apigateway-sqs.test.ts index 685a3f02c..fcfc5a567 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/apigateway-sqs.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/apigateway-sqs.test.ts @@ -69,7 +69,7 @@ test('Test properties', () => { deployDeadLetterQueue: true, maxReceiveCount: 3 }); - // Assertion 1 + // Assertion 1 expect(pattern.apiGateway).toBeDefined(); // Assertion 2 expect(pattern.sqsQueue).toBeDefined(); @@ -163,6 +163,45 @@ test('Test deployment for override ApiGateway deleteRequestTemplate', () => { }); }); +test('Test deployment for override ApiGateway createRequestPath', () => { + const stack = new Stack(); + + new ApiGatewayToSqs(stack, 'api-gateway-sqs', { + createRequestPath: "testPath", + allowCreateOperation: true + }); + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::ApiGateway::Resource', { + PathPart: "testPath" + }); +}); + +test('Test deployment for override ApiGateway getRequestPath', () => { + const stack = new Stack(); + + new ApiGatewayToSqs(stack, 'api-gateway-sqs', { + readRequestPath: "testPath", + allowReadOperation: true + }); + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::ApiGateway::Resource', { + PathPart: "testPath" + }); +}); + +test('Test deployment for for override ApiGateway deleteRequestTemplate', () => { + const stack = new Stack(); + + new ApiGatewayToSqs(stack, 'api-gateway-sqs', { + allowDeleteOperation: true, + deleteRequestPath: "testPath" + }); + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::ApiGateway::Resource', { + PathPart: "testPath" + }); +}); + test('Test deployment for disallow delete operation', () => { const stack = new Stack();