Skip to content

Commit c29772a

Browse files
authored
Merge branch 'main' into timeout-fixup
2 parents d4fa8aa + 61855c2 commit c29772a

87 files changed

Lines changed: 1552 additions & 62 deletions

File tree

Some content is hidden

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

.github/workflows/run-integration-test.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ on:
1010

1111
jobs:
1212
run-integration-tests:
13+
# Only run on the main repo, not forks
14+
if: ${{ github.repository_owner == 'aws' }}
1315
runs-on: ubuntu-latest
1416
steps:
1517
- name: install Cargo Lambda

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ members = [
99
"lambda-events",
1010
]
1111

12-
exclude = ["examples", "test-lmi"]
12+
exclude = ["examples","lambda-events/lambda-events-examples", "test-lmi"]
1313

1414
[workspace.dependencies]
1515
base64 = "0.22"

README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,80 @@ By default, the log level to emit events is `INFO`. Log at `TRACE` level for mor
449449

450450
This project includes Lambda event struct definitions, [`aws_lambda_events`](https://crates.io/crates/aws_lambda_events). This crate can be leveraged to provide strongly-typed Lambda event structs. You can create your own custom event objects and their corresponding structs as well.
451451

452+
### Builder pattern for event responses
453+
454+
The `aws_lambda_events` crate provides an optional `builders` feature that adds builder pattern support for constructing event responses. This is particularly useful when working with custom context types that don't implement `Default`.
455+
456+
Enable the builders feature in your `Cargo.toml`:
457+
458+
```toml
459+
[dependencies]
460+
aws_lambda_events = { version = "*", features = ["builders"] }
461+
```
462+
463+
Example with API Gateway custom authorizers:
464+
465+
```rust
466+
use aws_lambda_events::event::apigw::{
467+
ApiGatewayV2CustomAuthorizerSimpleResponseBuilder,
468+
ApiGatewayV2CustomAuthorizerV2Request,
469+
};
470+
use lambda_runtime::{Error, LambdaEvent};
471+
472+
struct MyContext {
473+
user_id: String,
474+
permissions: Vec<String>,
475+
}
476+
477+
async fn handler(
478+
event: LambdaEvent<ApiGatewayV2CustomAuthorizerV2Request>,
479+
) -> Result<ApiGatewayV2CustomAuthorizerSimpleResponse<MyContext>, Error> {
480+
let context = MyContext {
481+
user_id: "user-123".to_string(),
482+
permissions: vec!["read".to_string()],
483+
};
484+
485+
let response = ApiGatewayV2CustomAuthorizerSimpleResponseBuilder::default()
486+
.is_authorized(true)
487+
.context(context)
488+
.build()?;
489+
490+
Ok(response)
491+
}
492+
```
493+
494+
Example with SQS batch responses:
495+
496+
```rust
497+
use aws_lambda_events::event::sqs::{
498+
BatchItemFailureBuilder,
499+
SqsBatchResponseBuilder,
500+
SqsEvent,
501+
};
502+
use lambda_runtime::{Error, LambdaEvent};
503+
504+
async fn handler(event: LambdaEvent<SqsEvent>) -> Result<SqsBatchResponse, Error> {
505+
let mut failures = Vec::new();
506+
507+
for record in event.payload.records {
508+
if let Err(_) = process_record(&record).await {
509+
let failure = BatchItemFailureBuilder::default()
510+
.item_identifier(record.message_id.unwrap())
511+
.build()?;
512+
failures.push(failure);
513+
}
514+
}
515+
516+
let response = SqsBatchResponseBuilder::default()
517+
.batch_item_failures(failures)
518+
.build()?;
519+
520+
Ok(response)
521+
}
522+
```
523+
524+
See the [examples directory](https://github.com/aws/aws-lambda-rust-runtime/tree/main/lambda-events/examples) for more builder pattern examples.
525+
452526
### Custom event objects
453527

454528
To serialize and deserialize events and responses, we suggest using the [`serde`](https://github.com/serde-rs/serde) library. To receive custom events, annotate your structure with Serde's macros:

examples/basic-lambda-concurrent/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7-
lambda_runtime = { path = "../../lambda-runtime", features = ["experimental-concurrency"] }
7+
lambda_runtime = { path = "../../lambda-runtime", features = ["concurrency-tokio"] }
88
serde = "1.0.219"
99
tokio = { version = "1", features = ["macros"] }

lambda-events/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ edition = "2021"
2020
base64 = { workspace = true }
2121
bytes = { workspace = true, features = ["serde"], optional = true }
2222
chrono = { workspace = true, optional = true }
23+
bon = { version = "3", optional = true }
2324
flate2 = { version = "1.0.24", optional = true }
2425
http = { workspace = true, optional = true }
2526
http-body = { workspace = true, optional = true }
@@ -126,6 +127,7 @@ documentdb = []
126127
eventbridge = ["chrono", "serde_with"]
127128

128129
catch-all-fields = []
130+
builders = ["bon"]
129131

130132
[package.metadata.docs.rs]
131133
all-features = true

lambda-events/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,50 @@ This crate divides all Lambda Events into features named after the service that
2727
cargo add aws_lambda_events --no-default-features --features apigw,alb
2828
```
2929

30+
### Builder pattern support
31+
32+
The crate provides an optional `builders` feature that adds builder pattern support for event types. This enables type-safe, immutable construction of event responses with a clean, ergonomic API.
33+
34+
Enable the builders feature:
35+
36+
```
37+
cargo add aws_lambda_events --features builders
38+
```
39+
40+
Example using builders with API Gateway custom authorizers:
41+
42+
```rust
43+
use aws_lambda_events::event::apigw::{
44+
ApiGatewayV2CustomAuthorizerSimpleResponse,
45+
ApiGatewayV2CustomAuthorizerV2Request,
46+
};
47+
use lambda_runtime::{Error, LambdaEvent};
48+
49+
// Context type without Default implementation
50+
struct MyContext {
51+
user_id: String,
52+
permissions: Vec<String>,
53+
}
54+
55+
async fn handler(
56+
event: LambdaEvent<ApiGatewayV2CustomAuthorizerV2Request>,
57+
) -> Result<ApiGatewayV2CustomAuthorizerSimpleResponse<MyContext>, Error> {
58+
let context = MyContext {
59+
user_id: "user-123".to_string(),
60+
permissions: vec!["read".to_string()],
61+
};
62+
63+
let response = ApiGatewayV2CustomAuthorizerSimpleResponse::builder()
64+
.is_authorized(true)
65+
.context(context)
66+
.build();
67+
68+
Ok(response)
69+
}
70+
```
71+
72+
See the [examples directory](https://github.com/aws/aws-lambda-rust-runtime/tree/main/lambda-events/examples) for more builder pattern examples.
73+
3074
## History
3175

3276
The AWS Lambda Events crate was created by [Christian Legnitto](https://github.com/LegNeato). Without all his work and dedication, this project could have not been possible.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
name = "lambda-events-examples"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[dependencies]
8+
aws_lambda_events = { path = "..", features = ["builders"] }
9+
lambda_runtime = { path = "../../lambda-runtime" }
10+
serde = { version = "1", features = ["derive"] }
11+
serde_json = "1"
12+
chrono = { version = "0.4", default-features = false, features = ["clock"] }
13+
serde_dynamo = "4"
14+
15+
[[example]]
16+
name = "comprehensive-builders"
17+
path = "examples/comprehensive-builders.rs"
18+
19+
[[example]]
20+
name = "lambda-runtime-authorizer-builder"
21+
path = "examples/lambda-runtime-authorizer-builder.rs"
22+
23+
[[example]]
24+
name = "lambda-runtime-sqs-batch-builder"
25+
path = "examples/lambda-runtime-sqs-batch-builder.rs"
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Example demonstrating builder pattern usage for AWS Lambda events
2+
use aws_lambda_events::event::{
3+
dynamodb::{Event as DynamoDbEvent, EventRecord as DynamoDbEventRecord, StreamRecord},
4+
kinesis::{KinesisEvent, KinesisEventRecord, KinesisRecord, KinesisEncryptionType},
5+
s3::{S3Event, S3EventRecord, S3Entity, S3Bucket, S3Object, S3RequestParameters, S3UserIdentity},
6+
secretsmanager::SecretsManagerSecretRotationEvent,
7+
sns::{SnsEvent, SnsRecord, SnsMessage},
8+
sqs::{SqsEvent, SqsMessage},
9+
};
10+
use std::collections::HashMap;
11+
12+
fn main() {
13+
// S3 Event - Object storage notifications with nested structures
14+
let s3_record = S3EventRecord::builder()
15+
.event_time(chrono::Utc::now())
16+
.principal_id(S3UserIdentity::builder().build())
17+
.request_parameters(S3RequestParameters::builder().build())
18+
.response_elements(HashMap::new())
19+
.s3(S3Entity::builder()
20+
.bucket(S3Bucket::builder().name("my-bucket".to_string()).build())
21+
.object(S3Object::builder().key("file.txt".to_string()).size(1024).build())
22+
.build())
23+
.build();
24+
let _s3_event = S3Event::builder().records(vec![s3_record]).build();
25+
26+
// Kinesis Event - Stream processing with data
27+
let kinesis_record = KinesisEventRecord::builder()
28+
.kinesis(KinesisRecord::builder()
29+
.data(serde_json::from_str("\"SGVsbG8gV29ybGQ=\"").unwrap())
30+
.partition_key("key-1".to_string())
31+
.sequence_number("12345".to_string())
32+
.approximate_arrival_timestamp(serde_json::from_str("1234567890.0").unwrap())
33+
.encryption_type(KinesisEncryptionType::None)
34+
.build())
35+
.build();
36+
let _kinesis_event = KinesisEvent::builder().records(vec![kinesis_record]).build();
37+
38+
// DynamoDB Event - Database change streams with item data
39+
let mut keys = HashMap::new();
40+
keys.insert("id".to_string(), serde_dynamo::AttributeValue::S("123".to_string()));
41+
42+
let dynamodb_record = DynamoDbEventRecord::builder()
43+
.aws_region("us-east-1".to_string())
44+
.change(StreamRecord::builder()
45+
.approximate_creation_date_time(chrono::Utc::now())
46+
.keys(keys.into())
47+
.new_image(HashMap::new().into())
48+
.old_image(HashMap::new().into())
49+
.size_bytes(100)
50+
.build())
51+
.event_id("event-123".to_string())
52+
.event_name("INSERT".to_string())
53+
.build();
54+
let _dynamodb_event = DynamoDbEvent::builder().records(vec![dynamodb_record]).build();
55+
56+
// SNS Event - Pub/sub messaging with message details
57+
let sns_record = SnsRecord::builder()
58+
.event_source("aws:sns".to_string())
59+
.event_version("1.0".to_string())
60+
.event_subscription_arn("arn:aws:sns:us-east-1:123456789012:topic".to_string())
61+
.sns(SnsMessage::builder()
62+
.message("Hello from SNS".to_string())
63+
.sns_message_type("Notification".to_string())
64+
.message_id("msg-123".to_string())
65+
.topic_arn("arn:aws:sns:us-east-1:123456789012:topic".to_string())
66+
.timestamp(chrono::Utc::now())
67+
.signature_version("1".to_string())
68+
.signature("sig".to_string())
69+
.signing_cert_url("https://cert.url".to_string())
70+
.unsubscribe_url("https://unsub.url".to_string())
71+
.message_attributes(HashMap::new())
72+
.build())
73+
.build();
74+
let _sns_event = SnsEvent::builder().records(vec![sns_record]).build();
75+
76+
// SQS Event - Queue messaging with attributes
77+
let mut attrs = HashMap::new();
78+
attrs.insert("ApproximateReceiveCount".to_string(), "1".to_string());
79+
attrs.insert("SentTimestamp".to_string(), "1234567890".to_string());
80+
81+
let sqs_message = SqsMessage::builder()
82+
.attributes(attrs)
83+
.message_attributes(HashMap::new())
84+
.body("message body".to_string())
85+
.message_id("msg-456".to_string())
86+
.build();
87+
88+
#[cfg(feature = "catch-all-fields")]
89+
let _sqs_event = SqsEvent::builder()
90+
.records(vec![sqs_message])
91+
.other(serde_json::Map::new())
92+
.build();
93+
94+
#[cfg(not(feature = "catch-all-fields"))]
95+
let _sqs_event = SqsEvent::builder().records(vec![sqs_message]).build();
96+
97+
// Secrets Manager Event - Secret rotation
98+
let _secrets_event = SecretsManagerSecretRotationEvent::builder()
99+
.step("createSecret".to_string())
100+
.secret_id("test-secret".to_string())
101+
.client_request_token("token-123".to_string())
102+
.build();
103+
}

0 commit comments

Comments
 (0)