Skip to content

Commit f792432

Browse files
authored
Merge branch 'master' into robertd/autoscaling-step-scaling-policy
2 parents b0955a7 + d884a34 commit f792432

File tree

207 files changed

+1312
-345
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

207 files changed

+1312
-345
lines changed

DESIGN_GUIDELINES.md

Lines changed: 284 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,65 @@
11
# AWS Construct Library Design Guidelines
22

3+
- [AWS Construct Library Design Guidelines](#aws-construct-library-design-guidelines)
4+
- [What's Included](#what-s-included)
5+
- [API Design](#api-design)
6+
- [Modules](#modules)
7+
- [Construct Class](#construct-class)
8+
- [Construct Interface](#construct-interface)
9+
- [Owned vs. Unowned Constructs](#owned-vs-unowned-constructs)
10+
- [Abstract Base](#abstract-base)
11+
- [Props](#props)
12+
- [Types](#types)
13+
- [Defaults](#defaults)
14+
- [Flat](#flat)
15+
- [Concise](#concise)
16+
- [Naming](#naming)
17+
- [Property Documentation](#property-documentation)
18+
- [Enums](#enums)
19+
- [Unions](#unions)
20+
- [Attributes](#attributes)
21+
- [Configuration](#configuration)
22+
- [Prefer Additions](#prefer-additions)
23+
- [Dropped Mutations](#dropped-mutations)
24+
- [Factories](#factories)
25+
- [Imports](#imports)
26+
- [“from” Methods](#-from--methods)
27+
- [From-attributes](#from-attributes)
28+
- [Roles](#roles)
29+
- [Resource Policies](#resource-policies)
30+
- [VPC](#vpc)
31+
- [Grants](#grants)
32+
- [Metrics](#metrics)
33+
- [Events](#events)
34+
- [Connections](#connections)
35+
- [Integrations](#integrations)
36+
- [State](#state)
37+
- [Physical Names - TODO](#physical-names---todo)
38+
- [Tags](#tags)
39+
- [Secrets](#secrets)
40+
- [Project Structure](#project-structure)
41+
- [Code Organization](#code-organization)
42+
- [Implementation](#implementation)
43+
- [General Principles](#general-principles)
44+
- [Construct IDs](#construct-ids)
45+
- [Errors](#errors)
46+
- [Input Validation](#input-validation)
47+
- [Avoid Errors If Possible](#avoid-errors-if-possible)
48+
- [Never Catch Exceptions](#never-catch-exceptions)
49+
- [Post Validation](#post-validation)
50+
- [Attached Errors/Warnings](#attached-errors-warnings)
51+
- [Tokens](#tokens)
52+
- [Documentation](#documentation)
53+
- [Inline Documentation](#inline-documentation)
54+
- [Readme](#readme)
55+
- [Testing](#testing)
56+
- [Unit tests](#unit-tests)
57+
- [Integration tests](#integration-tests)
58+
- [Versioning](#versioning)
59+
- [Naming & Style](#naming---style)
60+
- [Naming Conventions](#naming-conventions)
61+
- [Coding Style](#coding-style)
62+
363
The AWS Construct Library is a rich class library of CDK constructs which
464
represent all resources offered by the AWS Cloud and higher-level constructs for
565
achieving common tasks.
@@ -8,6 +68,8 @@ The purpose of this document is to provide guidelines for designing the APIs in
868
the AWS Construct Library in order to ensure a consistent and integrated
969
experience across the entire AWS surface area.
1070

71+
## Preface
72+
1173
As much as possible, the guidelines in this document are enforced using the
1274
[**awslint** tool](https://www.npmjs.com/package/awslint) which reflects on the
1375
APIs and verifies that the APIs adhere to the guidelines. When a guideline is
@@ -56,6 +118,73 @@ allows the library to be used from all supported programming languages. jsii
56118
poses restrictions on language features that cannot be idiomatically represented
57119
in target languages.
58120

121+
## What's Included
122+
123+
The AWS Construct Library, which is shipped as part of the AWS CDK constructs
124+
representing AWS resources.
125+
126+
The AWS Construct Library has multiple layers of constructs, beginning
127+
with low-level constructs, which we call _CFN Resources_ (or L1, short for
128+
"level 1") or CFN Resources (short for CloudFormation). These constructs
129+
directly represent all resources available in AWS CloudFormation. CFN Resources
130+
are periodically generated from the AWS CloudFormation Resource
131+
Specification. They are named **Cfn**_Xyz_, where _Xyz_ is name of the
132+
resource. For example, CfnBucket represents the AWS::S3::Bucket AWS
133+
CloudFormation resource. When you use Cfn resources, you must explicitly
134+
configure all resource properties, which requires a complete understanding of
135+
the details of the underlying AWS CloudFormation resource model.
136+
137+
The next level of constructs, L2, also represent AWS resources, but with a
138+
higher-level, intent-based API. They provide similar functionality, but provide
139+
the defaults, boilerplate, and glue logic you'd be writing yourself with a CFN
140+
Resource construct. L2 constructs offer convenient defaults and reduce the need
141+
to know all the details about the AWS resources they represent, while providing
142+
convenience methods that make it simpler to work with the resource. For example,
143+
the `s3.Bucket` class represents an Amazon S3 bucket with additional properties
144+
and methods, such as `bucket.addLifeCycleRule()`, which adds a lifecycle rule to
145+
the bucket.
146+
147+
Examples of behaviors that an L2 commonly include:
148+
149+
- Strongly-typed modeling of the underlying L1 properties
150+
- Methods for integrating other AWS resources (e.g., adding an event notification to
151+
an S3 bucket).
152+
- Modeling of permissions and resource policies
153+
- Modeling of metrics
154+
155+
In addition to the above, some L2s may introduce more complex and
156+
helpful functionality, either part of the original L2 itself, or as part of a
157+
separate construct. The most common form of these L2s are integration constructs
158+
that model interactions between different services (e.g., SNS publishing to SQS,
159+
CodePipeline actions that trigger Lambda functions).
160+
161+
The next level of abstraction present within the CDK are what we designate as
162+
"L2.5s": a step above the L2s in terms of abstraction, but not quite at the
163+
level of complete patterns or applications. These constructs still largely
164+
focus on a single logical resource -- in constrast to "patterns" which combine
165+
multiple resources -- but are customized for a specific common usage scenario of
166+
an L2. Examples of L2.5s in the CDK are `aws-apigateway.LambdaRestApi`,
167+
`aws-lambda-nodejs.NodeJsFunction`, `aws-rds.ServerlessCluster` and `eks.FargateCluster`.
168+
169+
L2.5 constructs will be considered for inclusion in the CDK if they...
170+
171+
- cover a common usage scenario that can be used by a significant portion of
172+
the community;
173+
- provide significant ease of use over the base L2 (via usage-specific defaults
174+
convenience methods or improved strong-typing);
175+
- simplify or enable another L2 within the CDK
176+
177+
The CDK also currently includes some even higher-level constructs, which we call
178+
patterns. These constructs often involve multiple kinds of resources and are
179+
designed to help you complete common tasks in AWS or represent entire
180+
applications. For example, the
181+
`aws-ecs-patterns.ApplicationLoadBalancedFargateService` construct represents an
182+
architecture that includes an AWS Fargate container cluster employing an
183+
Application Load Balancer (ALB). These patterns are typically difficult to
184+
design to be one-size-fits-all and are best suited to be published as separate
185+
libraries, rather than included directly in the CDK. The patterns that currently
186+
exist in the CDK will be removed in the next CDK major version (CDKv2).
187+
59188
## API Design
60189

61190
### Modules
@@ -333,14 +462,31 @@ from harnessing the full power of the resource, and customizing its behavior.
333462
alignment.
334463

335464
The **@default** documentation tag must be included on all optional properties
336-
of interfaces. Since there are cases where the default behavior is not a
337-
specific value but rather depends on circumstances/context, the default
338-
documentation tag must always begin with a “**-**" and then include a
339-
description of the default behavior _[awslint:props-default-doc]_.
465+
of interfaces.
466+
467+
In cases where the default behavior can be described by a value (typically the
468+
case for booleans and enums, sometimes for strings and numbers), the value immediately
469+
follows the **@default** tag and should be a valid JavaScript value (as in:
470+
`@default false`, or `@default "stringValue"`).
340471

341-
For example:
472+
In the majority of cases, the default behavior is not a specific value but
473+
rather depends on circumstances/context. The default documentation tag must
474+
begin with a “**-**" and then include a description of the default behavior
475+
_[awslint:props-default-doc]_. This is specially true if the property
476+
is a complex value or a reference to an object: don't write `@default
477+
undefined`, describe the behavior that happens if the property is not
478+
supplied.
479+
480+
Describe the default value or default behavior, even if it's not CDK that
481+
controls the default. For example, if an absent value does not get rendered
482+
into the template and it's ultimately the AWS *service* that determines the
483+
default behavior, we still describe it in our documentation.
484+
485+
Examples:
342486

343487
```ts
488+
// ✅ DO - uses a '-' and describes the behavior
489+
344490
/**
345491
* External KMS key to use for bucket encryption.
346492
*
@@ -350,6 +496,32 @@ For example:
350496
encryptionKey?: kms.IEncryptionKey;
351497
```
352498

499+
```ts
500+
/**
501+
* External KMS key to use for bucket encryption.
502+
*
503+
* @default undefined
504+
* ❌ DO NOT - that the value is 'undefined' by default is implied. However,
505+
* what will the *behavior* be if the value is left out?
506+
*/
507+
encryptionKey?: kms.IEncryptionKey;
508+
```
509+
510+
```ts
511+
/**
512+
* Minimum capacity of the AutoScaling resource
513+
*
514+
* @default - no minimum capacity
515+
* ❌ DO NOT - there most certainly is. It's probably 0 or 1.
516+
*
517+
* // OR
518+
* @default - the minimum capacity is the default minimum capacity
519+
* ❌ DO NOT - this is circular and useless to the reader.
520+
* Describe what will actually happen.
521+
*/
522+
minCapacity?: number;
523+
```
524+
353525
#### Flat
354526

355527
Do not introduce artificial nesting for props. It hinders discoverability and
@@ -1216,19 +1388,6 @@ for (const az of availabilityZones) {
12161388
12171389
### Errors
12181390
1219-
#### Input Validation
1220-
1221-
Prefer to validate input as early as it is passed into your code (ctor, methods,
1222-
etc) and bail out by throwing an **Error** (no need to create subclasses of
1223-
Error since all errors in the CDK are unrecoverable):
1224-
1225-
* All lowercase sentences (usually they are printed after “Error: \<message\>”)
1226-
* Include a descriptive message
1227-
* Include the value provided
1228-
* Include the expected/allowed values
1229-
* No need to include information that can be obtained from the stack trace
1230-
* No need to add a period at the end of error messages
1231-
12321391
#### Avoid Errors If Possible
12331392
12341393
Always prefer to do the right thing for the user instead of raising an
@@ -1237,26 +1396,126 @@ example, VPC has **enableDnsHostnames** and **enableDnsSupport**. DNS hostnames
12371396
*require* DNS support, so only fail if the user enabled DNS hostnames but
12381397
explicitly disabled DNS support. Otherwise, auto-enable DNS support for them.
12391398
1399+
#### Error reporting mechanism
1400+
1401+
There are three mechanism you can use to report errors:
1402+
1403+
* Eagerly throw an exception (fails synthesis)
1404+
* Attach a (lazy) validator to a construct (fails synthesis)
1405+
* Attach errors to a construct (succeeds synthesis, fails deployment)
1406+
1407+
Between these, the first two fail synthesis, while the latter doesn't. Failing synthesis
1408+
means that no Cloud Assembly will be produced.
1409+
1410+
The distinction becomes apparent when you consider multiple stacks in the same Cloud
1411+
Assembly:
1412+
1413+
* If synthesis fails due to an error in *one* stack (either by throwing an exception
1414+
or by failing validation), the other stack can also not be deployed.
1415+
* In contrast, if you attach an error to a construct in one stack, that stack cannot
1416+
be deployed but the other one still can.
1417+
1418+
Choose one of the first two methods if the failure is caused by a misuse of the API,
1419+
which the user should be alerted to and fix as quickly as possible. Choose attaching
1420+
an error to a construct if the failure is due to environmental factors outside the
1421+
direct use of the API surface (for example, lack of context provider lookup values).
1422+
1423+
#### Throwing exceptions
1424+
1425+
This should be the preferred error reporting method.
1426+
1427+
Validate input as early as it is passed into your code (ctor, methods,
1428+
etc) and bail out by throwing an `Error`. No need to create subclasses of
1429+
Error since all errors in the CDK are unrecoverable.
1430+
1431+
When validating inputs, don't forget to account for the fact that these
1432+
values may be `Token`s and not available for inspection at synthesis time.
1433+
1434+
Example:
1435+
1436+
```ts
1437+
if (!Token.isUnresolved(props.minCapacity) && props.minCapacity < 1) {
1438+
throw new Error(`'minCapacity' should be at least 1, got '${props.minCapacity}'`);
1439+
}
1440+
```
1441+
12401442
#### Never Catch Exceptions
12411443
1242-
All CDK errors are unrecoverable. If a method wishes to signal a recoverable
1444+
All CDK errors are unrecoverable. If a method wishes to signal a recoverable
12431445
error, this should be modeled in a return value and not through exceptions.
12441446
1245-
#### Post Validation
1447+
#### Attaching (lazy) Validators
1448+
1449+
In the rare case where the integrity of your construct can only be checked
1450+
after the app has completed its initialization, call the
1451+
**this.node.addValidation()** method to add a validation object. This will
1452+
generally only be necessary if you want to produce an error when a certain
1453+
interaction with your construct did *not* happen (for example, a property
1454+
that should have been configured over the lifetime of the construct, wasn't):
1455+
1456+
Always prefer early input validation over post-validation, as the necessity
1457+
of these should be rare.
1458+
1459+
Example:
12461460
1247-
In the rare case where the integrity of your construct can only be checked right
1248-
before synthesis, override the **Construct.validate()** method and return
1249-
meaningful errors. Always prefer early input validation over post-validation.
1461+
```ts
1462+
this.node.addValidation({
1463+
// 'validate' should return a string[] list of errors
1464+
validate: () => this.rules.length === 0
1465+
? ['At least one Rule must be added. Call \'addRule()\' to add Rules.']
1466+
: []
1467+
}
1468+
});
1469+
```
12501470
1251-
#### Attached Errors/Warnings
1471+
#### Attaching Errors/Warnings
12521472
12531473
You can also “attach” an error or a warning to a construct via
12541474
the **Annotations** class. These methods (e.g., `Annotations.of(construct).addWarning`)
12551475
will attach CDK metadata to your construct, which will be displayed to the user
12561476
by the toolchain when the stack is deployed.
12571477
12581478
Errors will not allow deployment and warnings will only be displayed in
1259-
highlight (unless **--strict** mode is used).
1479+
highlight (unless `--strict` mode is used).
1480+
1481+
```ts
1482+
if (!Token.isUnresolved(subnetIds) && subnetIds.length < 2) {
1483+
Annotations.of(this).addError(`Need at least 2 subnet ids, got: ${JSON.stringify(subnetIds)}`);
1484+
}
1485+
```
1486+
1487+
#### Error messages
1488+
1489+
Think about error messages from the point of view of the end user of the CDK.
1490+
This is not necessarily someone who knows about the internals of your
1491+
construct library, so try to phrase the message in a way that would make
1492+
sense to them.
1493+
1494+
For example, if a value the user supplied gets handed off between a number of
1495+
functions before finally being validated, phrase the message in terms of the
1496+
API the user interacted with, not in terms of the internal APIs.
1497+
1498+
A good error message should include the following components:
1499+
1500+
* What went wrong, in a way that makes sense to a top-level user
1501+
* An example of the incorrect value provided (if applicable)
1502+
* An example of the expected/allowed values (if applicable)
1503+
* The message should explain the (most likely) cause and change the user can
1504+
make to rectify the situation
1505+
1506+
The message should be all lowercase and not end in a period, or contain
1507+
information that can be obtained from the stack trace.
1508+
1509+
```ts
1510+
// ✅ DO - show the value you got and be specific about what the user should do
1511+
`supply at least one of minCapacity or maxCapacity, got ${JSON.stringify(action)}`
1512+
1513+
// ❌ DO NOT - this tells the user nothing about what's wrong or what they should do
1514+
`required values are missing`
1515+
1516+
// ❌ DO NOT - this error only makes sense if you know the implementation
1517+
`'undefined' is not a number`
1518+
```
12601519
12611520
### Tokens
12621521

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
"fs-extra": "^9.1.0",
1919
"graceful-fs": "^4.2.6",
2020
"jest-junit": "^12.0.0",
21-
"jsii-diff": "^1.21.0",
22-
"jsii-pacmak": "^1.21.0",
23-
"jsii-rosetta": "^1.21.0",
21+
"jsii-diff": "^1.23.0",
22+
"jsii-pacmak": "^1.23.0",
23+
"jsii-rosetta": "^1.23.0",
2424
"lerna": "^3.22.1",
2525
"standard-version": "^9.1.1",
2626
"typescript": "~3.9.9"

packages/@aws-cdk/alexa-ask/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
"Framework :: AWS CDK",
2727
"Framework :: AWS CDK :: 1"
2828
]
29+
},
30+
"go": {
31+
"moduleName": "github.com/aws/aws-cdk-go"
2932
}
3033
},
3134
"projectReferences": true

0 commit comments

Comments
 (0)