From f4fff9d4350ce2cfa38a88f2765776cb089bdc8c Mon Sep 17 00:00:00 2001 From: HBobertz Date: Wed, 22 Jan 2025 15:39:05 -0500 Subject: [PATCH 1/4] resolve conflicts --- packages/aws-cdk-lib/.eslintrc.js | 1 + .../aws-cdk-lib/aws-apigateway/lib/authorizers/cognito.ts | 5 +++-- .../aws-apigateway/lib/authorizers/identity-source.ts | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/aws-cdk-lib/.eslintrc.js b/packages/aws-cdk-lib/.eslintrc.js index a54c29ef2583d..10ca6be2d97a1 100644 --- a/packages/aws-cdk-lib/.eslintrc.js +++ b/packages/aws-cdk-lib/.eslintrc.js @@ -25,6 +25,7 @@ const enableNoThrowDefaultErrorIn = [ 'aws-ssmcontacts', 'aws-ssmincidents', 'aws-ssmquicksetup', + 'aws-apigateway', ]; baseConfig.overrides.push({ files: enableNoThrowDefaultErrorIn.map(m => `./${m}/lib/**`), diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/cognito.ts b/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/cognito.ts index 46b4348dcddb2..22e7872f40073 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/cognito.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/cognito.ts @@ -2,6 +2,7 @@ import { Construct } from 'constructs'; import { IdentitySource } from './identity-source'; import * as cognito from '../../../aws-cognito'; import { Duration, FeatureFlags, Lazy, Names, Stack } from '../../../core'; +import { UnscopedValidationError } from '../../../core/lib/errors'; import { APIGATEWAY_AUTHORIZER_CHANGE_DEPLOYMENT_LOGICAL_ID } from '../../../cx-api'; import { CfnAuthorizer, CfnAuthorizerProps } from '../apigateway.generated'; import { Authorizer, IAuthorizer } from '../authorizer'; @@ -102,7 +103,7 @@ export class CognitoUserPoolsAuthorizer extends Authorizer implements IAuthorize */ public _attachToApi(restApi: IRestApi): void { if (this.restApiId && this.restApiId !== restApi.restApiId) { - throw new Error('Cannot attach authorizer to two different rest APIs'); + throw new UnscopedValidationError('Cannot attach authorizer to two different rest APIs'); } this.restApiId = restApi.restApiId; @@ -126,7 +127,7 @@ export class CognitoUserPoolsAuthorizer extends Authorizer implements IAuthorize return Lazy.string({ produce: () => { if (!this.restApiId) { - throw new Error(`Authorizer (${this.node.path}) must be attached to a RestApi`); + throw new UnscopedValidationError(`Authorizer (${this.node.path}) must be attached to a RestApi`); } return this.restApiId; }, diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/identity-source.ts b/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/identity-source.ts index 059363cf1d228..02254e0278603 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/identity-source.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/identity-source.ts @@ -1,3 +1,5 @@ +import { UnscopedValidationError } from '../../../core/lib/errors'; + /** * Represents an identity source. * @@ -47,7 +49,7 @@ export class IdentitySource { private static toString(source: string, type: string) { if (!source.trim()) { - throw new Error('IdentitySources must be a non-empty string.'); + throw new UnscopedValidationError('IdentitySources must be a non-empty string.'); } return `${type}.${source}`; From 0e88d95da4224bdbb8789e730300d847b698622f Mon Sep 17 00:00:00 2001 From: HBobertz Date: Wed, 22 Jan 2025 16:26:22 -0500 Subject: [PATCH 2/4] apigwv1 validation errors --- .../aws-apigateway/lib/access-log.ts | 3 ++- .../aws-apigateway/lib/api-definition.ts | 11 ++++---- .../aws-cdk-lib/aws-apigateway/lib/api-key.ts | 7 ++--- .../aws-apigateway/lib/authorizers/lambda.ts | 9 ++++--- .../aws-apigateway/lib/base-path-mapping.ts | 7 ++--- .../aws-apigateway/lib/deployment.ts | 3 ++- .../aws-apigateway/lib/domain-name.ts | 13 ++++----- .../aws-apigateway/lib/integration.ts | 15 ++++++----- .../aws-apigateway/lib/integrations/aws.ts | 3 ++- .../lib/integrations/stepfunctions.ts | 3 ++- .../aws-apigateway/lib/lambda-api.ts | 9 ++++--- .../aws-cdk-lib/aws-apigateway/lib/method.ts | 8 +++--- .../aws-apigateway/lib/resource.ts | 27 ++++++++++--------- .../aws-cdk-lib/aws-apigateway/lib/restapi.ts | 19 ++++++------- .../aws-cdk-lib/aws-apigateway/lib/stage.ts | 11 ++++---- .../aws-apigateway/lib/stepfunctions-api.ts | 5 ++-- .../aws-cdk-lib/aws-apigateway/lib/util.ts | 17 ++++++------ 17 files changed, 93 insertions(+), 77 deletions(-) diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/access-log.ts b/packages/aws-cdk-lib/aws-apigateway/lib/access-log.ts index 6a9fb027405d5..4ec472de5ed91 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/access-log.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/access-log.ts @@ -1,6 +1,7 @@ import { IStage } from './stage'; import * as firehose from '../../aws-kinesisfirehose'; import { ILogGroup } from '../../aws-logs'; +import { UnscopedValidationError } from '../../core/lib/errors'; /** * Access log destination for a RestApi Stage. @@ -51,7 +52,7 @@ export class FirehoseLogDestination implements IAccessLogDestination { */ public bind(_stage: IStage): AccessLogDestinationConfig { if (!this.stream.deliveryStreamName?.startsWith('amazon-apigateway-')) { - throw new Error(`Firehose delivery stream name for access log destination must begin with 'amazon-apigateway-', got '${this.stream.deliveryStreamName}'`); + throw new UnscopedValidationError(`Firehose delivery stream name for access log destination must begin with 'amazon-apigateway-', got '${this.stream.deliveryStreamName}'`); } return { destinationArn: this.stream.attrArn, diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/api-definition.ts b/packages/aws-cdk-lib/aws-apigateway/lib/api-definition.ts index d9072aba941ae..291e4864fc5a4 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/api-definition.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/api-definition.ts @@ -3,6 +3,7 @@ import { CfnRestApi } from './apigateway.generated'; import { IRestApi } from './restapi'; import * as s3 from '../../aws-s3'; import * as s3_assets from '../../aws-s3-assets'; +import { UnscopedValidationError, ValidationError } from '../../core/lib/errors'; import * as cxapi from '../../cx-api'; /** @@ -137,7 +138,7 @@ export class S3ApiDefinition extends ApiDefinition { super(); if (!bucket.bucketName) { - throw new Error('bucketName is undefined for the provided bucket'); + throw new ValidationError('bucketName is undefined for the provided bucket', bucket); } this.bucketName = bucket.bucketName; @@ -162,11 +163,11 @@ export class InlineApiDefinition extends ApiDefinition { super(); if (typeof(definition) !== 'object') { - throw new Error('definition should be of type object'); + throw new UnscopedValidationError('definition should be of type object'); } if (Object.keys(definition).length === 0) { - throw new Error('JSON definition cannot be empty'); + throw new UnscopedValidationError('JSON definition cannot be empty'); } } @@ -197,7 +198,7 @@ export class AssetApiDefinition extends ApiDefinition { } if (this.asset.isZipArchive) { - throw new Error(`Asset cannot be a .zip file or a directory (${this.path})`); + throw new ValidationError(`Asset cannot be a .zip file or a directory (${this.path})`, scope); } return { @@ -214,7 +215,7 @@ export class AssetApiDefinition extends ApiDefinition { } if (!this.asset) { - throw new Error('bindToResource() must be called after bind()'); + throw new ValidationError('bindToResource() must be called after bind()', scope); } const child = Node.of(restApi).defaultChild as CfnRestApi; diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/api-key.ts b/packages/aws-cdk-lib/aws-apigateway/lib/api-key.ts index d4b42fc6d3b0e..54c8b01bd7cdf 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/api-key.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/api-key.ts @@ -6,6 +6,7 @@ import { IStage } from './stage'; import { QuotaSettings, ThrottleSettings, UsagePlan, UsagePlanPerApiStage } from './usage-plan'; import * as iam from '../../aws-iam'; import { ArnFormat, IResource as IResourceBase, Resource, Stack } from '../../core'; +import { ValidationError } from '../../core/lib/errors'; /** * API keys are alphanumeric string values that you distribute to @@ -197,15 +198,15 @@ export class ApiKey extends ApiKeyBase { } if (resources && stages) { - throw new Error('Only one of "resources" or "stages" should be provided'); + throw new ValidationError('Only one of "resources" or "stages" should be provided', this); } return resources ? resources.map((resource: IRestApi) => { const restApi = resource; if (!restApi.deploymentStage) { - throw new Error('Cannot add an ApiKey to a RestApi that does not contain a "deploymentStage".\n'+ - 'Either set the RestApi.deploymentStage or create an ApiKey from a Stage'); + throw new ValidationError('Cannot add an ApiKey to a RestApi that does not contain a "deploymentStage".\n'+ + 'Either set the RestApi.deploymentStage or create an ApiKey from a Stage', this); } const restApiId = restApi.restApiId; const stageName = restApi.deploymentStage!.stageName.toString(); diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/lambda.ts b/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/lambda.ts index df124eb306291..fa44af6b653a7 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/lambda.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/authorizers/lambda.ts @@ -3,6 +3,7 @@ import { IdentitySource } from './identity-source'; import * as iam from '../../../aws-iam'; import * as lambda from '../../../aws-lambda'; import { Arn, ArnFormat, Duration, FeatureFlags, Lazy, Names, Stack } from '../../../core'; +import { ValidationError } from '../../../core/lib/errors'; import { APIGATEWAY_AUTHORIZER_CHANGE_DEPLOYMENT_LOGICAL_ID } from '../../../cx-api'; import { CfnAuthorizer, CfnAuthorizerProps } from '../apigateway.generated'; import { Authorizer, IAuthorizer } from '../authorizer'; @@ -80,7 +81,7 @@ abstract class LambdaAuthorizer extends Authorizer implements IAuthorizer { this.role = props.assumeRole; if (props.resultsCacheTtl && props.resultsCacheTtl?.toSeconds() > 3600) { - throw new Error('Lambda authorizer property \'resultsCacheTtl\' must not be greater than 3600 seconds (1 hour)'); + throw new ValidationError('Lambda authorizer property \'resultsCacheTtl\' must not be greater than 3600 seconds (1 hour)', scope); } } @@ -90,7 +91,7 @@ abstract class LambdaAuthorizer extends Authorizer implements IAuthorizer { */ public _attachToApi(restApi: IRestApi) { if (this.restApiId && this.restApiId !== restApi.restApiId) { - throw new Error('Cannot attach authorizer to two different rest APIs'); + throw new ValidationError('Cannot attach authorizer to two different rest APIs', this); } this.restApiId = restApi.restApiId; @@ -161,7 +162,7 @@ abstract class LambdaAuthorizer extends Authorizer implements IAuthorizer { return Lazy.string({ produce: () => { if (!this.restApiId) { - throw new Error(`Authorizer (${this.node.path}) must be attached to a RestApi`); + throw new ValidationError(`Authorizer (${this.node.path}) must be attached to a RestApi`, this); } return this.restApiId; }, @@ -275,7 +276,7 @@ export class RequestAuthorizer extends LambdaAuthorizer { super(scope, id, props); if ((props.resultsCacheTtl === undefined || props.resultsCacheTtl.toSeconds() !== 0) && props.identitySources.length === 0) { - throw new Error('At least one Identity Source is required for a REQUEST-based Lambda authorizer if caching is enabled.'); + throw new ValidationError('At least one Identity Source is required for a REQUEST-based Lambda authorizer if caching is enabled.', scope); } const restApiId = this.lazyRestApiId(); diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/base-path-mapping.ts b/packages/aws-cdk-lib/aws-apigateway/lib/base-path-mapping.ts index 005acd07c24a8..8547c4cc15f77 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/base-path-mapping.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/base-path-mapping.ts @@ -4,6 +4,7 @@ import { IDomainName } from './domain-name'; import { IRestApi, RestApiBase } from './restapi'; import { Stage } from './stage'; import { Resource, Token } from '../../core'; +import { ValidationError } from '../../core/lib/errors'; export interface BasePathMappingOptions { /** @@ -57,13 +58,13 @@ export class BasePathMapping extends Resource { if (props.basePath && !Token.isUnresolved(props.basePath)) { if (props.basePath.startsWith('/') || props.basePath.endsWith('/')) { - throw new Error(`A base path cannot start or end with /", received: ${props.basePath}`); + throw new ValidationError(`A base path cannot start or end with /", received: ${props.basePath}`, scope); } if (props.basePath.match(/\/{2,}/)) { - throw new Error(`A base path cannot have more than one consecutive /", received: ${props.basePath}`); + throw new ValidationError(`A base path cannot have more than one consecutive /", received: ${props.basePath}`, scope); } if (!props.basePath.match(/^[a-zA-Z0-9$_.+!*'()-/]+$/)) { - throw new Error(`A base path may only contain letters, numbers, and one of "$-_.+!*'()/", received: ${props.basePath}`); + throw new ValidationError(`A base path may only contain letters, numbers, and one of "$-_.+!*'()/", received: ${props.basePath}`, scope); } } diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts b/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts index c245f82769110..4c1b6f7adbf1a 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts @@ -3,6 +3,7 @@ import { CfnDeployment } from './apigateway.generated'; import { Method } from './method'; import { IRestApi, RestApi, SpecRestApi, RestApiBase } from './restapi'; import { Lazy, RemovalPolicy, Resource, CfnResource } from '../../core'; +import { UnscopedValidationError } from '../../core/lib/errors'; import { md5hash } from '../../core/lib/helpers-internal'; export interface DeploymentProps { @@ -168,7 +169,7 @@ class LatestDeploymentResource extends CfnDeployment { // if the construct is locked, it means we are already synthesizing and then // we can't modify the hash because we might have already calculated it. if (this.node.locked) { - throw new Error('Cannot modify the logical ID when the construct is locked'); + throw new UnscopedValidationError('Cannot modify the logical ID when the construct is locked'); } this.hashComponents.push(data); diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/domain-name.ts b/packages/aws-cdk-lib/aws-apigateway/lib/domain-name.ts index 4f4ae930983b1..02035a409c651 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/domain-name.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/domain-name.ts @@ -7,6 +7,7 @@ import * as apigwv2 from '../../aws-apigatewayv2'; import * as acm from '../../aws-certificatemanager'; import { IBucket } from '../../aws-s3'; import { IResource, Names, Resource, Token } from '../../core'; +import { ValidationError } from '../../core/lib/errors'; /** * Options for creating an api mapping @@ -144,7 +145,7 @@ export class DomainName extends Resource implements IDomainName { this.securityPolicy = props.securityPolicy; if (!Token.isUnresolved(props.domainName) && /[A-Z]/.test(props.domainName)) { - throw new Error(`Domain name does not support uppercase letters. Got: ${props.domainName}`); + throw new ValidationError(`Domain name does not support uppercase letters. Got: ${props.domainName}`, scope); } const mtlsConfig = this.configureMTLS(props.mtls); @@ -182,10 +183,10 @@ export class DomainName extends Resource implements IDomainName { private validateBasePath(path?: string): boolean { if (this.isMultiLevel(path)) { if (this.endpointType === EndpointType.EDGE) { - throw new Error('multi-level basePath is only supported when endpointType is EndpointType.REGIONAL'); + throw new ValidationError('multi-level basePath is only supported when endpointType is EndpointType.REGIONAL', this); } if (this.securityPolicy && this.securityPolicy !== SecurityPolicy.TLS_1_2) { - throw new Error('securityPolicy must be set to TLS_1_2 if multi-level basePath is provided'); + throw new ValidationError('securityPolicy must be set to TLS_1_2 if multi-level basePath is provided', this); } return true; } @@ -208,10 +209,10 @@ export class DomainName extends Resource implements IDomainName { */ public addBasePathMapping(targetApi: IRestApi, options: BasePathMappingOptions = { }): BasePathMapping { if (this.basePaths.has(options.basePath)) { - throw new Error(`DomainName ${this.node.id} already has a mapping for path ${options.basePath}`); + throw new ValidationError(`DomainName ${this.node.id} already has a mapping for path ${options.basePath}`, this); } if (this.isMultiLevel(options.basePath)) { - throw new Error('BasePathMapping does not support multi-level paths. Use "addApiMapping instead.'); + throw new ValidationError('BasePathMapping does not support multi-level paths. Use "addApiMapping instead.', this); } this.basePaths.add(options.basePath); @@ -237,7 +238,7 @@ export class DomainName extends Resource implements IDomainName { */ public addApiMapping(targetStage: IStage, options: ApiMappingOptions = {}): void { if (this.basePaths.has(options.basePath)) { - throw new Error(`DomainName ${this.node.id} already has a mapping for path ${options.basePath}`); + throw new ValidationError(`DomainName ${this.node.id} already has a mapping for path ${options.basePath}`, this); } this.validateBasePath(options.basePath); this.basePaths.add(options.basePath); diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/integration.ts b/packages/aws-cdk-lib/aws-apigateway/lib/integration.ts index 8aa0700854601..fe02f36d32bee 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/integration.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/integration.ts @@ -2,6 +2,7 @@ import { Method } from './method'; import { IVpcLink, VpcLink } from './vpc-link'; import * as iam from '../../aws-iam'; import { Lazy, Duration } from '../../core'; +import { UnscopedValidationError } from '../../core/lib/errors'; export interface IntegrationOptions { /** @@ -199,23 +200,23 @@ export class Integration { constructor(private readonly props: IntegrationProps) { const options = this.props.options || { }; if (options.credentialsPassthrough !== undefined && options.credentialsRole !== undefined) { - throw new Error('\'credentialsPassthrough\' and \'credentialsRole\' are mutually exclusive'); + throw new UnscopedValidationError('\'credentialsPassthrough\' and \'credentialsRole\' are mutually exclusive'); } if (options.connectionType === ConnectionType.VPC_LINK && options.vpcLink === undefined) { - throw new Error('\'connectionType\' of VPC_LINK requires \'vpcLink\' prop to be set'); + throw new UnscopedValidationError('\'connectionType\' of VPC_LINK requires \'vpcLink\' prop to be set'); } if (options.connectionType === ConnectionType.INTERNET && options.vpcLink !== undefined) { - throw new Error('cannot set \'vpcLink\' where \'connectionType\' is INTERNET'); + throw new UnscopedValidationError('cannot set \'vpcLink\' where \'connectionType\' is INTERNET'); } if (options.timeout && !options.timeout.isUnresolved() && options.timeout.toMilliseconds() < 50) { - throw new Error('Integration timeout must be greater than 50 milliseconds.'); + throw new UnscopedValidationError('Integration timeout must be greater than 50 milliseconds.'); } if (props.type !== IntegrationType.MOCK && !props.integrationHttpMethod) { - throw new Error('integrationHttpMethod is required for non-mock integration types.'); + throw new UnscopedValidationError('integrationHttpMethod is required for non-mock integration types.'); } } @@ -235,12 +236,12 @@ export class Integration { if (vpcLink instanceof VpcLink) { const targets = vpcLink._targetDnsNames; if (targets.length > 1) { - throw new Error("'uri' is required when there are more than one NLBs in the VPC Link"); + throw new UnscopedValidationError("'uri' is required when there are more than one NLBs in the VPC Link"); } else { return `http://${targets[0]}`; } } else { - throw new Error("'uri' is required when the 'connectionType' is VPC_LINK"); + throw new UnscopedValidationError("'uri' is required when the 'connectionType' is VPC_LINK"); } }, }); diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/integrations/aws.ts b/packages/aws-cdk-lib/aws-apigateway/lib/integrations/aws.ts index 50a916f6b074a..ec94ef6de5771 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/integrations/aws.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/integrations/aws.ts @@ -1,6 +1,7 @@ import { IConstruct } from 'constructs'; import * as cdk from '../../../core'; import { ArnFormat } from '../../../core'; +import { UnscopedValidationError } from '../../../core/lib/errors'; import { Integration, IntegrationConfig, IntegrationOptions, IntegrationType } from '../integration'; import { Method } from '../method'; import { parseAwsApiCall } from '../util'; @@ -89,7 +90,7 @@ export class AwsIntegration extends Integration { integrationHttpMethod: props.integrationHttpMethod || 'POST', uri: cdk.Lazy.string({ produce: () => { - if (!this.scope) { throw new Error('AwsIntegration must be used in API'); } + if (!this.scope) { throw new UnscopedValidationError('AwsIntegration must be used in API'); } return cdk.Stack.of(this.scope).formatArn({ service: 'apigateway', account: backend, diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/integrations/stepfunctions.ts b/packages/aws-cdk-lib/aws-apigateway/lib/integrations/stepfunctions.ts index d37febc7ef807..6a575ee3ff321 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/integrations/stepfunctions.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/integrations/stepfunctions.ts @@ -5,6 +5,7 @@ import { AwsIntegration } from './aws'; import * as iam from '../../../aws-iam'; import * as sfn from '../../../aws-stepfunctions'; import { Token } from '../../../core'; +import { UnscopedValidationError } from '../../../core/lib/errors'; import { IntegrationConfig, IntegrationOptions, PassthroughBehavior } from '../integration'; import { Method } from '../method'; import { Model } from '../model'; @@ -150,7 +151,7 @@ class StepFunctionsExecutionIntegration extends AwsIntegration { if (this.stateMachine instanceof sfn.StateMachine) { const stateMachineType = (this.stateMachine as sfn.StateMachine).stateMachineType; if (stateMachineType !== sfn.StateMachineType.EXPRESS) { - throw new Error('State Machine must be of type "EXPRESS". Please use StateMachineType.EXPRESS as the stateMachineType'); + throw new UnscopedValidationError('State Machine must be of type "EXPRESS". Please use StateMachineType.EXPRESS as the stateMachineType'); } //if not imported, extract the name from the CFN layer to reach the diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/lambda-api.ts b/packages/aws-cdk-lib/aws-apigateway/lib/lambda-api.ts index 6dbea4c17a12f..3ab88c3530cd3 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/lambda-api.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/lambda-api.ts @@ -5,6 +5,7 @@ import { Method } from './method'; import { ProxyResource, Resource } from './resource'; import { RestApi, RestApiProps } from './restapi'; import * as lambda from '../../aws-lambda'; +import { UnscopedValidationError, ValidationError } from '../../core/lib/errors'; export interface LambdaRestApiProps extends RestApiProps { /** @@ -52,7 +53,7 @@ export interface LambdaRestApiProps extends RestApiProps { export class LambdaRestApi extends RestApi { constructor(scope: Construct, id: string, props: LambdaRestApiProps) { if (props.options?.defaultIntegration || props.defaultIntegration) { - throw new Error('Cannot specify "defaultIntegration" since Lambda integration is automatically defined'); + throw new ValidationError('Cannot specify "defaultIntegration" since Lambda integration is automatically defined', scope); } super(scope, id, { @@ -86,13 +87,13 @@ export class LambdaRestApi extends RestApi { } function addResourceThrows(): Resource { - throw new Error('Cannot call \'addResource\' on a proxying LambdaRestApi; set \'proxy\' to false'); + throw new UnscopedValidationError('Cannot call \'addResource\' on a proxying LambdaRestApi; set \'proxy\' to false'); } function addMethodThrows(): Method { - throw new Error('Cannot call \'addMethod\' on a proxying LambdaRestApi; set \'proxy\' to false'); + throw new UnscopedValidationError('Cannot call \'addMethod\' on a proxying LambdaRestApi; set \'proxy\' to false'); } function addProxyThrows(): ProxyResource { - throw new Error('Cannot call \'addProxy\' on a proxying LambdaRestApi; set \'proxy\' to false'); + throw new UnscopedValidationError('Cannot call \'addProxy\' on a proxying LambdaRestApi; set \'proxy\' to false'); } diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/method.ts b/packages/aws-cdk-lib/aws-apigateway/lib/method.ts index 8f282d253dbcc..048bb22e4ec9e 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/method.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/method.ts @@ -14,8 +14,8 @@ import { validateHttpMethod } from './util'; import * as cloudwatch from '../../aws-cloudwatch'; import * as iam from '../../aws-iam'; import { Annotations, ArnFormat, FeatureFlags, Lazy, Names, Resource, Stack } from '../../core'; +import { ValidationError } from '../../core/lib/errors'; import { APIGATEWAY_REQUEST_VALIDATOR_UNIQUE_ID } from '../../cx-api'; - export interface MethodOptions { /** * A friendly operation name for the method. For example, you can assign the @@ -330,8 +330,8 @@ export class Method extends Resource { // if the authorizer defines an authorization type and we also have an explicit option set, check that they are the same if (authorizerAuthType && optionsAuthType && authorizerAuthType !== optionsAuthType) { - throw new Error(`${this.resource}/${this.httpMethod} - Authorization type is set to ${optionsAuthType} ` + - `which is different from what is required by the authorizer [${authorizerAuthType}]`); + throw new ValidationError(`${this.resource}/${this.httpMethod} - Authorization type is set to ${optionsAuthType} ` + + `which is different from what is required by the authorizer [${authorizerAuthType}]`, this); } return finalAuthType; @@ -408,7 +408,7 @@ export class Method extends Resource { private requestValidatorId(options: MethodOptions): string | undefined { if (options.requestValidator && options.requestValidatorOptions) { - throw new Error('Only one of \'requestValidator\' or \'requestValidatorOptions\' must be specified.'); + throw new ValidationError('Only one of \'requestValidator\' or \'requestValidatorOptions\' must be specified.', this); } if (options.requestValidatorOptions) { diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/resource.ts b/packages/aws-cdk-lib/aws-apigateway/lib/resource.ts index 16f6af41840ba..0ec1f170ba61f 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/resource.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/resource.ts @@ -6,6 +6,7 @@ import { MockIntegration } from './integrations'; import { Method, MethodOptions, AuthorizationType } from './method'; import { IRestApi, RestApi } from './restapi'; import { IResource as IResourceBase, Resource as ResourceConstruct } from '../../core'; +import { ValidationError } from '../../core/lib/errors'; export interface IResource extends IResourceBase { /** @@ -204,11 +205,11 @@ export abstract class ResourceBase extends ResourceConstruct implements IResourc // Access-Control-Allow-Origin if (options.allowOrigins.length === 0) { - throw new Error('allowOrigins must contain at least one origin'); + throw new ValidationError('allowOrigins must contain at least one origin', this); } if (options.allowOrigins.includes('*') && options.allowOrigins.length > 1) { - throw new Error(`Invalid "allowOrigins" - cannot mix "*" with specific origins: ${options.allowOrigins.join(',')}`); + throw new ValidationError(`Invalid "allowOrigins" - cannot mix "*" with specific origins: ${options.allowOrigins.join(',')}`, this); } // we use the first origin here and if there are more origins in the list, we @@ -229,7 +230,7 @@ export abstract class ResourceBase extends ResourceConstruct implements IResourc if (allowMethods.includes('ANY')) { if (allowMethods.length > 1) { - throw new Error(`ANY cannot be used with any other method. Received: ${allowMethods.join(',')}`); + throw new ValidationError(`ANY cannot be used with any other method. Received: ${allowMethods.join(',')}`, this); } allowMethods = Cors.ALL_METHODS; @@ -250,7 +251,7 @@ export abstract class ResourceBase extends ResourceConstruct implements IResourc let maxAgeSeconds; if (options.maxAge && options.disableCache) { - throw new Error('The options "maxAge" and "disableCache" are mutually exclusive'); + throw new ValidationError('The options "maxAge" and "disableCache" are mutually exclusive', this); } if (options.maxAge) { @@ -353,7 +354,7 @@ export abstract class ResourceBase extends ResourceConstruct implements IResourc if (path.startsWith('/')) { if (this.path !== '/') { - throw new Error(`Path may start with "/" only for the resource, but we are at: ${this.path}`); + throw new ValidationError(`Path may start with "/" only for the resource, but we are at: ${this.path}`, this); } // trim trailing "/" @@ -363,7 +364,7 @@ export abstract class ResourceBase extends ResourceConstruct implements IResourc const parts = path.split('/'); const next = parts.shift(); if (!next || next === '') { - throw new Error('resourceForPath cannot be called with an empty path'); + throw new ValidationError('resourceForPath cannot be called with an empty path', this); } let resource = this.getResource(next); @@ -416,11 +417,11 @@ export class Resource extends ResourceBase { public readonly defaultCorsPreflightOptions?: CorsOptions = undefined; public get parentResource(): IResource { - throw new Error('parentResource is not configured for imported resource.'); + throw new ValidationError('parentResource is not configured for imported resource.', scope); } public get restApi(): RestApi { - throw new Error('restApi is not configured for imported resource.'); + throw new ValidationError('restApi is not configured for imported resource.', scope); } } @@ -439,7 +440,7 @@ export class Resource extends ResourceBase { constructor(scope: Construct, id: string, props: ResourceProps) { super(scope, id); - validateResourcePathPart(props.pathPart); + validateResourcePathPart(props.pathPart, scope); this.parentResource = props.parent; @@ -488,7 +489,7 @@ export class Resource extends ResourceBase { */ public get restApi(): RestApi { if (!this.parentResource) { - throw new Error('parentResource was unexpectedly not defined'); + throw new ValidationError('parentResource was unexpectedly not defined', this); } return this.parentResource.restApi; } @@ -550,7 +551,7 @@ export class ProxyResource extends Resource { } } -function validateResourcePathPart(part: string) { +function validateResourcePathPart(part: string, scope: Construct) { // strip {} which indicate this is a parameter if (part.startsWith('{') && part.endsWith('}')) { part = part.slice(1, -1); @@ -562,7 +563,7 @@ function validateResourcePathPart(part: string) { } if (!/^[a-zA-Z0-9:\.\_\-\$]+$/.test(part)) { - throw new Error(`Resource's path part only allow [a-zA-Z0-9:._-$], an optional trailing '+' - and curly braces at the beginning and the end: ${part}`); + throw new ValidationError(`Resource's path part only allow [a-zA-Z0-9:._-$], an optional trailing '+' + and curly braces at the beginning and the end: ${part}`, scope); } } diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/restapi.ts b/packages/aws-cdk-lib/aws-apigateway/lib/restapi.ts index 32dca38262529..15758f7caabb0 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/restapi.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/restapi.ts @@ -18,6 +18,7 @@ import * as cloudwatch from '../../aws-cloudwatch'; import { IVpcEndpoint } from '../../aws-ec2'; import * as iam from '../../aws-iam'; import { ArnFormat, CfnOutput, IResource as IResourceBase, Resource, Stack, Token, FeatureFlags, RemovalPolicy, Size } from '../../core'; +import { ValidationError } from '../../core/lib/errors'; import { APIGATEWAY_DISABLE_CLOUDWATCH_ROLE } from '../../cx-api'; const RESTAPI_SYMBOL = Symbol.for('@aws-cdk/aws-apigateway.RestApiBase'); @@ -388,7 +389,7 @@ export abstract class RestApiBase extends Resource implements IRestApi { */ public urlForPath(path: string = '/'): string { if (!this.deploymentStage) { - throw new Error('Cannot determine deployment stage for API from "deploymentStage". Use "deploy" or explicitly set "deploymentStage"'); + throw new ValidationError('Cannot determine deployment stage for API from "deploymentStage". Use "deploy" or explicitly set "deploymentStage"', this); } return this.deploymentStage.urlForPath(path); @@ -419,7 +420,7 @@ export abstract class RestApiBase extends Resource implements IRestApi { public arnForExecuteApi(method: string = '*', path: string = '/*', stage: string = '*') { if (!Token.isUnresolved(path) && !path.startsWith('/')) { - throw new Error(`"path" must begin with a "/": '${path}'`); + throw new ValidationError(`"path" must begin with a "/": '${path}'`, this); } if (method.toUpperCase() === 'ANY') { @@ -578,7 +579,7 @@ export abstract class RestApiBase extends Resource implements IRestApi { cloudWatchRole = cloudWatchRole ?? cloudWatchRoleDefault; if (!cloudWatchRole) { if (cloudWatchRoleRemovalPolicy) { - throw new Error('\'cloudWatchRole\' must be enabled for \'cloudWatchRoleRemovalPolicy\' to be applied.'); + throw new ValidationError('\'cloudWatchRole\' must be enabled for \'cloudWatchRoleRemovalPolicy\' to be applied.', this); } return; } @@ -638,7 +639,7 @@ export abstract class RestApiBase extends Resource implements IRestApi { new CfnOutput(this, 'Endpoint', { exportName: props.endpointExportName, value: this.urlForPath() }); } else { if (props.deployOptions) { - throw new Error('Cannot set \'deployOptions\' if \'deploy\' is disabled'); + throw new ValidationError('Cannot set \'deployOptions\' if \'deploy\' is disabled', this); } } } @@ -648,7 +649,7 @@ export abstract class RestApiBase extends Resource implements IRestApi { */ protected _configureEndpoints(props: RestApiProps): CfnRestApi.EndpointConfigurationProperty | undefined { if (props.endpointTypes && props.endpointConfiguration) { - throw new Error('Only one of the RestApi props, endpointTypes or endpointConfiguration, is allowed'); + throw new ValidationError('Only one of the RestApi props, endpointTypes or endpointConfiguration, is allowed', this); } if (props.endpointConfiguration) { return { @@ -776,11 +777,11 @@ export class RestApi extends RestApiBase { public readonly restApiId = restApiId; public get root(): IResource { - throw new Error('root is not configured when imported using `fromRestApiId()`. Use `fromRestApiAttributes()` API instead.'); + throw new ValidationError('root is not configured when imported using `fromRestApiId()`. Use `fromRestApiAttributes()` API instead.', scope); } public get restApiRootResourceId(): string { - throw new Error('restApiRootResourceId is not configured when imported using `fromRestApiId()`. Use `fromRestApiAttributes()` API instead.'); + throw new ValidationError('restApiRootResourceId is not configured when imported using `fromRestApiId()`. Use `fromRestApiAttributes()` API instead.', scope); } } @@ -821,7 +822,7 @@ export class RestApi extends RestApiBase { super(scope, id, props); if (props.minCompressionSize !== undefined && props.minimumCompressionSize !== undefined) { - throw new Error('both properties minCompressionSize and minimumCompressionSize cannot be set at once.'); + throw new ValidationError('both properties minCompressionSize and minimumCompressionSize cannot be set at once.', scope); } const resource = new CfnRestApi(this, 'Resource', { @@ -1007,7 +1008,7 @@ class RootResource extends ResourceBase { */ public get restApi(): RestApi { if (!this._restApi) { - throw new Error('RestApi is not available on Resource not connected to an instance of RestApi. Use `api` instead'); + throw new ValidationError('RestApi is not available on Resource not connected to an instance of RestApi. Use `api` instead', this); } return this._restApi; } diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts b/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts index 266ea23df121d..58933032a0b67 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts @@ -8,6 +8,7 @@ import { IRestApi, RestApiBase } from './restapi'; import { parseMethodOptionsPath } from './util'; import * as cloudwatch from '../../aws-cloudwatch'; import { ArnFormat, Duration, IResource, Resource, Stack, Token } from '../../core'; +import { UnscopedValidationError, ValidationError } from '../../core/lib/errors'; /** * Represents an APIGateway Stage. @@ -241,7 +242,7 @@ export abstract class StageBase extends Resource implements IStage { */ public urlForPath(path: string = '/') { if (!path.startsWith('/')) { - throw new Error(`Path must begin with "/": ${path}`); + throw new ValidationError(`Path must begin with "/": ${path}`, this); } return `https://${this.restApi.restApiId}.execute-api.${Stack.of(this).region}.${Stack.of(this).urlSuffix}/${this.stageName}${path}`; } @@ -391,10 +392,10 @@ export class Stage extends StageBase { !Token.isUnresolved(accessLogFormat.toString()) && !/.*\$context.(requestId|extendedRequestId)\b.*/.test(accessLogFormat.toString())) { - throw new Error('Access log must include either `AccessLogFormat.contextRequestId()` or `AccessLogFormat.contextExtendedRequestId()`'); + throw new ValidationError('Access log must include either `AccessLogFormat.contextRequestId()` or `AccessLogFormat.contextExtendedRequestId()`', this); } if (accessLogFormat !== undefined && accessLogDestination === undefined) { - throw new Error('Access log format is specified without a destination'); + throw new ValidationError('Access log format is specified without a destination', this); } accessLogSetting = { @@ -408,7 +409,7 @@ export class Stage extends StageBase { if (this.enableCacheCluster === undefined) { this.enableCacheCluster = true; } else if (this.enableCacheCluster === false) { - throw new Error(`Cannot set "cacheClusterSize" to ${props.cacheClusterSize} and "cacheClusterEnabled" to "false"`); + throw new ValidationError(`Cannot set "cacheClusterSize" to ${props.cacheClusterSize} and "cacheClusterEnabled" to "false"`, this); } } @@ -471,7 +472,7 @@ export class Stage extends StageBase { if (self.enableCacheCluster === undefined) { self.enableCacheCluster = true; } else if (self.enableCacheCluster === false) { - throw new Error(`Cannot enable caching for method ${path} since cache cluster is disabled on stage`); + throw new UnscopedValidationError(`Cannot enable caching for method ${path} since cache cluster is disabled on stage`); } } diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/stepfunctions-api.ts b/packages/aws-cdk-lib/aws-apigateway/lib/stepfunctions-api.ts index 3175d852920d8..27fb4c179c2fc 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/stepfunctions-api.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/stepfunctions-api.ts @@ -4,6 +4,7 @@ import { RequestContext } from './integrations'; import { StepFunctionsIntegration } from './integrations/stepfunctions'; import * as iam from '../../aws-iam'; import * as sfn from '../../aws-stepfunctions'; +import { ValidationError } from '../../core/lib/errors'; /** * Properties for StepFunctionsRestApi @@ -111,11 +112,11 @@ export interface StepFunctionsRestApiProps extends RestApiProps { export class StepFunctionsRestApi extends RestApi { constructor(scope: Construct, id: string, props: StepFunctionsRestApiProps) { if (props.defaultIntegration) { - throw new Error('Cannot specify "defaultIntegration" since Step Functions integration is automatically defined'); + throw new ValidationError('Cannot specify "defaultIntegration" since Step Functions integration is automatically defined', scope); } if ((props.stateMachine.node.defaultChild as sfn.CfnStateMachine).stateMachineType !== sfn.StateMachineType.EXPRESS) { - throw new Error('State Machine must be of type "EXPRESS". Please use StateMachineType.EXPRESS as the stateMachineType'); + throw new ValidationError('State Machine must be of type "EXPRESS". Please use StateMachineType.EXPRESS as the stateMachineType', scope); } const stepfunctionsIntegration = StepFunctionsIntegration.startExecution(props.stateMachine, { diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/util.ts b/packages/aws-cdk-lib/aws-apigateway/lib/util.ts index 166f59de99ec0..912ca0d6e33c2 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/util.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/util.ts @@ -1,5 +1,6 @@ import { format as formatUrl } from 'url'; import * as jsonSchema from './json-schema'; +import { UnscopedValidationError } from '../../core/lib/errors'; export const ALL_METHODS = ['OPTIONS', 'GET', 'PUT', 'POST', 'DELETE', 'PATCH', 'HEAD']; @@ -7,13 +8,13 @@ const ALLOWED_METHODS = ['ANY', ...ALL_METHODS]; export function validateHttpMethod(method: string, messagePrefix: string = '') { if (!ALLOWED_METHODS.includes(method)) { - throw new Error(`${messagePrefix}Invalid HTTP method "${method}". Allowed methods: ${ALLOWED_METHODS.join(',')}`); + throw new UnscopedValidationError(`${messagePrefix}Invalid HTTP method "${method}". Allowed methods: ${ALLOWED_METHODS.join(',')}`); } } export function parseMethodOptionsPath(originalPath: string): { resourcePath: string; httpMethod: string } { if (!originalPath.startsWith('/')) { - throw new Error(`Method options path must start with '/': ${originalPath}`); + throw new UnscopedValidationError(`Method options path must start with '/': ${originalPath}`); } const path = originalPath.slice(1); // trim trailing '/' @@ -21,7 +22,7 @@ export function parseMethodOptionsPath(originalPath: string): { resourcePath: st const components = path.split('/'); if (components.length < 2) { - throw new Error(`Method options path must include at least two components: /{resource}/{method} (i.e. /foo/bar/GET): ${path}`); + throw new UnscopedValidationError(`Method options path must include at least two components: /{resource}/{method} (i.e. /foo/bar/GET): ${path}`); } const httpMethod = components.pop()!.toUpperCase(); // last component is an HTTP method @@ -44,11 +45,11 @@ export function parseMethodOptionsPath(originalPath: string): { resourcePath: st export function parseAwsApiCall(path?: string, action?: string, actionParams?: { [key: string]: string }): { apiType: string; apiValue: string } { if (actionParams && !action) { - throw new Error('"actionParams" requires that "action" will be set'); + throw new UnscopedValidationError('"actionParams" requires that "action" will be set'); } if (path && action) { - throw new Error(`"path" and "action" are mutually exclusive (path="${path}", action="${action}")`); + throw new UnscopedValidationError(`"path" and "action" are mutually exclusive (path="${path}", action="${action}")`); } if (path) { @@ -69,18 +70,18 @@ export function parseAwsApiCall(path?: string, action?: string, actionParams?: { }; } - throw new Error('Either "path" or "action" are required'); + throw new UnscopedValidationError('Either "path" or "action" are required'); } export function validateInteger(property: number | undefined, messagePrefix: string) { if (property && !Number.isInteger(property)) { - throw new Error(`${messagePrefix} should be an integer`); + throw new UnscopedValidationError(`${messagePrefix} should be an integer`); } } export function validateDouble(property: number | undefined, messagePrefix: string) { if (property && isNaN(property) && isNaN(parseFloat(property.toString()))) { - throw new Error(`${messagePrefix} should be an double`); + throw new UnscopedValidationError(`${messagePrefix} should be an double`); } } From e857045449d0ecfb1121b492e094de357513fc3b Mon Sep 17 00:00:00 2001 From: HBobertz Date: Fri, 24 Jan 2025 00:15:14 -0500 Subject: [PATCH 3/4] address feedback --- packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts | 4 ++-- packages/aws-cdk-lib/aws-apigateway/lib/integration.ts | 8 ++++---- .../aws-apigateway/lib/integrations/stepfunctions.ts | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts b/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts index 4c1b6f7adbf1a..ee2111d8ce067 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/deployment.ts @@ -3,7 +3,7 @@ import { CfnDeployment } from './apigateway.generated'; import { Method } from './method'; import { IRestApi, RestApi, SpecRestApi, RestApiBase } from './restapi'; import { Lazy, RemovalPolicy, Resource, CfnResource } from '../../core'; -import { UnscopedValidationError } from '../../core/lib/errors'; +import { ValidationError } from '../../core/lib/errors'; import { md5hash } from '../../core/lib/helpers-internal'; export interface DeploymentProps { @@ -169,7 +169,7 @@ class LatestDeploymentResource extends CfnDeployment { // if the construct is locked, it means we are already synthesizing and then // we can't modify the hash because we might have already calculated it. if (this.node.locked) { - throw new UnscopedValidationError('Cannot modify the logical ID when the construct is locked'); + throw new ValidationError('Cannot modify the logical ID when the construct is locked', this); } this.hashComponents.push(data); diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/integration.ts b/packages/aws-cdk-lib/aws-apigateway/lib/integration.ts index fe02f36d32bee..ad246c9034b30 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/integration.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/integration.ts @@ -2,7 +2,7 @@ import { Method } from './method'; import { IVpcLink, VpcLink } from './vpc-link'; import * as iam from '../../aws-iam'; import { Lazy, Duration } from '../../core'; -import { UnscopedValidationError } from '../../core/lib/errors'; +import { UnscopedValidationError, ValidationError } from '../../core/lib/errors'; export interface IntegrationOptions { /** @@ -224,7 +224,7 @@ export class Integration { * Can be overridden by subclasses to allow the integration to interact with the method * being integrated, access the REST API object, method ARNs, etc. */ - public bind(_method: Method): IntegrationConfig { + public bind(method: Method): IntegrationConfig { let uri = this.props.uri; const options = this.props.options; @@ -236,12 +236,12 @@ export class Integration { if (vpcLink instanceof VpcLink) { const targets = vpcLink._targetDnsNames; if (targets.length > 1) { - throw new UnscopedValidationError("'uri' is required when there are more than one NLBs in the VPC Link"); + throw new ValidationError("'uri' is required when there are more than one NLBs in the VPC Link", method); } else { return `http://${targets[0]}`; } } else { - throw new UnscopedValidationError("'uri' is required when the 'connectionType' is VPC_LINK"); + throw new ValidationError("'uri' is required when the 'connectionType' is VPC_LINK", method); } }, }); diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/integrations/stepfunctions.ts b/packages/aws-cdk-lib/aws-apigateway/lib/integrations/stepfunctions.ts index 6a575ee3ff321..70f5c03421631 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/integrations/stepfunctions.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/integrations/stepfunctions.ts @@ -5,7 +5,7 @@ import { AwsIntegration } from './aws'; import * as iam from '../../../aws-iam'; import * as sfn from '../../../aws-stepfunctions'; import { Token } from '../../../core'; -import { UnscopedValidationError } from '../../../core/lib/errors'; +import { ValidationError } from '../../../core/lib/errors'; import { IntegrationConfig, IntegrationOptions, PassthroughBehavior } from '../integration'; import { Method } from '../method'; import { Model } from '../model'; @@ -151,7 +151,7 @@ class StepFunctionsExecutionIntegration extends AwsIntegration { if (this.stateMachine instanceof sfn.StateMachine) { const stateMachineType = (this.stateMachine as sfn.StateMachine).stateMachineType; if (stateMachineType !== sfn.StateMachineType.EXPRESS) { - throw new UnscopedValidationError('State Machine must be of type "EXPRESS". Please use StateMachineType.EXPRESS as the stateMachineType'); + throw new ValidationError('State Machine must be of type "EXPRESS". Please use StateMachineType.EXPRESS as the stateMachineType', this.stateMachine); } //if not imported, extract the name from the CFN layer to reach the From 24120c9368ff4dc599f11b17eb4791adae08cdd2 Mon Sep 17 00:00:00 2001 From: HBobertz Date: Fri, 24 Jan 2025 00:28:39 -0500 Subject: [PATCH 4/4] add self --- packages/aws-cdk-lib/aws-apigateway/lib/stage.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts b/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts index 58933032a0b67..e96338fd4b286 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts @@ -8,7 +8,7 @@ import { IRestApi, RestApiBase } from './restapi'; import { parseMethodOptionsPath } from './util'; import * as cloudwatch from '../../aws-cloudwatch'; import { ArnFormat, Duration, IResource, Resource, Stack, Token } from '../../core'; -import { UnscopedValidationError, ValidationError } from '../../core/lib/errors'; +import { ValidationError } from '../../core/lib/errors'; /** * Represents an APIGateway Stage. @@ -472,7 +472,7 @@ export class Stage extends StageBase { if (self.enableCacheCluster === undefined) { self.enableCacheCluster = true; } else if (self.enableCacheCluster === false) { - throw new UnscopedValidationError(`Cannot enable caching for method ${path} since cache cluster is disabled on stage`); + throw new ValidationError(`Cannot enable caching for method ${path} since cache cluster is disabled on stage`, self); } }