Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/aws-cdk-lib/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const enableNoThrowDefaultErrorIn = [
'aws-apigatewayv2-authorizers',
'aws-apigatewayv2-integrations',
'aws-applicationautoscaling',
'aws-appsync',
'aws-cognito',
'aws-elasticloadbalancing',
'aws-elasticloadbalancingv2',
Expand Down
8 changes: 4 additions & 4 deletions packages/aws-cdk-lib/aws-appsync/lib/appsync-function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { BaseDataSource, LambdaDataSource } from './data-source';
import { IGraphqlApi } from './graphqlapi-base';
import { MappingTemplate } from './mapping-template';
import { FunctionRuntime } from './runtime';
import { Resource, IResource, Lazy, Fn } from '../../core';
import { Resource, IResource, Lazy, Fn, ValidationError } from '../../core';

/**
* the base properties for AppSync Functions
Expand Down Expand Up @@ -160,15 +160,15 @@ export class AppsyncFunction extends Resource implements IAppsyncFunction {

// If runtime is specified, code must also be
if (props.runtime && !props.code) {
throw new Error('Code is required when specifying a runtime');
throw new ValidationError('Code is required when specifying a runtime', scope);
}

if (props.code && (props.requestMappingTemplate || props.responseMappingTemplate)) {
throw new Error('Mapping templates cannot be used alongside code');
throw new ValidationError('Mapping templates cannot be used alongside code', scope);
}

if (props.maxBatchSize && !(props.dataSource instanceof LambdaDataSource)) {
throw new Error('maxBatchSize can only be set for the data source of type \LambdaDataSource\'');
throw new ValidationError('maxBatchSize can only be set for the data source of type \LambdaDataSource\'', scope);
}

const code = props.code?.bind(this);
Expand Down
6 changes: 3 additions & 3 deletions packages/aws-cdk-lib/aws-appsync/lib/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ export class AssetCode extends Code {
...this.options,
});
} else if (cdk.Stack.of(this.asset) !== cdk.Stack.of(scope)) {
throw new Error(`Asset is already associated with another stack '${cdk.Stack.of(this.asset).stackName}'. ` +
'Create a new Code instance for every stack.');
throw new cdk.ValidationError(`Asset is already associated with another stack '${cdk.Stack.of(this.asset).stackName}'. ` +
'Create a new Code instance for every stack.', scope);
}

return {
Expand All @@ -86,7 +86,7 @@ export class InlineCode extends Code {
super();

if (code.length === 0) {
throw new Error('AppSync Inline code cannot be empty');
throw new cdk.UnscopedValidationError('AppSync Inline code cannot be empty');
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/aws-cdk-lib/aws-appsync/lib/graphqlapi-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { IFunction } from '../../aws-lambda';
import { IDomain as IOpenSearchDomain } from '../../aws-opensearchservice';
import { IDatabaseCluster, IServerlessCluster } from '../../aws-rds';
import { ISecret } from '../../aws-secretsmanager';
import { ArnFormat, CfnResource, IResource, Resource, Stack } from '../../core';
import { ArnFormat, CfnResource, IResource, Resource, Stack, UnscopedValidationError } from '../../core';

/**
* Optional configuration for data sources
Expand Down Expand Up @@ -64,7 +64,7 @@ export class IamResource {
*/
public static custom(...arns: string[]): IamResource {
if (arns.length === 0) {
throw new Error('At least 1 custom ARN must be provided.');
throw new UnscopedValidationError('At least 1 custom ARN must be provided.');
}
return new IamResource(arns);
}
Expand Down
36 changes: 18 additions & 18 deletions packages/aws-cdk-lib/aws-appsync/lib/graphqlapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { IUserPool } from '../../aws-cognito';
import { ManagedPolicy, Role, IRole, ServicePrincipal } from '../../aws-iam';
import { IFunction } from '../../aws-lambda';
import { ILogGroup, LogGroup, LogRetention, RetentionDays } from '../../aws-logs';
import { CfnResource, Duration, Expiration, FeatureFlags, IResolvable, Lazy, Stack, Token } from '../../core';
import { CfnResource, Duration, Expiration, FeatureFlags, IResolvable, Lazy, Stack, Token, ValidationError } from '../../core';
import * as cxapi from '../../cx-api';

/**
Expand Down Expand Up @@ -578,7 +578,7 @@ export class GraphqlApi extends GraphqlApiBase {
if (this.definition.schema) {
return this.definition.schema;
}
throw new Error('Schema does not exist for AppSync merged APIs.');
throw new ValidationError('Schema does not exist for AppSync merged APIs.', this);
}

/**
Expand Down Expand Up @@ -619,19 +619,19 @@ export class GraphqlApi extends GraphqlApiBase {
this.validateAuthorizationProps(modes);

if (!props.schema && !props.definition) {
throw new Error('You must specify a GraphQL schema or source APIs in property definition.');
throw new ValidationError('You must specify a GraphQL schema or source APIs in property definition.', this);
}
if ((props.schema !== undefined) === (props.definition !== undefined)) {
throw new Error('You cannot specify both properties schema and definition.');
throw new ValidationError('You cannot specify both properties schema and definition.', this);
}
if (props.queryDepthLimit !== undefined && (props.queryDepthLimit < 0 || props.queryDepthLimit > 75)) {
throw new Error('You must specify a query depth limit between 0 and 75.');
throw new ValidationError('You must specify a query depth limit between 0 and 75.', this);
}
if (props.resolverCountLimit !== undefined && (props.resolverCountLimit < 0 || props.resolverCountLimit > 10000)) {
throw new Error('You must specify a resolver count limit between 0 and 10000.');
throw new ValidationError('You must specify a resolver count limit between 0 and 10000.', this);
}
if (!Token.isUnresolved(props.ownerContact) && props.ownerContact !== undefined && (props.ownerContact.length > 256)) {
throw new Error('You must specify `ownerContact` as a string of 256 characters or less.');
throw new ValidationError('You must specify `ownerContact` as a string of 256 characters or less.', this);
}

this.definition = props.schema ? Definition.fromSchema(props.schema) : props.definition!;
Expand Down Expand Up @@ -786,24 +786,24 @@ export class GraphqlApi extends GraphqlApiBase {

private validateAuthorizationProps(modes: AuthorizationMode[]) {
if (modes.filter((mode) => mode.authorizationType === AuthorizationType.LAMBDA).length > 1) {
throw new Error('You can only have a single AWS Lambda function configured to authorize your API.');
throw new ValidationError('You can only have a single AWS Lambda function configured to authorize your API.', this);
}
modes.map((mode) => {
if (mode.authorizationType === AuthorizationType.OIDC && !mode.openIdConnectConfig) {
throw new Error('Missing OIDC Configuration');
throw new ValidationError('Missing OIDC Configuration', this);
}
if (mode.authorizationType === AuthorizationType.USER_POOL && !mode.userPoolConfig) {
throw new Error('Missing User Pool Configuration');
throw new ValidationError('Missing User Pool Configuration', this);
}
if (mode.authorizationType === AuthorizationType.LAMBDA && !mode.lambdaAuthorizerConfig) {
throw new Error('Missing Lambda Configuration');
throw new ValidationError('Missing Lambda Configuration', this);
}
});
if (modes.filter((mode) => mode.authorizationType === AuthorizationType.API_KEY).length > 1) {
throw new Error('You can\'t duplicate API_KEY configuration. See https://docs.aws.amazon.com/appsync/latest/devguide/security.html');
throw new ValidationError('You can\'t duplicate API_KEY configuration. See https://docs.aws.amazon.com/appsync/latest/devguide/security.html', this);
}
if (modes.filter((mode) => mode.authorizationType === AuthorizationType.IAM).length > 1) {
throw new Error('You can\'t duplicate IAM configuration. See https://docs.aws.amazon.com/appsync/latest/devguide/security.html');
throw new ValidationError('You can\'t duplicate IAM configuration. See https://docs.aws.amazon.com/appsync/latest/devguide/security.html', this);
}
}

Expand All @@ -824,16 +824,16 @@ export class GraphqlApi extends GraphqlApiBase {
*/
public addEnvironmentVariable(key: string, value: string) {
if (this.definition.sourceApiOptions) {
throw new Error('Environment variables are not supported for merged APIs');
throw new ValidationError('Environment variables are not supported for merged APIs', this);
}
if (!Token.isUnresolved(key) && !/^[A-Za-z]+\w*$/.test(key)) {
throw new Error(`Key '${key}' must begin with a letter and can only contain letters, numbers, and underscores`);
throw new ValidationError(`Key '${key}' must begin with a letter and can only contain letters, numbers, and underscores`, this);
}
if (!Token.isUnresolved(key) && (key.length < 2 || key.length > 64)) {
throw new Error(`Key '${key}' must be between 2 and 64 characters long, got ${key.length}`);
throw new ValidationError(`Key '${key}' must be between 2 and 64 characters long, got ${key.length}`, this);
}
if (!Token.isUnresolved(value) && value.length > 512) {
throw new Error(`Value for '${key}' is too long. Values can be up to 512 characters long, got ${value.length}`);
throw new ValidationError(`Value for '${key}' is too long. Values can be up to 512 characters long, got ${value.length}`, this);
}

this.environmentVariables[key] = value;
Expand Down Expand Up @@ -926,7 +926,7 @@ export class GraphqlApi extends GraphqlApiBase {
*/
public get appSyncDomainName(): string {
if (!this.domainNameResource) {
throw new Error('Cannot retrieve the appSyncDomainName without a domainName configuration');
throw new ValidationError('Cannot retrieve the appSyncDomainName without a domainName configuration', this);
}
return this.domainNameResource.attrAppSyncDomainName;
}
Expand Down
12 changes: 6 additions & 6 deletions packages/aws-cdk-lib/aws-appsync/lib/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { BaseDataSource } from './data-source';
import { IGraphqlApi } from './graphqlapi-base';
import { MappingTemplate } from './mapping-template';
import { FunctionRuntime } from './runtime';
import { Token } from '../../core';
import { Token, ValidationError } from '../../core';

/**
* Basic properties for an AppSync resolver
Expand Down Expand Up @@ -110,25 +110,25 @@ export class Resolver extends Construct {

// If runtime is specified, code must also be
if (props.runtime && !props.code) {
throw new Error('Code is required when specifying a runtime');
throw new ValidationError('Code is required when specifying a runtime', scope);
}

if (props.code && (props.requestMappingTemplate || props.responseMappingTemplate)) {
throw new Error('Mapping templates cannot be used alongside code');
throw new ValidationError('Mapping templates cannot be used alongside code', scope);
}

if (pipelineConfig && props.dataSource) {
throw new Error(`Pipeline Resolver cannot have data source. Received: ${props.dataSource.name}`);
throw new ValidationError(`Pipeline Resolver cannot have data source. Received: ${props.dataSource.name}`, scope);
}

if (props.cachingConfig?.ttl && (props.cachingConfig.ttl.toSeconds() < 1 || props.cachingConfig.ttl.toSeconds() > 3600)) {
throw new Error(`Caching config TTL must be between 1 and 3600 seconds. Received: ${props.cachingConfig.ttl.toSeconds()}`);
throw new ValidationError(`Caching config TTL must be between 1 and 3600 seconds. Received: ${props.cachingConfig.ttl.toSeconds()}`, scope);
}

if (props.cachingConfig?.cachingKeys) {
if (props.cachingConfig.cachingKeys.find(cachingKey =>
!Token.isUnresolved(cachingKey) && !BASE_CACHING_KEYS.find(baseCachingKey => cachingKey.startsWith(baseCachingKey)))) {
throw new Error(`Caching config keys must begin with $context.arguments, $context.source or $context.identity. Received: ${props.cachingConfig.cachingKeys}`);
throw new ValidationError(`Caching config keys must begin with $context.arguments, $context.source or $context.identity. Received: ${props.cachingConfig.cachingKeys}`, scope);
}
}

Expand Down