Skip to content

Commit 84818e3

Browse files
authored
Require name in defineStorage props (#989)
1 parent ccde77a commit 84818e3

File tree

11 files changed

+43
-14
lines changed

11 files changed

+43
-14
lines changed

.changeset/selfish-eels-jam.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@aws-amplify/backend-storage': minor
3+
---
4+
5+
Require name in defineStorage props

packages/backend-storage/API.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export type AmplifyStorageFactoryProps = Omit<AmplifyStorageProps, 'outputStorag
1515

1616
// @public (undocumented)
1717
export type AmplifyStorageProps = {
18+
name: string;
1819
versioned?: boolean;
1920
outputStorageStrategy?: BackendOutputStorageStrategy<StorageOutput>;
2021
};

packages/backend-storage/src/construct.test.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ void describe('AmplifyStorage', () => {
1414
void it('creates a bucket', () => {
1515
const app = new App();
1616
const stack = new Stack(app);
17-
new AmplifyStorage(stack, 'test', {});
17+
new AmplifyStorage(stack, 'test', { name: 'testName' });
1818
const template = Template.fromStack(stack);
1919
template.resourceCountIs('AWS::S3::Bucket', 1);
2020
});
2121

2222
void it('turns versioning on if specified', () => {
2323
const app = new App();
2424
const stack = new Stack(app);
25-
new AmplifyStorage(stack, 'test', { versioned: true });
25+
new AmplifyStorage(stack, 'test', { versioned: true, name: 'testName' });
2626
const template = Template.fromStack(stack);
2727
template.resourceCountIs('AWS::S3::Bucket', 1);
2828
template.hasResourceProperties('AWS::S3::Bucket', {
@@ -33,7 +33,7 @@ void describe('AmplifyStorage', () => {
3333
void it('stores attribution data in stack', () => {
3434
const app = new App();
3535
const stack = new Stack(app);
36-
new AmplifyStorage(stack, 'testAuth', {});
36+
new AmplifyStorage(stack, 'testAuth', { name: 'testName' });
3737

3838
const template = Template.fromStack(stack);
3939
assert.equal(
@@ -54,11 +54,12 @@ void describe('AmplifyStorage', () => {
5454
};
5555

5656
const storageConstruct = new AmplifyStorage(stack, 'test', {
57+
name: 'testName',
5758
outputStorageStrategy: storageStrategy,
5859
});
5960

6061
const expectedBucketName = (
61-
storageConstruct.node.findChild('testBucket') as Bucket
62+
storageConstruct.node.findChild('Bucket') as Bucket
6263
).bucketName;
6364
const expectedRegion = Stack.of(storageConstruct).region;
6465

@@ -80,7 +81,7 @@ void describe('AmplifyStorage', () => {
8081
const app = new App();
8182
const stack = new Stack(app);
8283

83-
new AmplifyStorage(stack, 'test', {});
84+
new AmplifyStorage(stack, 'test', { name: 'testName' });
8485
const template = Template.fromStack(stack);
8586
template.templateMatches({
8687
Metadata: {

packages/backend-storage/src/construct.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { fileURLToPath } from 'url';
1919
const storageStackType = 'storage-S3';
2020

2121
export type AmplifyStorageProps = {
22+
name: string;
2223
versioned?: boolean;
2324
outputStorageStrategy?: BackendOutputStorageStrategy<StorageOutput>;
2425
};
@@ -48,7 +49,7 @@ export class AmplifyStorage
4849
};
4950

5051
this.resources = {
51-
bucket: new Bucket(this, `${id}Bucket`, bucketProps),
52+
bucket: new Bucket(this, 'Bucket', bucketProps),
5253
};
5354

5455
this.storeOutput(props.outputStorageStrategy);

packages/backend-storage/src/factory.test.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ void describe('AmplifyStorageFactory', () => {
3737
let getInstanceProps: ConstructFactoryGetInstanceProps;
3838

3939
beforeEach(() => {
40-
storageFactory = defineStorage({});
40+
storageFactory = defineStorage({ name: 'testName' });
4141
const stack = createStackAndSetContext();
4242

4343
constructContainer = new ConstructContainerStub(
@@ -110,4 +110,12 @@ void describe('AmplifyStorageFactory', () => {
110110
)
111111
);
112112
});
113+
114+
void it('throws on invalid name', () => {
115+
const storageFactory = defineStorage({ name: '!$87++|' });
116+
assert.throws(() => storageFactory.getInstance(getInstanceProps), {
117+
message:
118+
'defineStorage name can only contain alphanumeric characters, found !$87++|',
119+
});
120+
});
113121
});

packages/backend-storage/src/factory.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
AmplifyStorageProps,
1414
StorageResources,
1515
} from './construct.js';
16+
import { AmplifyUserError } from '@aws-amplify/platform-core';
1617

1718
export type AmplifyStorageFactoryProps = Omit<
1819
AmplifyStorageProps,
@@ -48,6 +49,7 @@ class AmplifyStorageFactory
4849
path.join('amplify', 'storage', 'resource'),
4950
'Amplify Storage must be defined in amplify/storage/resource.ts'
5051
);
52+
this.validateName(this.props.name);
5153
if (!this.generator) {
5254
this.generator = new AmplifyStorageGenerator(
5355
this.props,
@@ -56,19 +58,29 @@ class AmplifyStorageFactory
5658
}
5759
return constructContainer.getOrCompute(this.generator) as AmplifyStorage;
5860
};
61+
62+
private validateName = (name: string): void => {
63+
const nameIsAlphanumeric = /^[a-zA-Z0-9]+$/.test(name);
64+
if (!nameIsAlphanumeric) {
65+
throw new AmplifyUserError('InvalidResourceNameError', {
66+
message: `defineStorage name can only contain alphanumeric characters, found ${name}`,
67+
resolution:
68+
'Change the name parameter of defineStorage to only use alphanumeric characters',
69+
});
70+
}
71+
};
5972
}
6073

6174
class AmplifyStorageGenerator implements ConstructContainerEntryGenerator {
6275
readonly resourceGroupName = 'storage';
63-
private readonly defaultName = 'amplifyStorage';
6476

6577
constructor(
6678
private readonly props: AmplifyStorageProps,
6779
private readonly outputStorageStrategy: BackendOutputStorageStrategy<BackendOutputEntry>
6880
) {}
6981

7082
generateContainerEntry = (scope: Construct) => {
71-
return new AmplifyStorage(scope, this.defaultName, {
83+
return new AmplifyStorage(scope, `${this.props.name}`, {
7284
...this.props,
7385
outputStorageStrategy: this.outputStorageStrategy,
7486
});

packages/integration-tests/src/test-in-memory/integration_tests.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ void it('data storage auth with triggers', () => {
3939

4040
assertExpectedLogicalIds(templates.storage, 'AWS::S3::Bucket', [
4141
// eslint-disable-next-line spellcheck/spell-checker
42-
'amplifyStorageamplifyStorageBucketC2F702CD',
42+
'testNameBucketB4152AD5',
4343
]);
4444
});
4545

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import { defineStorage } from '@aws-amplify/backend';
22

3-
export const storage = defineStorage({});
3+
export const storage = defineStorage({name: 'testName'});
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import { defineStorage } from '@aws-amplify/backend';
22

3-
export const storage = defineStorage({});
3+
export const storage = defineStorage({name: 'testName'});

packages/platform-core/API.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export class AmplifyUserError extends AmplifyError {
6464
}
6565

6666
// @public
67-
export type AmplifyUserErrorType = 'InvalidPackageJsonError' | 'InvalidSchemaAuthError' | 'InvalidSchemaError' | 'ExpiredTokenError' | 'CloudFormationDeploymentError' | 'CFNUpdateNotSupportedError' | 'SyntaxError' | 'BackendBuildError' | 'BootstrapNotDetectedError' | 'AccessDeniedError' | 'FileConventionError';
67+
export type AmplifyUserErrorType = 'InvalidPackageJsonError' | 'InvalidSchemaAuthError' | 'InvalidSchemaError' | 'ExpiredTokenError' | 'CloudFormationDeploymentError' | 'CFNUpdateNotSupportedError' | 'SyntaxError' | 'BackendBuildError' | 'BootstrapNotDetectedError' | 'AccessDeniedError' | 'FileConventionError' | 'InvalidResourceNameError';
6868

6969
// @public
7070
export class BackendIdentifierConversions {

0 commit comments

Comments
 (0)