Skip to content

Commit badbb43

Browse files
authored
DynamoDB client wrapper (#9)
* feat: update package version to 0.3.0-alpha.2 and add DynamoDB client utilities - Updated package version in package.json - Added DynamoDB client and Document client utilities in dynamodb-client.ts - Implemented initialization, retrieval, and reset functions for DynamoDB clients - Created unit tests for DynamoDB client functionalities in dynamodb-client.test.ts - Exported new client utilities from index.ts * feat: enhance DynamoDB client utilities and update documentation
1 parent 32e40f3 commit badbb43

8 files changed

Lines changed: 3130 additions & 1251 deletions

File tree

README.md

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const handler = async (event: APIGatewayProxyEvent) => {
6767
- **📝 Structured Logging** – Pino logger pre-configured for Lambda with automatic AWS request context enrichment
6868
- **📤 API Response Helpers** – Standard response formatting for API Gateway with proper HTTP status codes
6969
- **⚙️ Configuration Validation** – Environment variable validation with Zod schema support
70-
- **🔌 AWS SDK Clients** – Pre-configured AWS SDK v3 clients for DynamoDB, Lambda, and more
70+
- **🔌 AWS SDK Clients** – Pre-configured AWS SDK v3 clients including DynamoDB with document client support
7171
- **🔒 Full TypeScript Support** – Complete type definitions and IDE autocomplete
7272
- **⚡ Lambda Optimized** – Designed for performance in serverless environments
7373

@@ -79,9 +79,7 @@ Comprehensive guides and examples are available in the `docs` directory:
7979
| ------------------------------------------------------------ | ---------------------------------------------------------------------- |
8080
| **[Logging Guide](./docs/LOGGING.md)** | Configure and use structured logging with automatic AWS Lambda context |
8181
| **[API Gateway Responses](./docs/API_GATEWAY_RESPONSES.md)** | Format responses for API Gateway with standard HTTP patterns |
82-
| **[Configuration](./docs/CONFIGURATION.md)** | Validate and manage environment variables with type safety |
83-
| **[AWS Clients](./docs/CLIENTS.md)** | Use pre-configured AWS SDK v3 clients in your handlers |
84-
| **[Getting Started](./docs/GETTING_STARTED.md)** | Setup and first steps guide |
82+
| **[AWS Clients](./docs/README.md)** | Use pre-configured AWS SDK v3 clients in your handlers |
8583

8684
## Usage
8785

@@ -119,39 +117,35 @@ export const handler = async (event: APIGatewayProxyEvent) => {
119117

120118
**→ See [API Gateway Responses](./docs/API_GATEWAY_RESPONSES.md) for all response types**
121119

122-
### Configuration Validation
123-
124-
Validate your Lambda environment configuration:
125-
126-
```typescript
127-
import { validateConfig } from '@leanstacks/lambda-utils';
128-
import { z } from 'zod';
129-
130-
const configSchema = z.object({
131-
DATABASE_URL: z.string().url(),
132-
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']),
133-
API_KEY: z.string(),
134-
});
135-
136-
const config = validateConfig(configSchema);
137-
```
120+
### AWS Clients
138121

139-
**→ See [Configuration](./docs/CONFIGURATION.md) for validation patterns**
122+
Use pre-configured AWS SDK v3 clients. Currently available:
140123

141-
### AWS Clients
124+
#### DynamoDB Client
142125

143-
Use pre-configured AWS SDK v3 clients:
126+
Initialize the DynamoDB clients (base client and document client) once during handler initialization:
144127

145128
```typescript
146-
import { getDynamoDBClient, getLambdaClient } from '@leanstacks/lambda-utils';
129+
import { initializeDynamoDBClients, getDynamoDBDocumentClient } from '@leanstacks/lambda-utils';
147130

148-
const dynamoDB = getDynamoDBClient();
149-
const lambda = getLambdaClient();
131+
export const handler = async (event: any, context: any) => {
132+
// Initialize clients once
133+
initializeDynamoDBClients({ region: 'us-east-1' });
134+
135+
// Use the document client for operations
136+
const docClient = getDynamoDBDocumentClient();
137+
const result = await docClient.get({
138+
TableName: 'MyTable',
139+
Key: { id: 'item-123' },
140+
});
150141

151-
// Use clients for API calls
142+
return { statusCode: 200, body: JSON.stringify(result) };
143+
};
152144
```
153145

154-
**→ See [AWS Clients](./docs/CLIENTS.md) for available clients and examples**
146+
**→ See [DynamoDB Client Guide](./docs/DYNAMODB_CLIENT.md) for detailed configuration and examples**
147+
148+
Additional AWS Clients are coming soon.
155149

156150
## Examples
157151

docs/DYNAMODB_CLIENT.md

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
# DynamoDB Client Utilities
2+
3+
The DynamoDB client utilities provide reusable singleton instances of `DynamoDBClient` and `DynamoDBDocumentClient` for use in AWS Lambda functions. These utilities enable you to configure clients once and reuse them across invocations, following AWS best practices for Lambda performance optimization.
4+
5+
## Overview
6+
7+
The utility exports the following functions:
8+
9+
- `initializeDynamoDBClients()` - Initialize both DynamoDB clients with optional configuration
10+
- `getDynamoDBClient()` - Get the singleton DynamoDB client instance
11+
- `getDynamoDBDocumentClient()` - Get the singleton DynamoDB Document client instance
12+
- `resetDynamoDBClients()` - Reset both client instances (useful for testing)
13+
14+
## Usage
15+
16+
### Basic Usage
17+
18+
```typescript
19+
import { initializeDynamoDBClients, getDynamoDBDocumentClient } from '@leanstacks/lambda-utils';
20+
import { PutCommand } from '@aws-sdk/lib-dynamodb';
21+
22+
// Initialize both clients (typically done once outside the handler)
23+
initializeDynamoDBClients({ region: 'us-east-1' });
24+
25+
export const handler = async (event: any) => {
26+
// Get the document client (most common use case)
27+
const docClient = getDynamoDBDocumentClient();
28+
29+
// Use the document client
30+
await docClient.send(
31+
new PutCommand({
32+
TableName: 'MyTable',
33+
Item: { id: '123', name: 'Example' },
34+
}),
35+
);
36+
};
37+
```
38+
39+
### Using the Base DynamoDB Client
40+
41+
````typescript
42+
import { initializeDynamoDBClients, getDynamoDBClient } from '@leanstacks/lambda-utils';
43+
import { PutItemCommand } from '@aws-sdk/client-dynamodb';
44+
45+
// Initialize both clients
46+
initializeDynamoDBClients({ region: 'us-east-1' });
47+
48+
export const handler = async (event: any) => {
49+
// Get the base client for advanced use cases
50+
const client = getDynamoDBClient();
51+
52+
// Use the base client
53+
await client.send(new PutItemCommand({
54+
TableName: 'MyTable',
55+
Item: { id: { S: '123' }, name: { S: 'Example' } }
56+
}));
57+
58+
### Advanced Configuration
59+
60+
#### Custom DynamoDB Client Configuration
61+
62+
```typescript
63+
import { initializeDynamoDBClients } from '@leanstacks/lambda-utils';
64+
65+
initializeDynamoDBClients({
66+
region: 'us-west-2',
67+
endpoint: 'http://localhost:8000', // For local development
68+
credentials: {
69+
accessKeyId: 'local',
70+
secretAccessKey: 'local',
71+
},
72+
});
73+
````
74+
75+
#### Custom Marshall/Unmarshall Options
76+
77+
```typescript
78+
import { initializeDynamoDBClients } from '@leanstacks/lambda-utils';
79+
80+
initializeDynamoDBClients(
81+
{ region: 'us-east-1' },
82+
{
83+
// Marshall options
84+
removeUndefinedValues: true,
85+
convertEmptyValues: false,
86+
convertClassInstanceToMap: true,
87+
},
88+
{
89+
// Unmarshall options
90+
wrapNumbers: false,
91+
},
92+
);
93+
```
94+
95+
### Lambda Handler Pattern
96+
97+
```typescript
98+
import { initializeDynamoDBClients, getDynamoDBDocumentClient } from '@leanstacks/lambda-utils';
99+
import { GetCommand } from '@aws-sdk/lib-dynamodb';
100+
101+
// Initialize clients outside the handler (runs once per cold start)
102+
initializeDynamoDBClients({ region: process.env.AWS_REGION }, { removeUndefinedValues: true });
103+
104+
// Handler function
105+
export const handler = async (event: any) => {
106+
const docClient = getDynamoDBDocumentClient();
107+
108+
const result = await docClient.send(
109+
new GetCommand({
110+
TableName: process.env.TABLE_NAME,
111+
Key: { id: event.id },
112+
}),
113+
);
114+
115+
return result.Item;
116+
};
117+
```
118+
119+
## API Reference
120+
121+
### `initializeDynamoDBClients(config?, marshallOptions?, unmarshallOptions?): { client: DynamoDBClient; documentClient: DynamoDBDocumentClient }`
122+
123+
Initializes both the DynamoDB client and DynamoDB Document client with the provided configuration.
124+
125+
**Parameters:**
126+
127+
- `config` (optional) - DynamoDB client configuration object
128+
- `marshallOptions` (optional) - Options for marshalling JavaScript objects to DynamoDB AttributeValues
129+
- `unmarshallOptions` (optional) - Options for unmarshalling DynamoDB AttributeValues to JavaScript objects
130+
131+
**Returns:**
132+
133+
- An object containing both `client` (DynamoDBClient) and `documentClient` (DynamoDBDocumentClient)
134+
135+
**Notes:**
136+
137+
- Creates both clients in a single call
138+
- If called multiple times, it will replace the existing client instances
139+
- If no config is provided, uses default AWS SDK configuration
140+
- Most users will only need the `documentClient` from the return value or via `getDynamoDBDocumentClient()`
141+
142+
### `getDynamoDBClient(): DynamoDBClient`
143+
144+
Returns the singleton DynamoDB client instance.
145+
146+
**Returns:**
147+
148+
- The `DynamoDBClient` instance
149+
150+
**Throws:**
151+
152+
- Error if the client has not been initialized
153+
154+
### `getDynamoDBDocumentClient(): DynamoDBDocumentClient`
155+
156+
Returns the singleton DynamoDB Document client instance.
157+
158+
**Returns:**
159+
160+
- The `DynamoDBDocumentClient` instance
161+
162+
**Throws:**
163+
164+
- Error if the document client has not been initialized
165+
166+
### `resetDynamoDBClients(): void`
167+
168+
Resets both DynamoDB client instances to null.
169+
170+
**Notes:**
171+
172+
- Primarily useful for testing scenarios where you need to reinitialize clients with different configurations
173+
- After calling this, you must reinitialize the clients before using the getter functions
174+
175+
## Best Practices
176+
177+
1. **Initialize Outside the Handler**: Always initialize clients outside your Lambda handler function to reuse the instance across invocations.
178+
179+
2. **Use Environment Variables**: Configure clients using environment variables for flexibility across environments.
180+
181+
3. **Error Handling**: Always wrap client operations in try-catch blocks to handle errors gracefully.
182+
183+
4. **Testing**: Use `resetDynamoDBClients()` in test setup/teardown to ensure clean test isolation.
184+
185+
## Testing Example
186+
187+
```typescript
188+
import { initializeDynamoDBClients, getDynamoDBDocumentClient, resetDynamoDBClients } from '@leanstacks/lambda-utils';
189+
190+
describe('MyLambdaHandler', () => {
191+
beforeEach(() => {
192+
resetDynamoDBClients();
193+
initializeDynamoDBClients(
194+
{ region: 'us-east-1', endpoint: 'http://localhost:8000' },
195+
{ removeUndefinedValues: true },
196+
);
197+
});
198+
199+
afterEach(() => {
200+
resetDynamoDBClients();
201+
});
202+
203+
it('should retrieve item from DynamoDB', async () => {
204+
// Your test code here
205+
});
206+
});
207+
```
208+
209+
## Related Resources
210+
211+
- **[AWS SDK for JavaScript v3 - DynamoDB Client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb/)**
212+
- **[AWS SDK for JavaScript v3 - DynamoDB Document Client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-lib-dynamodb/Class/DynamoDBDocumentClient/)**
213+
- **[AWS Lambda Best Practices](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html)**
214+
- **[Back to the project documentation](README.md)**

docs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ Lambda Utilities is a collection of pre-configured tools and helpers designed to
1010

1111
- **[Logging Guide](./LOGGING.md)** – Implement structured logging in your Lambda functions with Pino and automatic AWS context enrichment
1212
- **[API Gateway Responses](./API_GATEWAY_RESPONSES.md)** – Format Lambda responses for API Gateway with standard HTTP status codes and headers
13+
- **[DynamoDB Client](./DYNAMODB_CLIENT.md)** – Reusable singleton DynamoDB client instances with custom configuration
1314
- **[Configuration](./CONFIGURATION.md)** – Validate environment variables and configuration with Zod type safety
14-
- **[AWS Clients](./CLIENTS.md)** – Pre-configured AWS SDK v3 clients optimized for Lambda
1515
- **[Getting Started](./GETTING_STARTED.md)** – Quick setup and installation instructions
1616

1717
## Features

0 commit comments

Comments
 (0)