Skip to content

Commit a91df31

Browse files
Alexander Schuerendreamorosi
Alexander Schueren
andauthored
docs(idempotency): API docs for idempotency (#1485)
* update typedoc * add main and base typedoc config for each package * move package specific typedoc to dedicated config file, the package.json config is depricated * add js doc comment * add js doc comment * change readme to focus only on specifics of the package * fix broken commit on docs by checking latest 5d6ed1a commit * revert docs * remove generated api docs in the wrong folder * remove generated variables in docs * adjust middleware export * add more docs * added warning to readme and imports * switch to any to make examples easier to consume * add status record comment * Update typedoc.json --------- Co-authored-by: Andrea Amorosi <[email protected]>
1 parent d96c84c commit a91df31

33 files changed

+462
-105
lines changed

Diff for: package-lock.json

+45-27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@
7878
"proxy-agent": "^5.0.0",
7979
"ts-jest": "^29.0.3",
8080
"ts-node": "^10.9.1",
81-
"typedoc": "^0.23.22",
82-
"typedoc-plugin-missing-exports": "^1.0.0",
81+
"typedoc": "^0.24.7",
82+
"typedoc-plugin-missing-exports": "^2.0.0",
8383
"typescript": "^4.9.4",
8484
"uuid": "^9.0.0"
8585
},

Diff for: packages/commons/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
"license": "MIT-0",
3131
"main": "./lib/index.js",
3232
"types": "./lib/index.d.ts",
33-
"typedocMain": "src/index.ts",
3433
"files": [
3534
"lib"
3635
],

Diff for: packages/commons/typedoc.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": ["../../typedoc.base.json"],
3+
"entryPoints": [
4+
"./src/index.ts"
5+
],
6+
"readme": "README.md"
7+
}

Diff for: packages/idempotency/README.md

+120-43
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,148 @@
1-
# Powertools for AWS Lambda (TypeScript) <!-- omit in toc -->
1+
# Powertools for AWS Lambda (TypeScript) - Idempotency Utility <!-- omit in toc -->
2+
3+
4+
| ⚠️ **WARNING: Do not use this utility in production just yet!** ⚠️ |
5+
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
6+
| **This utility is currently released as beta developer preview** and is intended strictly for feedback and testing purposes **and not for production workloads**.. The version and all future versions tagged with the `-beta` suffix should be treated as not stable. Up until before the [General Availability release](https://github.com/awslabs/aws-lambda-powertools-typescript/milestone/10) we might introduce significant breaking changes and improvements in response to customers feedback. | _ |
7+
28

39
Powertools for AWS Lambda (TypeScript) is a developer toolkit to implement Serverless [best practices and increase developer velocity](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#features).
410

5-
You can use the library in both TypeScript and JavaScript code bases.
11+
## Intro
12+
13+
This package provides a utility to implement idempotency in your Lambda functions.
14+
You can either use it as a decorator on your Lambda handler or as a wrapper on any other function.
15+
If you use middy, we also provide a middleware to make your Lambda handler idempotent.
16+
The current implementation provides a persistance layer for Amazon DynamoDB, which offers a variety of configuration options.
17+
You can also bring your own persistance layer by implementing the `IdempotencyPersistanceLayer` interface.
18+
19+
## Key features
20+
* Prevent Lambda handler from executing more than once on the same event payload during a time window
21+
* Ensure Lambda handler returns the same result when called with the same payload
22+
* Select a subset of the event as the idempotency key using JMESPath expressions
23+
* Set a time window in which records with the same payload should be considered duplicates
24+
* Expires in-progress executions if the Lambda function times out halfway through
25+
26+
## Usage
27+
28+
### Decorators
29+
If you use classes to define your Lambda handlers, you can use the decorators to make your handler idempotent or a specific function idempotent.
30+
We offer two decorators:
31+
* `@idempotentLambdaHandler`: makes the handler idempotent.
32+
* `@idempotentFunction`: makes any function within your class idempotent
633

7-
[Powertools for AWS Lambda (Python)](https://github.com/awslabs/aws-lambda-powertools-python) and [Powertools for AWS Lambda (Java)](https://github.com/awslabs/aws-lambda-powertools-java) are also available.
34+
The first can only be applied to the handler function with the specific signature of a Lambda handler.
35+
The second can be applied to any function within your class. In this case you need to pass a `Record` object and provide the `dataKeywordArgument` parameter to specify the name of the argument that contains the data to be used as the idempotency key.
36+
In any of both cases yoiu need to pass the persistance layer where we will store the idempotency information.
837

9-
**[📜 Documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/)** | **[NPM](https://www.npmjs.com/org/aws-lambda-powertools)** | **[Roadmap](https://github.com/awslabs/aws-lambda-powertools-roadmap/projects/1)** | **[Examples](https://github.com/awslabs/aws-lambda-powertools-typescript/tree/main/examples)** | **[Serverless TypeScript Demo](https://github.com/aws-samples/serverless-typescript-demo)**
1038

11-
## Table of contents <!-- omit in toc -->
39+
### Function wrapper
1240

13-
- [Features](#features)
14-
- [Getting started](#getting-started)
15-
- [Installation](#installation)
16-
- [Examples](#examples)
17-
- [Serverless TypeScript Demo application](#serverless-typescript-demo-application)
18-
- [Contribute](#contribute)
19-
- [Roadmap](#roadmap)
20-
- [Connect](#connect)
21-
- [How to support Powertools for AWS Lambda (TypeScript)?](#how-to-support-powertools-for-aws-lambda-typescript)
22-
- [Becoming a reference customer](#becoming-a-reference-customer)
23-
- [Sharing your work](#sharing-your-work)
24-
- [Using Lambda Layer](#using-lambda-layer)
25-
- [Credits](#credits)
26-
- [License](#license)
41+
A more common approach is to use the function wrapper.
42+
Similar to `@idempotentFunction` decorator you need to pass keyword argument to indicate which part of the payload will be hashed.
2743

28-
## Features
44+
### Middy middleware
45+
// TODO: after e2e tests are implemented
2946

30-
* **[Tracer](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/tracer/)** - Utilities to trace Lambda function handlers, and both synchronous and asynchronous functions
31-
* **[Logger](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/logger/)** - Structured logging made easier, and a middleware to enrich log items with key details of the Lambda context
32-
* **[Metrics](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF)
33-
* **[Parameters (beta)](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM, Secrets Manager, AppConfig, and DynamoDB
47+
### DynamoDB peristance layer
48+
To store the idempotency information offer a DynamoDB persistance layer.
49+
This enables you to store the hash key, payload, status for progress and expiration and much more.
50+
You can customise most of the configuration options of the DynamoDB table, i.e the names of the attributes.
51+
See the [API documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/modules/.index.DynamoDBPersistenceLayer.html) for more details.
3452

35-
## Getting started
53+
## Examples
3654

37-
Find the complete project's [documentation here](https://awslabs.github.io/aws-lambda-powertools-typescript).
55+
### Decorator Lambda handler
3856

39-
### Installation
57+
```ts
58+
import { idempotentLambdaHandler } from "@aws-lambda-powertools/idempotency";
59+
import { DynamoDBPersistenceLayer } from "@aws-lambda-powertools/idempotency/persistance";
60+
import type { Context } from 'aws-lambda';
4061

41-
The Powertools for AWS Lambda (TypeScript) utilities follow a modular approach, similar to the official [AWS SDK v3 for JavaScript](https://github.com/aws/aws-sdk-js-v3).
42-
Each TypeScript utility is installed as standalone NPM package.
62+
const dynamoDBPersistenceLayer = new DynamoDBPersistenceLayer();
4363

44-
Install all three core utilities at once with this single command:
64+
class MyLambdaHandler implements LambdaInterface {
65+
@idempotentLambdaHandler({ persistenceStore: dynamoDBPersistenceLayer })
66+
public async handler(_event: any, _context: Context): Promise<string> {
67+
// your lambda code here
68+
return "Hello World";
69+
}
70+
}
4571

46-
```shell
47-
npm install @aws-lambda-powertools/logger @aws-lambda-powertools/tracer @aws-lambda-powertools/metrics
72+
const lambdaClass = new MyLambdaHandler();
73+
export const handler = lambdaClass.handler.bind(lambdaClass);
4874
```
4975

50-
Or refer to the installation guide of each utility:
76+
### Decorator function
77+
78+
```ts
79+
import { idempotentLambdaHandler } from "@aws-lambda-powertools/idempotency";
80+
import { DynamoDBPersistenceLayer } from "@aws-lambda-powertools/idempotency/persistance";
81+
import type { Context } from 'aws-lambda';
82+
83+
84+
const dynamoDBPersistenceLayer = new DynamoDBPersistenceLayer();
85+
86+
class MyLambdaHandler implements LambdaInterface {
87+
88+
public async handler(_event: any, _context: Context): Promise<void> {
89+
for(const record of _event.Records) {
90+
await this.processRecord(record);
91+
}
92+
}
93+
94+
@idempotentFunction({ persistenceStore: dynamoDBPersistenceLayer, dataKeywordArgument: "payload" })
95+
public async process(payload: Record<string, unknown>): Promise<void> {
96+
// your lambda code here
97+
}
98+
}
99+
```
100+
101+
The `dataKeywordArgument` parameter is optional. If not provided, the whole event will be used as the idempotency key.
102+
Otherwise, you need to specify the string name of the argument that contains the data to be used as the idempotency key.
103+
For example if you have an input like this:
104+
51105

52-
👉 [Installation guide for the **Tracer** utility](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/tracer#getting-started)
106+
```json
107+
{
108+
"transactionId": 1235,
109+
"product": "book",
110+
"quantity": 1,
111+
"price": 10
112+
}
113+
```
114+
115+
You can use `transactionId` as the idempotency key. This will ensure that the same transaction is not processed twice.
53116

54-
👉 [Installation guide for the **Logger** utility](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/logger#getting-started)
117+
### Function wrapper
55118

56-
👉 [Installation guide for the **Metrics** utility](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/core/metrics#getting-started)
119+
In case where you don't use classes and decorators you can wrap your function to make it idempotent.
57120

58-
👉 [Installation guide for the **Parameters** utility](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/#getting-started)
121+
```ts
122+
import { makeFunctionIdempotent } from "@aws-lambda-powertools/idempotency";
123+
import { DynamoDBPersistenceLayer } from "@aws-lambda-powertools/idempotency/persistance";
124+
import type { Context } from 'aws-lambda';
59125

60-
### Examples
61126

62-
* [CDK](https://github.com/awslabs/aws-lambda-powertools-typescript/tree/main/examples/cdk)
63-
* [SAM](https://github.com/awslabs/aws-lambda-powertools-typescript/tree/main/examples/sam)
127+
const dynamoDBPersistenceLayer = new DynamoDBPersistenceLayer();
128+
const processingFunction = async (payload: Record<string, unknown>): Promise<void> => {
129+
// your lambda code here
130+
};
64131

65-
### Serverless TypeScript Demo application
132+
const processIdempotently = makeFunctionIdempotent(proccessingFunction, {
133+
persistenceStore: dynamoDBPersistenceLayer,
134+
dataKeywordArgument: "transactionId"
135+
});
66136

67-
The [Serverless TypeScript Demo](https://github.com/aws-samples/serverless-typescript-demo) shows how to use Powertools for AWS Lambda (TypeScript).
68-
You can find instructions on how to deploy and load test this application in the [repository](https://github.com/aws-samples/serverless-typescript-demo).
137+
export const handler = async (
138+
_event: any,
139+
_context: Context
140+
): Promise<void> => {
141+
for (const record of _event.Records) {
142+
await processIdempotently(record);
143+
}
144+
};
145+
```
69146

70147
## Contribute
71148

Diff for: packages/idempotency/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@
7171
},
7272
"main": "./lib/index.js",
7373
"types": "./lib/index.d.ts",
74-
"typedocMain": "src/file_that_does_not_exist_so_its_ignored_from_api_docs.ts",
7574
"files": [
7675
"lib"
7776
],
@@ -91,6 +90,7 @@
9190
"aws",
9291
"lambda",
9392
"powertools",
93+
"idempotency",
9494
"serverless",
9595
"nodejs"
9696
],

0 commit comments

Comments
 (0)