-
Notifications
You must be signed in to change notification settings - Fork 393
Add builder pattern support for event response types #1090
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 12 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
071ff54
Add builder pattern support for event response types
GradExMachina 06d9bb9
fmt+fix feature flag
GradExMachina 9f87a56
Update readme
GradExMachina fa2af97
feat: migrate from derive_builder to bon
GradExMachina f9fd468
docs: update README to reflect bon migration
GradExMachina 86cd174
style: run cargo fmt and clippy --fix
GradExMachina 09b5819
fix: allow clippy::should_implement_trait for 'sub' fields
GradExMachina 610b520
fix: move clippy allow to struct level for bon builders
GradExMachina bbd6773
fix: update examples to work with bon builders
GradExMachina 6afee4e
style: apply nightly rustfmt formatting
GradExMachina f40cfa1
fix: make SqsEvent other field optional in builder
GradExMachina 1231e8c
Fix nits
GradExMachina ebd69a6
Apply suggestion from @FullyTyped
GradExMachina b10f52b
fmt
GradExMachina File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| [package] | ||
| name = "lambda-events-examples" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
| publish = false | ||
|
|
||
| [dependencies] | ||
| aws_lambda_events = { path = "..", features = ["builders"] } | ||
| lambda_runtime = { path = "../../lambda-runtime" } | ||
| serde = { version = "1", features = ["derive"] } | ||
| serde_json = "1" | ||
| chrono = { version = "0.4", default-features = false, features = ["clock"] } | ||
| serde_dynamo = "4" | ||
|
|
||
| [[example]] | ||
| name = "comprehensive-builders" | ||
| path = "examples/comprehensive-builders.rs" | ||
|
|
||
| [[example]] | ||
| name = "lambda-runtime-authorizer-builder" | ||
| path = "examples/lambda-runtime-authorizer-builder.rs" | ||
|
|
||
| [[example]] | ||
| name = "lambda-runtime-sqs-batch-builder" | ||
| path = "examples/lambda-runtime-sqs-batch-builder.rs" |
103 changes: 103 additions & 0 deletions
103
lambda-events/lambda-events-examples/examples/comprehensive-builders.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| // Example demonstrating builder pattern usage for AWS Lambda events | ||
| use aws_lambda_events::event::{ | ||
| dynamodb::{Event as DynamoDbEvent, EventRecord as DynamoDbEventRecord, StreamRecord}, | ||
| kinesis::{KinesisEvent, KinesisEventRecord, KinesisRecord, KinesisEncryptionType}, | ||
| s3::{S3Event, S3EventRecord, S3Entity, S3Bucket, S3Object, S3RequestParameters, S3UserIdentity}, | ||
| secretsmanager::SecretsManagerSecretRotationEvent, | ||
| sns::{SnsEvent, SnsRecord, SnsMessage}, | ||
| sqs::{SqsEvent, SqsMessage}, | ||
| }; | ||
| use std::collections::HashMap; | ||
|
|
||
| fn main() { | ||
| // S3 Event - Object storage notifications with nested structures | ||
| let s3_record = S3EventRecord::builder() | ||
| .event_time(chrono::Utc::now()) | ||
| .principal_id(S3UserIdentity::builder().build()) | ||
| .request_parameters(S3RequestParameters::builder().build()) | ||
| .response_elements(HashMap::new()) | ||
| .s3(S3Entity::builder() | ||
| .bucket(S3Bucket::builder().name("my-bucket".to_string()).build()) | ||
| .object(S3Object::builder().key("file.txt".to_string()).size(1024).build()) | ||
| .build()) | ||
| .build(); | ||
| let _s3_event = S3Event::builder().records(vec![s3_record]).build(); | ||
|
|
||
| // Kinesis Event - Stream processing with data | ||
| let kinesis_record = KinesisEventRecord::builder() | ||
| .kinesis(KinesisRecord::builder() | ||
| .data(serde_json::from_str("\"SGVsbG8gV29ybGQ=\"").unwrap()) | ||
| .partition_key("key-1".to_string()) | ||
| .sequence_number("12345".to_string()) | ||
| .approximate_arrival_timestamp(serde_json::from_str("1234567890.0").unwrap()) | ||
| .encryption_type(KinesisEncryptionType::None) | ||
| .build()) | ||
| .build(); | ||
| let _kinesis_event = KinesisEvent::builder().records(vec![kinesis_record]).build(); | ||
|
|
||
| // DynamoDB Event - Database change streams with item data | ||
| let mut keys = HashMap::new(); | ||
| keys.insert("id".to_string(), serde_dynamo::AttributeValue::S("123".to_string())); | ||
|
|
||
| let dynamodb_record = DynamoDbEventRecord::builder() | ||
| .aws_region("us-east-1".to_string()) | ||
| .change(StreamRecord::builder() | ||
| .approximate_creation_date_time(chrono::Utc::now()) | ||
| .keys(keys.into()) | ||
| .new_image(HashMap::new().into()) | ||
| .old_image(HashMap::new().into()) | ||
| .size_bytes(100) | ||
| .build()) | ||
| .event_id("event-123".to_string()) | ||
| .event_name("INSERT".to_string()) | ||
| .build(); | ||
| let _dynamodb_event = DynamoDbEvent::builder().records(vec![dynamodb_record]).build(); | ||
|
|
||
| // SNS Event - Pub/sub messaging with message details | ||
| let sns_record = SnsRecord::builder() | ||
| .event_source("aws:sns".to_string()) | ||
| .event_version("1.0".to_string()) | ||
| .event_subscription_arn("arn:aws:sns:us-east-1:123456789012:topic".to_string()) | ||
| .sns(SnsMessage::builder() | ||
| .message("Hello from SNS".to_string()) | ||
| .sns_message_type("Notification".to_string()) | ||
| .message_id("msg-123".to_string()) | ||
| .topic_arn("arn:aws:sns:us-east-1:123456789012:topic".to_string()) | ||
| .timestamp(chrono::Utc::now()) | ||
| .signature_version("1".to_string()) | ||
| .signature("sig".to_string()) | ||
| .signing_cert_url("https://cert.url".to_string()) | ||
| .unsubscribe_url("https://unsub.url".to_string()) | ||
| .message_attributes(HashMap::new()) | ||
| .build()) | ||
| .build(); | ||
| let _sns_event = SnsEvent::builder().records(vec![sns_record]).build(); | ||
|
|
||
| // SQS Event - Queue messaging with attributes | ||
| let mut attrs = HashMap::new(); | ||
| attrs.insert("ApproximateReceiveCount".to_string(), "1".to_string()); | ||
| attrs.insert("SentTimestamp".to_string(), "1234567890".to_string()); | ||
|
|
||
| let sqs_message = SqsMessage::builder() | ||
| .attributes(attrs) | ||
| .message_attributes(HashMap::new()) | ||
| .body("message body".to_string()) | ||
| .message_id("msg-456".to_string()) | ||
| .build(); | ||
|
|
||
| #[cfg(feature = "catch-all-fields")] | ||
| let _sqs_event = SqsEvent::builder() | ||
| .records(vec![sqs_message]) | ||
| .other(serde_json::Map::new()) | ||
| .build(); | ||
|
|
||
| #[cfg(not(feature = "catch-all-fields"))] | ||
| let _sqs_event = SqsEvent::builder().records(vec![sqs_message]).build(); | ||
|
|
||
| // Secrets Manager Event - Secret rotation | ||
| let _secrets_event = SecretsManagerSecretRotationEvent::builder() | ||
| .step("createSecret".to_string()) | ||
| .secret_id("test-secret".to_string()) | ||
| .client_request_token("token-123".to_string()) | ||
| .build(); | ||
| } |
96 changes: 96 additions & 0 deletions
96
lambda-events/lambda-events-examples/examples/lambda-runtime-authorizer-builder.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| // Example showing how builders work with generic types and custom context structs | ||
| // | ||
| // Demonstrates: | ||
| // 1. Generic types (ApiGatewayV2CustomAuthorizerSimpleResponse<T>) | ||
| // 2. Custom context struct WITHOUT Default implementation | ||
| // 3. Custom context struct WITH Default implementation | ||
|
|
||
| use aws_lambda_events::event::apigw::{ | ||
| ApiGatewayV2CustomAuthorizerSimpleResponse, ApiGatewayV2CustomAuthorizerV2Request, | ||
| }; | ||
| use lambda_runtime::{Error, LambdaEvent}; | ||
| use serde::{Deserialize, Serialize}; | ||
|
|
||
| // Custom context WITHOUT Default - requires builder pattern | ||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||
| pub struct ContextWithoutDefault { | ||
| pub user_id: String, | ||
| pub api_key: String, | ||
| pub permissions: Vec<String>, | ||
| } | ||
|
|
||
| // Custom context WITH Default - works both ways | ||
| #[derive(Debug, Default, Clone, Serialize, Deserialize)] | ||
| pub struct ContextWithDefault { | ||
| pub user_id: String, | ||
| pub role: String, | ||
| } | ||
|
|
||
| // Handler using context WITHOUT Default - builder pattern required | ||
| pub async fn handler_without_default( | ||
| _event: LambdaEvent<ApiGatewayV2CustomAuthorizerV2Request>, | ||
| ) -> Result<ApiGatewayV2CustomAuthorizerSimpleResponse<ContextWithoutDefault>, Error> { | ||
| let context = ContextWithoutDefault { | ||
| user_id: "user-123".to_string(), | ||
| api_key: "secret-key".to_string(), | ||
| permissions: vec!["read".to_string()], | ||
| }; | ||
|
|
||
| let response = ApiGatewayV2CustomAuthorizerSimpleResponse::builder() | ||
| .is_authorized(true) | ||
| .context(context) | ||
| .build(); | ||
|
|
||
| Ok(response) | ||
| } | ||
|
|
||
| // Handler using context WITH Default - builder pattern still preferred | ||
| pub async fn handler_with_default( | ||
| _event: LambdaEvent<ApiGatewayV2CustomAuthorizerV2Request>, | ||
| ) -> Result<ApiGatewayV2CustomAuthorizerSimpleResponse<ContextWithDefault>, Error> { | ||
| let context = ContextWithDefault { | ||
| user_id: "user-456".to_string(), | ||
| role: "admin".to_string(), | ||
| }; | ||
|
|
||
| let response = ApiGatewayV2CustomAuthorizerSimpleResponse::builder() | ||
| .is_authorized(true) | ||
| .context(context) | ||
| .build(); | ||
|
|
||
| Ok(response) | ||
| } | ||
|
|
||
| fn main() { | ||
| // Example 1: Context WITHOUT Default | ||
| let context_no_default = ContextWithoutDefault { | ||
| user_id: "user-123".to_string(), | ||
| api_key: "secret-key".to_string(), | ||
| permissions: vec!["read".to_string(), "write".to_string()], | ||
| }; | ||
|
|
||
| let response1 = ApiGatewayV2CustomAuthorizerSimpleResponse::builder() | ||
| .is_authorized(true) | ||
| .context(context_no_default) | ||
| .build(); | ||
|
|
||
| println!("Response with context WITHOUT Default:"); | ||
| println!(" User: {}", response1.context.user_id); | ||
| println!(" Authorized: {}", response1.is_authorized); | ||
|
|
||
| // Example 2: Context WITH Default | ||
| let context_with_default = ContextWithDefault { | ||
| user_id: "user-456".to_string(), | ||
| role: "admin".to_string(), | ||
| }; | ||
|
|
||
| let response2 = ApiGatewayV2CustomAuthorizerSimpleResponse::builder() | ||
| .is_authorized(false) | ||
| .context(context_with_default) | ||
| .build(); | ||
|
|
||
| println!("\nResponse with context WITH Default:"); | ||
| println!(" User: {}", response2.context.user_id); | ||
| println!(" Role: {}", response2.context.role); | ||
| println!(" Authorized: {}", response2.is_authorized); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.