Skip to content

Commit 6469412

Browse files
authored
feat(sqs): throw ValidationError instead of untyped errors (#33046)
### Issue `aws-sqs` for #32569 ### Description of changes ValidationErrors everywhere ### Describe any new or updated permissions being added n/a ### Description of how you validated changes Existing tests. Exemptions granted as this is basically a refactor of existing code. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent e256814 commit 6469412

File tree

4 files changed

+36
-26
lines changed

4 files changed

+36
-26
lines changed

packages/aws-cdk-lib/.eslintrc.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,15 @@ baseConfig.rules['import/no-extraneous-dependencies'] = [
1515

1616

1717
// no-throw-default-error
18-
const modules = ['aws-s3', 'aws-lambda', 'aws-rds', 'aws-sns'];
18+
const enableNoThrowDefaultErrorIn = [
19+
'aws-lambda',
20+
'aws-rds',
21+
'aws-s3',
22+
'aws-sns',
23+
'aws-sqs',
24+
];
1925
baseConfig.overrides.push({
20-
files: modules.map(m => `./${m}/lib/**`),
26+
files: enableNoThrowDefaultErrorIn.map(m => `./${m}/lib/**`),
2127
rules: { "@cdklabs/no-throw-default-error": ['error'] },
2228
});
2329

packages/aws-cdk-lib/aws-sqs/lib/policy.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { IQueue } from './queue-base';
33
import { CfnQueuePolicy } from './sqs.generated';
44
import { PolicyDocument } from '../../aws-iam';
55
import { Resource } from '../../core';
6+
import { ValidationError } from '../../core/lib/errors';
67

78
/**
89
* Properties to associate SQS queues with a policy
@@ -51,6 +52,6 @@ export class QueuePolicy extends Resource {
5152
* @attribute
5253
*/
5354
public get queuePolicyId(): string {
54-
throw new Error('QueuePolicy.queuePolicyId has been removed from CloudFormation');
55+
throw new ValidationError('QueuePolicy.queuePolicyId has been removed from CloudFormation', this);
5556
}
5657
}

packages/aws-cdk-lib/aws-sqs/lib/queue.ts

+14-13
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { validateProps } from './validate-props';
55
import * as iam from '../../aws-iam';
66
import * as kms from '../../aws-kms';
77
import { Duration, RemovalPolicy, Stack, Token, ArnFormat, Annotations } from '../../core';
8+
import { ValidationError } from '../../core/lib/errors';
89

910
/**
1011
* Properties for creating a new Queue
@@ -325,10 +326,10 @@ export class Queue extends QueueBase {
325326
} else {
326327
if (typeof attrs.fifo !== 'undefined') {
327328
if (attrs.fifo && !queueName.endsWith('.fifo')) {
328-
throw new Error("FIFO queue names must end in '.fifo'");
329+
throw new ValidationError("FIFO queue names must end in '.fifo'", this);
329330
}
330331
if (!attrs.fifo && queueName.endsWith('.fifo')) {
331-
throw new Error("Non-FIFO queue name may not end in '.fifo'");
332+
throw new ValidationError("Non-FIFO queue name may not end in '.fifo'", this);
332333
}
333334
}
334335
return queueName.endsWith('.fifo') ? true : false;
@@ -383,19 +384,19 @@ export class Queue extends QueueBase {
383384
physicalName: props.queueName,
384385
});
385386

386-
validateProps(props);
387+
validateProps(this, props);
387388

388389
if (props.redriveAllowPolicy) {
389390
const { redrivePermission, sourceQueues } = props.redriveAllowPolicy;
390391
if (redrivePermission === RedrivePermission.BY_QUEUE) {
391392
if (!sourceQueues || sourceQueues.length === 0) {
392-
throw new Error('At least one source queue must be specified when RedrivePermission is set to \'byQueue\'');
393+
throw new ValidationError('At least one source queue must be specified when RedrivePermission is set to \'byQueue\'', this);
393394
}
394395
if (sourceQueues && sourceQueues.length > 10) {
395-
throw new Error('Up to 10 sourceQueues can be specified. Set RedrivePermission to \'allowAll\' to specify more');
396+
throw new ValidationError('Up to 10 sourceQueues can be specified. Set RedrivePermission to \'allowAll\' to specify more', this);
396397
}
397398
} else if (redrivePermission && sourceQueues) {
398-
throw new Error('sourceQueues cannot be configured when RedrivePermission is set to \'allowAll\' or \'denyAll\'');
399+
throw new ValidationError('sourceQueues cannot be configured when RedrivePermission is set to \'allowAll\' or \'denyAll\'', this);
399400
}
400401
}
401402

@@ -452,7 +453,7 @@ export class Queue extends QueueBase {
452453
let encryption = props.encryption;
453454

454455
if (encryption === QueueEncryption.SQS_MANAGED && props.encryptionMasterKey) {
455-
throw new Error("'encryptionMasterKey' is not supported if encryption type 'SQS_MANAGED' is used");
456+
throw new ValidationError("'encryptionMasterKey' is not supported if encryption type 'SQS_MANAGED' is used", this);
456457
}
457458

458459
if (encryption !== QueueEncryption.KMS && props.encryptionMasterKey) {
@@ -513,7 +514,7 @@ export class Queue extends QueueBase {
513514
};
514515
}
515516

516-
throw new Error(`Unexpected 'encryptionType': ${encryption}`);
517+
throw new ValidationError(`Unexpected 'encryptionType': ${encryption}`, this);
517518
}
518519

519520
// Enforce encryption of data in transit
@@ -537,23 +538,23 @@ export class Queue extends QueueBase {
537538
// If we have a name, see that it agrees with the FIFO setting
538539
if (typeof queueName === 'string') {
539540
if (fifoQueue && !queueName.endsWith('.fifo')) {
540-
throw new Error("FIFO queue names must end in '.fifo'");
541+
throw new ValidationError("FIFO queue names must end in '.fifo'", this);
541542
}
542543
if (!fifoQueue && queueName.endsWith('.fifo')) {
543-
throw new Error("Non-FIFO queue name may not end in '.fifo'");
544+
throw new ValidationError("Non-FIFO queue name may not end in '.fifo'", this);
544545
}
545546
}
546547

547548
if (props.contentBasedDeduplication && !fifoQueue) {
548-
throw new Error('Content-based deduplication can only be defined for FIFO queues');
549+
throw new ValidationError('Content-based deduplication can only be defined for FIFO queues', this);
549550
}
550551

551552
if (props.deduplicationScope && !fifoQueue) {
552-
throw new Error('Deduplication scope can only be defined for FIFO queues');
553+
throw new ValidationError('Deduplication scope can only be defined for FIFO queues', this);
553554
}
554555

555556
if (props.fifoThroughputLimit && !fifoQueue) {
556-
throw new Error('FIFO throughput limit can only be defined for FIFO queues');
557+
throw new ValidationError('FIFO throughput limit can only be defined for FIFO queues', this);
557558
}
558559

559560
return {
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1+
import { Construct } from 'constructs';
12
import { QueueProps } from './index';
23
import { Token } from '../../core';
4+
import { ValidationError } from '../../core/lib/errors';
35

4-
export function validateProps(props: QueueProps) {
5-
validateRange('delivery delay', props.deliveryDelay && props.deliveryDelay.toSeconds(), 0, 900, 'seconds');
6-
validateRange('maximum message size', props.maxMessageSizeBytes, 1_024, 262_144, 'bytes');
7-
validateRange('message retention period', props.retentionPeriod && props.retentionPeriod.toSeconds(), 60, 1_209_600, 'seconds');
8-
validateRange('receive wait time', props.receiveMessageWaitTime && props.receiveMessageWaitTime.toSeconds(), 0, 20, 'seconds');
9-
validateRange('visibility timeout', props.visibilityTimeout && props.visibilityTimeout.toSeconds(), 0, 43_200, 'seconds');
10-
validateRange('dead letter target maximum receive count', props.deadLetterQueue && props.deadLetterQueue.maxReceiveCount, 1, +Infinity);
6+
export function validateProps(scope: Construct, props: QueueProps) {
7+
validateRange(scope, 'delivery delay', props.deliveryDelay && props.deliveryDelay.toSeconds(), 0, 900, 'seconds');
8+
validateRange(scope, 'maximum message size', props.maxMessageSizeBytes, 1_024, 262_144, 'bytes');
9+
validateRange(scope, 'message retention period', props.retentionPeriod && props.retentionPeriod.toSeconds(), 60, 1_209_600, 'seconds');
10+
validateRange(scope, 'receive wait time', props.receiveMessageWaitTime && props.receiveMessageWaitTime.toSeconds(), 0, 20, 'seconds');
11+
validateRange(scope, 'visibility timeout', props.visibilityTimeout && props.visibilityTimeout.toSeconds(), 0, 43_200, 'seconds');
12+
validateRange(scope, 'dead letter target maximum receive count', props.deadLetterQueue && props.deadLetterQueue.maxReceiveCount, 1, +Infinity);
1113
}
1214

13-
function validateRange(label: string, value: number | undefined, minValue: number, maxValue: number, unit?: string) {
15+
function validateRange(scope: Construct, label: string, value: number | undefined, minValue: number, maxValue: number, unit?: string) {
1416
if (value === undefined || Token.isUnresolved(value)) { return; }
1517
const unitSuffix = unit ? ` ${unit}` : '';
16-
if (value < minValue) { throw new Error(`${label} must be ${minValue}${unitSuffix} or more, but ${value} was provided`); }
17-
if (value > maxValue) { throw new Error(`${label} must be ${maxValue}${unitSuffix} or less, but ${value} was provided`); }
18+
if (value < minValue) { throw new ValidationError(`${label} must be ${minValue}${unitSuffix} or more, but ${value} was provided`, scope); }
19+
if (value > maxValue) { throw new ValidationError(`${label} must be ${maxValue}${unitSuffix} or less, but ${value} was provided`, scope); }
1820
}

0 commit comments

Comments
 (0)