or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

common-patterns.mdcore-sdk.mddynamodb-service.mdindex.mds3-service.md

common-patterns.mddocs/

0

# Common Patterns

1

2

The AWS SDK for Java 1.x uses consistent patterns across all 371+ AWS services. Understanding these patterns allows you to work with any service efficiently.

3

4

## Client Creation Pattern

5

6

All AWS service clients follow the same builder pattern for creation.

7

8

### Pattern: Default Client

9

10

```java

11

// Simplest approach - uses default credentials and region providers

12

AmazonS3 s3 = AmazonS3ClientBuilder.defaultClient();

13

AmazonDynamoDB dynamoDB = AmazonDynamoDBClientBuilder.defaultClient();

14

AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

15

```

16

17

### Pattern: Standard Builder

18

19

```java

20

import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;

21

import com.amazonaws.regions.Regions;

22

import com.amazonaws.ClientConfiguration;

23

24

// Recommended for production - explicit configuration

25

AmazonS3 s3 = AmazonS3ClientBuilder.standard()

26

.withRegion(Regions.US_WEST_2)

27

.withCredentials(new DefaultAWSCredentialsProviderChain())

28

.withClientConfiguration(new ClientConfiguration()

29

.withMaxConnections(100)

30

.withConnectionTimeout(10000))

31

.build();

32

```

33

34

### Pattern: Custom Endpoint

35

36

```java

37

import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration;

38

39

// For testing with LocalStack, DynamoDB Local, or custom endpoints

40

AmazonDynamoDB dynamoDB = AmazonDynamoDBClientBuilder.standard()

41

.withEndpointConfiguration(new EndpointConfiguration(

42

"http://localhost:8000",

43

"us-west-2"

44

))

45

.build();

46

```

47

48

## Credential Configuration Pattern

49

50

### Pattern: Default Credential Chain (Recommended)

51

52

```java

53

import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;

54

55

// Automatically searches in order:

56

// 1. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)

57

// 2. System properties (aws.accessKeyId, aws.secretKey)

58

// 3. Web identity token

59

// 4. AWS credentials file (~/.aws/credentials)

60

// 5. ECS container credentials

61

// 6. EC2 instance profile credentials

62

63

DefaultAWSCredentialsProviderChain credentialsProvider =

64

new DefaultAWSCredentialsProviderChain();

65

66

AmazonS3 s3 = AmazonS3ClientBuilder.standard()

67

.withCredentials(credentialsProvider)

68

.build();

69

```

70

71

### Pattern: Environment Variables

72

73

```bash

74

# Set credentials via environment variables

75

export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE

76

export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

77

export AWS_REGION=us-west-2

78

```

79

80

```java

81

import com.amazonaws.auth.EnvironmentVariableCredentialsProvider;

82

83

AmazonS3 s3 = AmazonS3ClientBuilder.standard()

84

.withCredentials(new EnvironmentVariableCredentialsProvider())

85

.build();

86

```

87

88

### Pattern: AWS Profile

89

90

```java

91

import com.amazonaws.auth.profile.ProfileCredentialsProvider;

92

93

// Use specific profile from ~/.aws/credentials

94

ProfileCredentialsProvider credentialsProvider =

95

new ProfileCredentialsProvider("myprofile");

96

97

AmazonS3 s3 = AmazonS3ClientBuilder.standard()

98

.withCredentials(credentialsProvider)

99

.build();

100

```

101

102

### Pattern: IAM Role (EC2, ECS, Lambda)

103

104

```java

105

import com.amazonaws.auth.InstanceProfileCredentialsProvider;

106

107

// Automatically retrieves credentials from instance metadata

108

InstanceProfileCredentialsProvider credentialsProvider =

109

InstanceProfileCredentialsProvider.getInstance();

110

111

AmazonS3 s3 = AmazonS3ClientBuilder.standard()

112

.withCredentials(credentialsProvider)

113

.build();

114

```

115

116

### Pattern: Assume Role (STS)

117

118

```java

119

import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;

120

import com.amazonaws.services.securitytoken.AWSSecurityTokenService;

121

import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;

122

123

AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.defaultClient();

124

125

STSAssumeRoleSessionCredentialsProvider credentialsProvider =

126

new STSAssumeRoleSessionCredentialsProvider.Builder(

127

"arn:aws:iam::123456789012:role/MyRole",

128

"session-name"

129

).withStsClient(stsClient).build();

130

131

AmazonS3 s3 = AmazonS3ClientBuilder.standard()

132

.withCredentials(credentialsProvider)

133

.build();

134

```

135

136

## Request-Response Pattern

137

138

All service operations follow the request-response pattern.

139

140

### Pattern: Simple Request (Convenience Methods)

141

142

```java

143

// Many operations have convenience methods with common parameters

144

s3.putObject("my-bucket", "my-key", new File("/path/to/file"));

145

dynamoDB.getItem("MyTable", Map.of("id", new AttributeValue("123")));

146

```

147

148

### Pattern: Full Request Object

149

150

```java

151

import com.amazonaws.services.s3.model.*;

152

153

// Full control using request objects

154

PutObjectRequest request = new PutObjectRequest("my-bucket", "my-key", file)

155

.withCannedAcl(CannedAccessControlList.PublicRead)

156

.withStorageClass(StorageClass.StandardInfrequentAccess)

157

.withMetadata(metadata);

158

159

PutObjectResult result = s3.putObject(request);

160

String etag = result.getETag();

161

String versionId = result.getVersionId();

162

```

163

164

## Pagination Pattern

165

166

Most list operations return paginated results.

167

168

### Pattern: Manual Pagination with Continuation Token

169

170

```java

171

import com.amazonaws.services.s3.model.*;

172

173

// V2 API uses continuation token (RECOMMENDED)

174

ListObjectsV2Request request = new ListObjectsV2Request()

175

.withBucketName("my-bucket")

176

.withPrefix("photos/")

177

.withMaxKeys(1000);

178

179

ListObjectsV2Result result;

180

do {

181

result = s3.listObjectsV2(request);

182

183

// Process results

184

for (S3ObjectSummary summary : result.getObjectSummaries()) {

185

System.out.println(summary.getKey());

186

}

187

188

// Set continuation token for next page

189

request.setContinuationToken(result.getNextContinuationToken());

190

191

} while (result.isTruncated());

192

```

193

194

### Pattern: Pagination with Helper Method

195

196

```java

197

import com.amazonaws.services.s3.model.*;

198

199

// Some APIs provide helper methods for pagination

200

ObjectListing listing = s3.listObjects("my-bucket");

201

do {

202

for (S3ObjectSummary summary : listing.getObjectSummaries()) {

203

System.out.println(summary.getKey());

204

}

205

listing = s3.listNextBatchOfObjects(listing);

206

} while (listing.isTruncated());

207

```

208

209

### Pattern: DynamoDB Query Pagination

210

211

```java

212

import com.amazonaws.services.dynamodbv2.model.*;

213

214

QueryRequest queryRequest = new QueryRequest()

215

.withTableName("MyTable")

216

.withKeyConditionExpression("userId = :userId")

217

.withExpressionAttributeValues(

218

Map.of(":userId", new AttributeValue("123")))

219

.withLimit(100);

220

221

QueryResult result;

222

Map<String, AttributeValue> lastKey = null;

223

224

do {

225

if (lastKey != null) {

226

queryRequest.setExclusiveStartKey(lastKey);

227

}

228

229

result = dynamoDB.query(queryRequest);

230

231

// Process items

232

for (Map<String, AttributeValue> item : result.getItems()) {

233

// Process item

234

}

235

236

lastKey = result.getLastEvaluatedKey();

237

238

} while (lastKey != null);

239

```

240

241

## Asynchronous Operations Pattern

242

243

### Pattern: Async with Future

244

245

```java

246

import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync;

247

import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsyncClientBuilder;

248

import java.util.concurrent.Future;

249

250

// Create async client

251

AmazonDynamoDBAsync asyncClient = AmazonDynamoDBAsyncClientBuilder.standard()

252

.withRegion(Regions.US_EAST_1)

253

.build();

254

255

// Execute async operation

256

Future<PutItemResult> future = asyncClient.putItemAsync(putItemRequest);

257

258

// Continue with other work...

259

260

// Wait for result (blocking)

261

PutItemResult result = future.get();

262

```

263

264

### Pattern: Async with Callback

265

266

```java

267

import com.amazonaws.handlers.AsyncHandler;

268

269

asyncClient.putItemAsync(putItemRequest,

270

new AsyncHandler<PutItemRequest, PutItemResult>() {

271

@Override

272

public void onSuccess(PutItemRequest request, PutItemResult result) {

273

System.out.println("Put item succeeded");

274

// Handle success

275

}

276

277

@Override

278

public void onError(Exception exception) {

279

System.err.println("Put item failed: " + exception.getMessage());

280

// Handle error

281

}

282

});

283

284

// Non-blocking - continues immediately

285

```

286

287

## Exception Handling Pattern

288

289

### Pattern: Comprehensive Exception Handling

290

291

```java

292

import com.amazonaws.AmazonServiceException;

293

import com.amazonaws.SdkClientException;

294

295

try {

296

// Perform AWS operation

297

s3.getObject("my-bucket", "my-key");

298

299

} catch (AmazonServiceException ase) {

300

// Service-side error (4xx, 5xx HTTP status codes)

301

System.err.println("Service Error:");

302

System.err.println(" Error Code: " + ase.getErrorCode());

303

System.err.println(" Error Message: " + ase.getErrorMessage());

304

System.err.println(" HTTP Status: " + ase.getStatusCode());

305

System.err.println(" Request ID: " + ase.getRequestId());

306

System.err.println(" Service: " + ase.getServiceName());

307

308

// Handle specific error codes

309

switch (ase.getErrorCode()) {

310

case "NoSuchKey":

311

// Object doesn't exist

312

break;

313

case "AccessDenied":

314

// Permission denied

315

break;

316

case "NoSuchBucket":

317

// Bucket doesn't exist

318

break;

319

default:

320

// Other service errors

321

break;

322

}

323

324

} catch (SdkClientException sce) {

325

// Client-side error (network failure, parsing error, etc.)

326

System.err.println("Client Error: " + sce.getMessage());

327

328

if (sce.isRetryable()) {

329

// Error is retryable - implement retry logic

330

}

331

}

332

```

333

334

### Pattern: Service-Specific Exceptions

335

336

```java

337

import com.amazonaws.services.s3.model.AmazonS3Exception;

338

import com.amazonaws.services.dynamodbv2.model.ResourceNotFoundException;

339

340

try {

341

dynamoDB.describeTable("NonExistentTable");

342

} catch (ResourceNotFoundException e) {

343

System.err.println("Table does not exist");

344

} catch (AmazonServiceException e) {

345

System.err.println("Other DynamoDB error: " + e.getErrorCode());

346

}

347

348

try {

349

s3.getObject("my-bucket", "my-key");

350

} catch (AmazonS3Exception e) {

351

if (e.getStatusCode() == 404) {

352

System.err.println("Object not found");

353

}

354

}

355

```

356

357

## Waiter Pattern

358

359

Services with long-running operations provide waiters.

360

361

### Pattern: Basic Waiter

362

363

```java

364

import com.amazonaws.waiters.WaiterParameters;

365

import com.amazonaws.services.ec2.AmazonEC2;

366

import com.amazonaws.services.ec2.model.*;

367

368

AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

369

370

// Launch instance

371

RunInstancesRequest runRequest = new RunInstancesRequest()

372

.withImageId("ami-12345678")

373

.withInstanceType(InstanceType.T2Micro)

374

.withMinCount(1)

375

.withMaxCount(1);

376

377

RunInstancesResult runResult = ec2.runInstances(runRequest);

378

String instanceId = runResult.getReservation().getInstances().get(0).getInstanceId();

379

380

// Wait for instance to be running

381

try {

382

ec2.waiters().instanceRunning().run(

383

new WaiterParameters<>(

384

new DescribeInstancesRequest().withInstanceIds(instanceId)

385

)

386

);

387

System.out.println("Instance is running");

388

389

} catch (WaiterTimedOutException e) {

390

System.err.println("Timed out waiting for instance");

391

} catch (WaiterUnrecoverableException e) {

392

System.err.println("Instance entered unrecoverable state");

393

}

394

```

395

396

### Pattern: Waiter with Custom Polling

397

398

```java

399

import com.amazonaws.waiters.*;

400

401

PollingStrategy pollingStrategy = new PollingStrategy(

402

new MaxAttemptsRetryStrategy(40), // Max 40 attempts

403

new FixedDelayStrategy(15) // 15 seconds between attempts

404

);

405

406

ec2.waiters().instanceRunning().run(

407

new WaiterParameters<>(request)

408

.withPollingStrategy(pollingStrategy)

409

);

410

```

411

412

## Batch Operations Pattern

413

414

### Pattern: S3 Batch Delete

415

416

```java

417

import com.amazonaws.services.s3.model.*;

418

import java.util.ArrayList;

419

import java.util.List;

420

421

// Delete up to 1000 objects at once

422

DeleteObjectsRequest multiDeleteRequest = new DeleteObjectsRequest("my-bucket");

423

424

List<KeyVersion> keys = new ArrayList<>();

425

keys.add(new KeyVersion("file1.txt"));

426

keys.add(new KeyVersion("file2.txt"));

427

keys.add(new KeyVersion("file3.txt", "version-id")); // Specific version

428

429

multiDeleteRequest.setKeys(keys);

430

431

DeleteObjectsResult result = s3.deleteObjects(multiDeleteRequest);

432

433

// Check results

434

System.out.println("Deleted: " + result.getDeletedObjects().size());

435

for (DeleteError error : result.getErrors()) {

436

System.err.println("Failed to delete: " + error.getKey() +

437

" - " + error.getMessage());

438

}

439

```

440

441

### Pattern: DynamoDB Batch Write

442

443

```java

444

import com.amazonaws.services.dynamodbv2.model.*;

445

import java.util.*;

446

447

// Batch write up to 25 items

448

Map<String, List<WriteRequest>> requestItems = new HashMap<>();

449

List<WriteRequest> writes = new ArrayList<>();

450

451

// Add put requests

452

Map<String, AttributeValue> item1 = new HashMap<>();

453

item1.put("id", new AttributeValue("1"));

454

item1.put("name", new AttributeValue("Item 1"));

455

writes.add(new WriteRequest().withPutRequest(new PutRequest().withItem(item1)));

456

457

// Add delete requests

458

Map<String, AttributeValue> key2 = new HashMap<>();

459

key2.put("id", new AttributeValue("2"));

460

writes.add(new WriteRequest().withDeleteRequest(new DeleteRequest().withKey(key2)));

461

462

requestItems.put("MyTable", writes);

463

464

BatchWriteItemResult result = dynamoDB.batchWriteItem(requestItems);

465

466

// Handle unprocessed items

467

Map<String, List<WriteRequest>> unprocessed = result.getUnprocessedItems();

468

if (unprocessed != null && !unprocessed.isEmpty()) {

469

// Retry unprocessed items with exponential backoff

470

int retries = 0;

471

while (!unprocessed.isEmpty() && retries < 5) {

472

Thread.sleep((long) Math.pow(2, retries) * 1000); // Exponential backoff

473

result = dynamoDB.batchWriteItem(unprocessed);

474

unprocessed = result.getUnprocessedItems();

475

retries++;

476

}

477

}

478

```

479

480

### Pattern: DynamoDB Batch Get

481

482

```java

483

import com.amazonaws.services.dynamodbv2.model.*;

484

485

// Batch get up to 100 items

486

Map<String, KeysAndAttributes> requestItems = new HashMap<>();

487

488

List<Map<String, AttributeValue>> keys = new ArrayList<>();

489

keys.add(Map.of("id", new AttributeValue("1")));

490

keys.add(Map.of("id", new AttributeValue("2")));

491

keys.add(Map.of("id", new AttributeValue("3")));

492

493

KeysAndAttributes keysAndAttributes = new KeysAndAttributes()

494

.withKeys(keys)

495

.withConsistentRead(true);

496

497

requestItems.put("MyTable", keysAndAttributes);

498

499

BatchGetItemResult result = dynamoDB.batchGetItem(requestItems);

500

501

// Process results

502

List<Map<String, AttributeValue>> items = result.getResponses().get("MyTable");

503

for (Map<String, AttributeValue> item : items) {

504

System.out.println("Item: " + item.get("id").getS());

505

}

506

507

// Handle unprocessed keys

508

Map<String, KeysAndAttributes> unprocessed = result.getUnprocessedKeys();

509

if (unprocessed != null && !unprocessed.isEmpty()) {

510

// Retry unprocessed keys

511

result = dynamoDB.batchGetItem(unprocessed);

512

}

513

```

514

515

## Retry Pattern

516

517

### Pattern: Automatic Retries (Default)

518

519

```java

520

import com.amazonaws.ClientConfiguration;

521

import com.amazonaws.retry.PredefinedRetryPolicies;

522

523

// Default retry policy automatically retries transient errors

524

ClientConfiguration config = new ClientConfiguration()

525

.withRetryPolicy(PredefinedRetryPolicies.DEFAULT)

526

.withMaxErrorRetry(3);

527

528

AmazonS3 s3 = AmazonS3ClientBuilder.standard()

529

.withClientConfiguration(config)

530

.build();

531

532

// Automatic retries for:

533

// - Network failures

534

// - 500 Internal Server Error

535

// - 503 Service Unavailable

536

// - Throttling errors

537

```

538

539

### Pattern: Custom Retry Logic

540

541

```java

542

import com.amazonaws.AmazonServiceException;

543

544

int maxRetries = 3;

545

int retryCount = 0;

546

boolean success = false;

547

548

while (!success && retryCount < maxRetries) {

549

try {

550

dynamoDB.putItem(putItemRequest);

551

success = true;

552

553

} catch (AmazonServiceException e) {

554

if (e.getErrorCode().equals("ProvisionedThroughputExceededException")) {

555

retryCount++;

556

if (retryCount < maxRetries) {

557

// Exponential backoff

558

Thread.sleep((long) Math.pow(2, retryCount) * 1000);

559

} else {

560

throw e;

561

}

562

} else {

563

throw e; // Don't retry other errors

564

}

565

}

566

}

567

```

568

569

## Resource Management Pattern

570

571

### Pattern: Client Lifecycle

572

573

```java

574

// Clients are thread-safe and expensive to create - reuse them

575

public class MyService {

576

private final AmazonS3 s3;

577

private final AmazonDynamoDB dynamoDB;

578

579

public MyService() {

580

// Create clients once

581

this.s3 = AmazonS3ClientBuilder.defaultClient();

582

this.dynamoDB = AmazonDynamoDBClientBuilder.defaultClient();

583

}

584

585

public void doWork() {

586

// Reuse clients across multiple operations

587

s3.listBuckets();

588

dynamoDB.listTables();

589

}

590

591

// Optional: Shutdown when application terminates

592

public void shutdown() {

593

s3.shutdown();

594

dynamoDB.shutdown();

595

}

596

}

597

```

598

599

### Pattern: Try-with-Resources

600

601

```java

602

import com.amazonaws.services.s3.model.S3Object;

603

import com.amazonaws.services.s3.model.S3ObjectInputStream;

604

import java.io.BufferedReader;

605

import java.io.InputStreamReader;

606

607

// Always close S3Object input streams

608

try (S3Object object = s3.getObject("my-bucket", "my-key");

609

S3ObjectInputStream content = object.getObjectContent();

610

BufferedReader reader = new BufferedReader(new InputStreamReader(content))) {

611

612

String line;

613

while ((line = reader.readLine()) != null) {

614

System.out.println(line);

615

}

616

} // Streams are automatically closed

617

```

618

619

## Testing Pattern

620

621

### Pattern: Local Testing with Endpoint Override

622

623

```java

624

import org.junit.Before;

625

import org.junit.Test;

626

627

public class DynamoDBTest {

628

private AmazonDynamoDB dynamoDB;

629

630

@Before

631

public void setUp() {

632

// Point to DynamoDB Local for testing

633

dynamoDB = AmazonDynamoDBClientBuilder.standard()

634

.withEndpointConfiguration(

635

new EndpointConfiguration(

636

"http://localhost:8000",

637

"us-west-2"

638

))

639

.withCredentials(new AWSStaticCredentialsProvider(

640

new BasicAWSCredentials("dummy", "dummy")))

641

.build();

642

}

643

644

@Test

645

public void testPutItem() {

646

// Test against local DynamoDB

647

}

648

}

649

```

650

651

## Configuration Best Practices

652

653

### Pattern: Production-Ready Configuration

654

655

```java

656

import com.amazonaws.ClientConfiguration;

657

import com.amazonaws.retry.PredefinedRetryPolicies;

658

import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;

659

import com.amazonaws.regions.DefaultAwsRegionProviderChain;

660

661

// Production-ready client configuration

662

ClientConfiguration config = new ClientConfiguration()

663

// Connection pooling

664

.withMaxConnections(100)

665

.withConnectionTimeout(10000) // 10 seconds

666

.withSocketTimeout(50000) // 50 seconds

667

.withConnectionTTL(60000) // 60 seconds

668

669

// Timeouts

670

.withRequestTimeout(0) // Disabled (use socket timeout)

671

.withClientExecutionTimeout(0) // Disabled

672

673

// Retries

674

.withRetryPolicy(PredefinedRetryPolicies.DEFAULT)

675

.withMaxErrorRetry(3)

676

677

// User agent

678

.withUserAgentPrefix("MyApp/1.0");

679

680

// Build client with best practices

681

AmazonS3 s3 = AmazonS3ClientBuilder.standard()

682

.withRegion(new DefaultAwsRegionProviderChain().getRegion())

683

.withCredentials(new DefaultAWSCredentialsProviderChain())

684

.withClientConfiguration(config)

685

.build();

686

```

687

688

## Summary

689

690

These patterns are consistent across all 371+ AWS services in the SDK. Once you understand these core patterns, you can work with any AWS service efficiently. Key principles:

691

692

1. **Builder Pattern**: Use fluent builders for client creation

693

2. **Credential Chain**: Use DefaultAWSCredentialsProviderChain for flexibility

694

3. **Request/Response**: Every operation uses typed request and result objects

695

4. **Pagination**: Always handle paginated results properly

696

5. **Exception Handling**: Catch AmazonServiceException and SdkClientException

697

6. **Resource Management**: Reuse clients, close streams

698

7. **Batch Operations**: Use batch APIs to reduce API calls

699

8. **Waiters**: Use built-in waiters for polling instead of manual polling

700