Skip to content

Commit e04f3cd

Browse files
authored
docs(maintenance): update examples to v2 (#2242)
* docs(examples): refresh cdk example * docs(examples): refresh cdk example * docs: update template & functions * chore: update arch to arm * chore: update comments & confis * chore: removed sam folder & merged samples * chore: fix tests * chore: reliability
1 parent bfeae84 commit e04f3cd

Some content is hidden

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

77 files changed

+1876
-2254
lines changed

.github/boring-cyborg.yml

+3-20
Original file line numberDiff line numberDiff line change
@@ -71,22 +71,7 @@ labelPRBasedOnFilePath:
7171
- docs/**/*
7272
- mkdocs.yml
7373
- typedoc.js
74-
- examples/cdk/bin/*
75-
- examples/cdk/functions/*
76-
- examples/cdk/functions/**/*
77-
- examples/cdk/src/*
78-
- examples/cdk/src/**/*
79-
- examples/cdk/tests/*
80-
- examples/cdk/tests/**/*
81-
- examples/cdk/README.md
82-
- examples/cdk/cdk.json
83-
- examples/sam/events/*
84-
- examples/sam/src/*
85-
- examples/sam/src/**/*
86-
- examples/sam/tests/*
87-
- examples/sam/tests/**/*
88-
- examples/sam/README.md
89-
- examples/sam/template.yaml
74+
- examples/app/*
9075

9176
area/automation:
9277
- .github/scripts/*
@@ -137,8 +122,7 @@ labelPRBasedOnFilePath:
137122
- packages/parser/README.md
138123
- layers/tsconfig*.json
139124
- layers/README.md
140-
- examples/sam/tsconfig*.json
141-
- examples/cdk/tsconfig*.json
125+
- examples/app/tsconfig*.json
142126

143127
type/dependencies:
144128
- package.json
@@ -153,8 +137,7 @@ labelPRBasedOnFilePath:
153137
- packages/validator/package.json
154138
- packages/batch/package.json
155139
- layers/package.json
156-
- examples/cdk/package.json
157-
- examples/sam/package.json
140+
- examples/app/package.json
158141

159142
##### Greetings ########################################################################################################
160143
firstPRWelcomeComment: >

.github/workflows/reusable-run-linting-check-and-unit-tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
NODE_ENV: dev
3838
strategy:
3939
matrix:
40-
example: ["sam", "cdk"]
40+
example: ["app"]
4141
fail-fast: false
4242
defaults:
4343
run:

.gitignore

-4
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,6 @@ site
4141
# Generated API documentation (from TypeDoc)
4242
/api
4343

44-
# SAM Example copies files
45-
/examples/sam/src/handlers/*
46-
!/examples/sam/src/handlers/COPY_LAMBDA_FUNCTIONS_HERE
47-
4844
# Layer temp files
4945
tmp
5046

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,7 @@ Or refer to the installation guide of each utility:
8484

8585
### Examples
8686

87-
* [CDK](https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/examples/cdk)
88-
* [SAM](https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/examples/sam)
87+
You can find examples of how to use Powertools for AWS Lambda (TypeScript) in the [examples](https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/examples/app) directory. The application is a simple REST API that can be deployed via either AWS CDK or AWS SAM.
8988

9089
### Demo applications
9190

docs/contributing/conventions.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Whenever possible, we use the same directory structure for all utilities. This m
3131
There are also a few other workspaces that are not utilities published to npm, but that still share dependencies and/or runtime code with the utilities. These workspaces are:
3232

3333
* `docs/snippets`: contains the documentation code snippets
34-
* `examples/*`: contains the example projects deployed via AWS CDK or AWS SAM
34+
* `examples/app`: contains an example project that can be deployed via AWS CDK or AWS SAM
3535
* `layers`: contains the code used to build and publish the [Lambda layers](../index.md#lambda-layer)
3636

3737
## Testing definition

docs/index.md

+2-5
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,9 @@ The examples in this documentation will feature all the approaches described abo
272272

273273
## Examples
274274

275-
The project's repository includes examples of how to instrument your functions both in AWS CDK and AWS SAM:
275+
You can find examples of how to use Powertools for AWS Lambda (TypeScript) in the [examples](https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/examples/app){target="_blank"} directory. The application is a simple REST API that can be deployed via either AWS CDK or AWS SAM.
276276

277-
* [AWS CDK](https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/examples/cdk){target="_blank"}
278-
* [AWS SAM](https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/examples/sam){target="_blank"}
279-
280-
If instead you want to see Powertools for AWS Lambda (TypeScript) in a slightly more complex use case, check the [Serverless TypeScript Demo](https://github.com/aws-samples/serverless-typescript-demo) or the [AWS Lambda performance tuning](https://github.com/aws-samples/optimizations-for-lambda-functions) repository. Both demos use Powertools for AWS Lambda (TypeScript) as well as demonstrating other common techniques for Lambda functions written in TypeScript.
277+
If instead you want to see Powertools for AWS Lambda (TypeScript) in slightly different use cases, check the [Serverless TypeScript Demo](https://github.com/aws-samples/serverless-typescript-demo) or the [AWS Lambda performance tuning](https://github.com/aws-samples/optimizations-for-lambda-functions) repository. Both demos use Powertools for AWS Lambda (TypeScript) as well as demonstrating other common techniques for Lambda functions written in TypeScript.
281278

282279

283280
## Features

examples/cdk/.gitignore renamed to examples/app/.gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,13 @@ node_modules
88
.cdk.staging
99
cdk.out
1010
lib
11+
# npm lock file - this is managed by the npm workspace
12+
package-lock.json
13+
14+
**/.aws-sam
15+
16+
# SAM
17+
samconfig.toml
18+
1119
# npm lock file - this is managed by the npm workspace
1220
package-lock.json
File renamed without changes.
File renamed without changes.

examples/cdk/cdk.json renamed to examples/app/cdk.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"app": "npx ts-node --prefer-ts-exts bin/cdk-app.ts",
2+
"app": "tsx cdk/example-app.ts",
33
"watch": {
44
"include": [
55
"**"

examples/app/cdk/example-app.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env node
2+
import 'source-map-support/register';
3+
import { App } from 'aws-cdk-lib';
4+
import { PowertoolsExampleStack } from './example-stack.js';
5+
6+
const app = new App();
7+
new PowertoolsExampleStack(app, 'PowertoolsTypeScript-Example-CDK', {});

examples/app/cdk/example-stack.ts

+240
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
import { RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib';
2+
import { LambdaIntegration, RestApi } from 'aws-cdk-lib/aws-apigateway';
3+
import {
4+
AttributeType,
5+
BillingMode,
6+
StreamViewType,
7+
Table,
8+
TableClass,
9+
} from 'aws-cdk-lib/aws-dynamodb';
10+
import {
11+
FilterCriteria,
12+
FilterRule,
13+
LayerVersion,
14+
StartingPosition,
15+
} from 'aws-cdk-lib/aws-lambda';
16+
import { SqsDestination } from 'aws-cdk-lib/aws-lambda-destinations';
17+
import { DynamoEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
18+
import { OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs';
19+
import { Queue } from 'aws-cdk-lib/aws-sqs';
20+
import { StringParameter } from 'aws-cdk-lib/aws-ssm';
21+
import { Construct } from 'constructs';
22+
import { FunctionWithLogGroup } from './function-with-logstream-construct.js';
23+
24+
export class PowertoolsExampleStack extends Stack {
25+
public constructor(scope: Construct, id: string, props?: StackProps) {
26+
super(scope, id, props);
27+
28+
// Import Powertools layer to be used in some of the functions
29+
const powertoolsLayer = LayerVersion.fromLayerVersionArn(
30+
this,
31+
'powertools-layer',
32+
`arn:aws:lambda:${
33+
Stack.of(this).region
34+
}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:3`
35+
);
36+
37+
// Items table
38+
const itemsTable = new Table(this, 'items-table', {
39+
tableName: 'powertools-example-items',
40+
tableClass: TableClass.STANDARD_INFREQUENT_ACCESS,
41+
billingMode: BillingMode.PAY_PER_REQUEST,
42+
partitionKey: {
43+
type: AttributeType.STRING,
44+
name: 'id',
45+
},
46+
removalPolicy: RemovalPolicy.DESTROY,
47+
stream: StreamViewType.NEW_IMAGE, // we use the stream to trigger the processItemsStreamFn
48+
});
49+
50+
// Idempotency table
51+
const idempotencyTable = new Table(this, 'idempotencyTable', {
52+
tableName: 'powertools-example-idempotency',
53+
partitionKey: {
54+
name: 'id',
55+
type: AttributeType.STRING,
56+
},
57+
timeToLiveAttribute: 'expiration',
58+
billingMode: BillingMode.PAY_PER_REQUEST,
59+
removalPolicy: RemovalPolicy.DESTROY, // for demo only, change to RETAIN in production
60+
});
61+
62+
/**
63+
* We will store the idempotency table name in a SSM parameter to simulate a potential
64+
* cross-stack reference. This is not strictly necessary in this example, but it's a good way of showing
65+
* how to use SSM parameters and retrieve them using Powertools.
66+
*/
67+
const idempotencyTableNameParam = new StringParameter(
68+
this,
69+
'idempotency-table-name',
70+
{
71+
parameterName: '/items-store/idempotency-table-name',
72+
stringValue: idempotencyTable.tableName,
73+
}
74+
);
75+
76+
/**
77+
* In this example, we use ESM and bundle all the dependencies
78+
* including the AWS SDK.
79+
*
80+
* Because we are using ESM and tree shake, we create an optimized bundle.
81+
*/
82+
const putItemFn = new FunctionWithLogGroup(this, 'put-item-fn', {
83+
entry: './functions/put-item.ts',
84+
functionName: 'powertools-example-put-item',
85+
bundling: {
86+
minify: true,
87+
sourceMap: true,
88+
keepNames: true,
89+
format: OutputFormat.ESM,
90+
sourcesContent: true,
91+
mainFields: ['module', 'main'],
92+
externalModules: [], // we bundle all the dependencies
93+
esbuildArgs: {
94+
'--tree-shaking': 'true',
95+
},
96+
// We include this polyfill to support `require` in ESM due to AWS X-Ray SDK for Node.js not being ESM compatible
97+
banner:
98+
'import { createRequire } from "module";const require = createRequire(import.meta.url);',
99+
},
100+
});
101+
putItemFn.bindTable({ table: itemsTable, accessMode: 'RW' });
102+
/**
103+
* Allow the function to read and write to the idempotency table so it
104+
* can persist idempotency data
105+
*/
106+
putItemFn.bindTable({
107+
table: idempotencyTable,
108+
accessOnly: true,
109+
accessMode: 'RW',
110+
});
111+
/**
112+
* Also allow the function to fetch the SSM parameter
113+
* that contains the idempotency table name
114+
*/
115+
idempotencyTableNameParam.grantRead(putItemFn);
116+
putItemFn.addEnvironment(
117+
'SSM_PARAMETER_NAME',
118+
idempotencyTableNameParam.parameterName
119+
);
120+
121+
/**
122+
* In this example, we instead use the Powertools layer to include Powertools
123+
* as well as the AWS SDK, this is a convenient way to use Powertools
124+
* in a centralized way across all your functions.
125+
*/
126+
const getAllItemsFn = new FunctionWithLogGroup(this, 'get-all-items-fn', {
127+
entry: './functions/get-all-items.ts',
128+
functionName: 'powertools-example-get-all-items',
129+
layers: [powertoolsLayer], // we use the powertools layer
130+
bundling: {
131+
minify: true,
132+
sourceMap: true,
133+
keepNames: true,
134+
format: OutputFormat.ESM,
135+
mainFields: ['module', 'main'],
136+
sourcesContent: true,
137+
externalModules: ['@aws-sdk/*', '@aws-lambda-powertools/*'], // the dependencies are included in the layer
138+
esbuildArgs: {
139+
'--tree-shaking': 'true',
140+
},
141+
// We include this polyfill to support `require` in ESM due to AWS X-Ray SDK for Node.js not being ESM compatible
142+
banner:
143+
'import { createRequire } from "module";const require = createRequire(import.meta.url);',
144+
},
145+
});
146+
getAllItemsFn.bindTable({ table: itemsTable });
147+
148+
/**
149+
* In this examle, we emit a CommonJS (CJS) bundle and include all the
150+
* dependencies in it.
151+
*/
152+
const getByIdFn = new FunctionWithLogGroup(this, 'get-by-id-fn', {
153+
entry: './functions/get-by-id.ts',
154+
functionName: 'powertools-example-get-by-id',
155+
bundling: {
156+
minify: true,
157+
sourceMap: true,
158+
keepNames: true,
159+
format: OutputFormat.CJS,
160+
mainFields: ['main'],
161+
sourcesContent: true,
162+
externalModules: [], // we bundle all the dependencies
163+
},
164+
});
165+
getByIdFn.bindTable({ table: itemsTable });
166+
167+
/**
168+
* In this example, we use the Powertools layer to include Powertools
169+
* but we also bundle the function as CommonJS (CJS).
170+
*/
171+
const processItemsStreamFn = new FunctionWithLogGroup(
172+
this,
173+
'process-items-stream-fn',
174+
{
175+
entry: './functions/process-items-stream.ts',
176+
functionName: 'powertools-example-process-items-stream',
177+
layers: [powertoolsLayer],
178+
bundling: {
179+
minify: true,
180+
sourceMap: true,
181+
keepNames: true,
182+
format: OutputFormat.CJS,
183+
mainFields: ['main'],
184+
sourcesContent: true,
185+
externalModules: ['@aws-sdk/*', '@aws-lambda-powertools/*'], // the dependencies are included in the layer
186+
},
187+
}
188+
);
189+
// Dead letter queue for the items that fail to be processed after the retry attempts
190+
const dlq = new Queue(this, 'dead-letter-queue', {
191+
queueName: 'powertools-example-dead-letter-queue',
192+
removalPolicy: RemovalPolicy.DESTROY,
193+
});
194+
// Add the DynamoDB event source to the function
195+
processItemsStreamFn.addEventSource(
196+
new DynamoEventSource(itemsTable, {
197+
startingPosition: StartingPosition.LATEST,
198+
reportBatchItemFailures: true, // Enable batch failure reporting
199+
onFailure: new SqsDestination(dlq),
200+
batchSize: 100,
201+
retryAttempts: 3,
202+
filters: [
203+
// Filter by the INSERT event type and the presence of the id and name attributes
204+
FilterCriteria.filter({
205+
eventName: FilterRule.isEqual('INSERT'),
206+
dynamodb: {
207+
NewImage: {
208+
id: {
209+
S: FilterRule.exists(),
210+
},
211+
name: {
212+
S: FilterRule.exists(),
213+
},
214+
},
215+
},
216+
}),
217+
],
218+
})
219+
);
220+
221+
// Create an API Gateway to expose the items service
222+
const api = new RestApi(this, 'items-api', {
223+
restApiName: 'Items Service',
224+
description: 'This service serves items.',
225+
deployOptions: {
226+
tracingEnabled: true,
227+
},
228+
});
229+
230+
const itemPutIntegration = new LambdaIntegration(putItemFn);
231+
api.root.addMethod('POST', itemPutIntegration);
232+
233+
const itemsIntegration = new LambdaIntegration(getAllItemsFn);
234+
api.root.addMethod('GET', itemsIntegration);
235+
236+
const item = api.root.addResource('{id}');
237+
const itemIntegration = new LambdaIntegration(getByIdFn);
238+
item.addMethod('GET', itemIntegration);
239+
}
240+
}

0 commit comments

Comments
 (0)