├── src ├── sample-app │ ├── product-api │ │ ├── main.tf │ │ ├── test │ │ │ ├── ProductApi.IntegrationTests │ │ │ │ ├── Usings.cs │ │ │ │ ├── Setup.cs │ │ │ │ └── ProductApi.IntegrationTests.csproj │ │ │ └── ProductApi.Test │ │ │ │ ├── ProductApi.Test.csproj │ │ │ │ └── QueryTests.cs │ │ ├── provider.tf │ │ ├── application │ │ │ ├── ApplicationIntegrationPatterns.Core │ │ │ │ ├── Models │ │ │ │ │ ├── PricingHistory.cs │ │ │ │ │ └── IProductRepository.cs │ │ │ │ ├── ApplicationIntegrationPatterns.Core.csproj │ │ │ │ ├── Events │ │ │ │ │ └── ProductCreatedEvent.cs │ │ │ │ ├── Services │ │ │ │ │ ├── IProductCatalogueService.cs │ │ │ │ │ └── ILoggingService.cs │ │ │ │ ├── Queries │ │ │ │ │ └── GetProductQuery.cs │ │ │ │ ├── DataTransfer │ │ │ │ │ └── ProductDTO.cs │ │ │ │ └── Command │ │ │ │ │ ├── DeleteProductCommand.cs │ │ │ │ │ └── CreateProductCommand.cs │ │ │ ├── GetProduct │ │ │ │ ├── AssemblyInfo.cs │ │ │ │ ├── Properties │ │ │ │ │ └── launchSettings.json │ │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ │ └── GetProduct.csproj │ │ │ ├── CreateProduct │ │ │ │ ├── AssemblyInfo.cs │ │ │ │ ├── Properties │ │ │ │ │ └── launchSettings.json │ │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ │ └── CreateProduct.csproj │ │ │ ├── DeleteProduct │ │ │ │ ├── AssemblyInfo.cs │ │ │ │ ├── Properties │ │ │ │ │ └── launchSettings.json │ │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ │ └── DeleteProduct.csproj │ │ │ ├── UpdateProduct │ │ │ │ ├── AssemblyInfo.cs │ │ │ │ ├── Properties │ │ │ │ │ └── launchSettings.json │ │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ │ └── UpdateProduct.csproj │ │ │ ├── DynamoDbStreamHandler │ │ │ │ ├── AssemblyInfo.cs │ │ │ │ ├── Properties │ │ │ │ │ └── launchSettings.json │ │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ │ └── DynamoDbStreamHandler.csproj │ │ │ ├── ExternalEventPublisher │ │ │ │ ├── AssemblyInfo.cs │ │ │ │ ├── Properties │ │ │ │ │ └── launchSettings.json │ │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ │ └── ExternalEventPublisher.csproj │ │ │ ├── UpdateProductCatalogue │ │ │ │ ├── AssemblyInfo.cs │ │ │ │ ├── Properties │ │ │ │ │ └── launchSettings.json │ │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ │ └── UpdateProductCatalogue.csproj │ │ │ └── ApplicationIntegrationPatterns.Implementations │ │ │ │ ├── Models │ │ │ │ └── SnsToSqsMessageBody.cs │ │ │ │ ├── ProductCatalogueService.cs │ │ │ │ ├── SystemParameters.cs │ │ │ │ └── ApplicationIntegrationPatterns.Implementations.csproj │ │ ├── deploy.ps1 │ │ └── variables.tf │ ├── modules │ │ ├── sqs-queue-length-alarm │ │ │ ├── variables.tf │ │ │ └── main.tf │ │ ├── sqs-with-dlq │ │ │ ├── variables.tf │ │ │ ├── output.tf │ │ │ └── main.tf │ │ ├── api-gateway │ │ │ ├── output.tf │ │ │ ├── variables.tf │ │ │ └── main.tf │ │ ├── iam-policies │ │ │ ├── variables.tf │ │ │ ├── output.tf │ │ │ └── main.tf │ │ ├── lambda-function │ │ │ ├── output.tf │ │ │ ├── variables.tf │ │ │ └── main.tf │ │ ├── sqs-sourced-lambda-function │ │ │ ├── output.tf │ │ │ └── variables.tf │ │ └── api-gateway-lambda-integration │ │ │ ├── variables.tf │ │ │ └── main.tf │ ├── shared-infrastructure │ │ ├── variables.tf │ │ ├── outputs.tf │ │ ├── provider.tf │ │ └── main.tf │ ├── assets │ │ └── sample-app-architecture.png │ ├── Shared │ │ ├── Messaging │ │ │ ├── IQueuing.cs │ │ │ ├── IPublisher.cs │ │ │ ├── MessageWrapper.cs │ │ │ ├── SqsQueuing.cs │ │ │ └── SnsPublisher.cs │ │ ├── TraceUtils.cs │ │ ├── Shared.csproj │ │ ├── SnsTracedFunction.cs │ │ └── ActivityExtensions.cs │ ├── customer-service │ │ ├── provider.tf │ │ ├── deploy.ps1 │ │ └── variables.tf │ ├── purchase-order-service │ │ ├── provider.tf │ │ ├── deploy.ps1 │ │ ├── variables.tf │ │ └── ordering.tf │ └── README.md └── patterns │ ├── scatter-gather │ ├── tests │ │ └── ScatterGather.IntegrationTest │ │ │ ├── Usings.cs │ │ │ ├── ScatterGather.IntegrationTest.csproj │ │ │ └── TestStartup.cs │ ├── modules │ │ ├── vendor-loan-request-lambda │ │ │ ├── output.tf │ │ │ ├── variables.tf │ │ │ └── main.tf │ │ ├── lambda-function │ │ │ ├── output.tf │ │ │ ├── variables.tf │ │ │ └── main.tf │ │ └── event-bridge-lambda-target │ │ │ ├── variables.tf │ │ │ └── main.tf │ ├── deploy.ps1 │ ├── functions │ │ ├── Aggregator │ │ │ ├── AssemblyInfo.cs │ │ │ ├── DataTransfer │ │ │ │ ├── GenerateLoanQuoteRequest.cs │ │ │ │ └── AggregationResult.cs │ │ │ ├── Properties │ │ │ │ └── launchSettings.json │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ ├── Aggregator.csproj │ │ │ └── Function.cs │ │ ├── VendorLoanQuoteGenerator │ │ │ ├── AssemblyInfo.cs │ │ │ ├── DataTransfer │ │ │ │ ├── LoanQuoteResult.cs │ │ │ │ └── GenerateLoanQuoteRequest.cs │ │ │ ├── Properties │ │ │ │ └── launchSettings.json │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ └── VendorLoanQuoteGenerator.csproj │ │ └── VendorLoanQuoteResponseHandler │ │ │ ├── AssemblyInfo.cs │ │ │ ├── DataTransfer │ │ │ ├── LoanQuoteResult.cs │ │ │ └── GenerateLoanQuoteRequest.cs │ │ │ ├── Properties │ │ │ └── launchSettings.json │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ ├── VendorLoanQuoteResponseHandler.csproj │ │ │ └── Function.cs │ ├── provider.tf │ ├── variables.tf │ ├── data.tf │ └── statemachine │ │ └── scatter-gather-orchestration.asl.json │ ├── synchronous-api │ ├── tf-modules │ │ ├── iam-policies │ │ │ ├── variables.tf │ │ │ ├── output.tf │ │ │ ├── main.tf │ │ │ └── data.tf │ │ ├── api-gateway │ │ │ ├── output.tf │ │ │ ├── variables.tf │ │ │ └── main.tf │ │ ├── lambda-function │ │ │ ├── output.tf │ │ │ ├── variables.tf │ │ │ └── main.tf │ │ └── api-gateway-lambda-integration │ │ │ ├── variables.tf │ │ │ └── main.tf │ ├── test │ │ ├── ProductApi.IntegrationTests │ │ │ ├── Usings.cs │ │ │ ├── Setup.cs │ │ │ ├── ProductApi.IntegrationTests.csproj │ │ │ └── IntegrationTests.cs │ │ └── ProductApi.Test │ │ │ ├── ProductApi.Test.csproj │ │ │ ├── FunctionTests.cs │ │ │ └── QueryTests.cs │ ├── application │ │ ├── SynchronousApi.Core │ │ │ ├── Services │ │ │ │ └── ILoggingService.cs │ │ │ ├── Models │ │ │ │ ├── IProductRepository.cs │ │ │ │ └── PricingHistory.cs │ │ │ ├── SynchronousApi.Core.csproj │ │ │ ├── Queries │ │ │ │ └── GetProductQuery.cs │ │ │ ├── DataTransfer │ │ │ │ └── ProductDTO.cs │ │ │ └── Command │ │ │ │ └── CreateProductCommand.cs │ │ ├── CreateProduct │ │ │ ├── AssemblyInfo.cs │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ └── CreateProduct.csproj │ │ ├── GetProduct │ │ │ ├── AssemblyInfo.cs │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ └── GetProduct.csproj │ │ ├── SynchronousApi.Implementations │ │ │ ├── SerilogLogger.cs │ │ │ ├── Metrics.cs │ │ │ ├── SynchronousApi.Implementations.csproj │ │ │ └── Startup.cs │ │ └── SynchronousApi.sln │ ├── provider.tf │ ├── deploy.ps1 │ └── variables.tf │ ├── pub-sub │ ├── modules │ │ ├── iam-policies │ │ │ ├── variables.tf │ │ │ ├── output.tf │ │ │ ├── main.tf │ │ │ └── data.tf │ │ ├── api-gateway │ │ │ ├── output.tf │ │ │ ├── variables.tf │ │ │ └── main.tf │ │ ├── lambda-function │ │ │ ├── output.tf │ │ │ ├── variables.tf │ │ │ └── main.tf │ │ ├── event-bridge-lambda-target │ │ │ ├── variables.tf │ │ │ └── main.tf │ │ └── api-gateway-lambda-integration │ │ │ ├── variables.tf │ │ │ └── main.tf │ ├── functions │ │ ├── SNSPublisher │ │ │ ├── Events │ │ │ │ ├── ProductCreatedEvent.cs │ │ │ │ ├── EventBase.cs │ │ │ │ └── EventProducer.cs │ │ │ ├── AssemblyInfo.cs │ │ │ ├── Properties │ │ │ │ └── launchSettings.json │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ ├── SNSPublisher.csproj │ │ │ └── Function.cs │ │ ├── SNSSubscriber │ │ │ ├── Events │ │ │ │ ├── ProductCreatedEvent.cs │ │ │ │ └── EventBase.cs │ │ │ ├── AssemblyInfo.cs │ │ │ ├── Properties │ │ │ │ └── launchSettings.json │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ ├── Function.cs │ │ │ └── SNSSubscriber.csproj │ │ ├── EventBridgePublisher │ │ │ ├── Events │ │ │ │ ├── ProductCreatedEvent.cs │ │ │ │ ├── EventBase.cs │ │ │ │ └── EventProducer.cs │ │ │ ├── AssemblyInfo.cs │ │ │ ├── Properties │ │ │ │ └── launchSettings.json │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ ├── EventBridgePublisher.csproj │ │ │ └── Function.cs │ │ └── EventBridgeSubscriber │ │ │ ├── Events │ │ │ ├── ProductCreatedEvent.cs │ │ │ └── EventBase.cs │ │ │ ├── AssemblyInfo.cs │ │ │ ├── Properties │ │ │ └── launchSettings.json │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ ├── Function.cs │ │ │ └── EventBridgeSubscriber.csproj │ ├── deploy.ps1 │ ├── provider.tf │ └── variables.tf │ └── anti-corruption-layer │ ├── modules │ ├── iam-policies │ │ ├── variables.tf │ │ ├── output.tf │ │ ├── main.tf │ │ └── data.tf │ ├── api-gateway │ │ ├── output.tf │ │ ├── variables.tf │ │ └── main.tf │ ├── lambda-function │ │ ├── output.tf │ │ ├── variables.tf │ │ └── main.tf │ ├── event-bridge-lambda-target │ │ ├── variables.tf │ │ └── main.tf │ └── api-gateway-lambda-integration │ │ ├── variables.tf │ │ └── main.tf │ ├── functions │ ├── Membership.Shared │ │ ├── NewCustomerCreatedEventReceived.cs │ │ └── Membership.Shared.csproj │ ├── MembershipSendWelcomeEmail │ │ ├── Member.cs │ │ ├── AssemblyInfo.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── aws-lambda-tools-defaults.json │ │ ├── Function.cs │ │ └── MembershipSendWelcomeEmail.csproj │ ├── MembershipCustomerCreatedAdapter │ │ ├── Events │ │ │ └── NewCustomerCreatedEvent.cs │ │ ├── Member.cs │ │ ├── AssemblyInfo.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── aws-lambda-tools-defaults.json │ │ ├── MembershipCustomerCreatedAdapter.csproj │ │ └── Function.cs │ ├── NewCustomerPublisher │ │ ├── AssemblyInfo.cs │ │ ├── CreateCustomerRequest.cs │ │ ├── Events │ │ │ ├── IEventBase.cs │ │ │ ├── NewCustomerCreatedEvent.cs │ │ │ ├── EventBase.cs │ │ │ └── EventProducer.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── Customer.cs │ │ ├── aws-lambda-tools-defaults.json │ │ └── NewCustomerPublisher.csproj │ ├── MembershipAssignPoints │ │ ├── AssemblyInfo.cs │ │ ├── Member.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── aws-lambda-tools-defaults.json │ │ ├── MembershipAssignPoints.csproj │ │ └── Function.cs │ └── MembershipUpdateAnalytics │ │ ├── AssemblyInfo.cs │ │ ├── Member.cs │ │ ├── Properties │ │ └── launchSettings.json │ │ ├── aws-lambda-tools-defaults.json │ │ ├── Function.cs │ │ └── MembershipUpdateAnalytics.csproj │ ├── provider.tf │ ├── deploy.ps1 │ └── variables.tf ├── assets ├── acl.png ├── scatter-gather.png ├── patterns-pub-sub.png └── patterns-synchronous-api.png └── LICENSE /src/sample-app/product-api/main.tf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/patterns/scatter-gather/tests/ScatterGather.IntegrationTest/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; -------------------------------------------------------------------------------- /assets/acl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeastham1993/application-integration-patterns/HEAD/assets/acl.png -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/iam-policies/variables.tf: -------------------------------------------------------------------------------- 1 | variable "table_name" { 2 | type = string 3 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/test/ProductApi.IntegrationTests/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; 2 | global using System.Net.Http; -------------------------------------------------------------------------------- /src/patterns/synchronous-api/test/ProductApi.IntegrationTests/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; 2 | global using System.Net.Http; -------------------------------------------------------------------------------- /assets/scatter-gather.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeastham1993/application-integration-patterns/HEAD/assets/scatter-gather.png -------------------------------------------------------------------------------- /assets/patterns-pub-sub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeastham1993/application-integration-patterns/HEAD/assets/patterns-pub-sub.png -------------------------------------------------------------------------------- /assets/patterns-synchronous-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeastham1993/application-integration-patterns/HEAD/assets/patterns-synchronous-api.png -------------------------------------------------------------------------------- /src/sample-app/modules/sqs-queue-length-alarm/variables.tf: -------------------------------------------------------------------------------- 1 | variable "alarm_name" { 2 | type = string 3 | } 4 | 5 | variable "queue" { 6 | type = string 7 | } -------------------------------------------------------------------------------- /src/sample-app/modules/sqs-with-dlq/variables.tf: -------------------------------------------------------------------------------- 1 | variable "queue_name" { 2 | type = string 3 | } 4 | 5 | variable "max_receive_count" { 6 | type = number 7 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/iam-policies/variables.tf: -------------------------------------------------------------------------------- 1 | variable "event_bus_name" { 2 | type = string 3 | } 4 | 5 | variable "topic_name" { 6 | type = string 7 | } -------------------------------------------------------------------------------- /src/sample-app/shared-infrastructure/variables.tf: -------------------------------------------------------------------------------- 1 | variable "environment" { 2 | description = "The current environment" 3 | type = string 4 | default = "dev" 5 | } -------------------------------------------------------------------------------- /src/sample-app/assets/sample-app-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeastham1993/application-integration-patterns/HEAD/src/sample-app/assets/sample-app-architecture.png -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/iam-policies/variables.tf: -------------------------------------------------------------------------------- 1 | variable "event_bus_name" { 2 | type = string 3 | } 4 | 5 | variable "topic_name" { 6 | type = string 7 | } -------------------------------------------------------------------------------- /src/sample-app/Shared/Messaging/IQueuing.cs: -------------------------------------------------------------------------------- 1 | namespace Shared.Messaging; 2 | 3 | public interface IQueuing 4 | { 5 | Task Enqueue(string queueUrl, MessageWrapper message); 6 | } -------------------------------------------------------------------------------- /src/sample-app/Shared/Messaging/IPublisher.cs: -------------------------------------------------------------------------------- 1 | namespace Shared.Messaging; 2 | 3 | public interface IPublisher 4 | { 5 | Task Publish(string publishTo, MessageWrapper message); 6 | } -------------------------------------------------------------------------------- /src/sample-app/modules/api-gateway/output.tf: -------------------------------------------------------------------------------- 1 | output "api_id" { 2 | value = aws_apigatewayv2_api.lambda.id 3 | } 4 | 5 | output "api_arn" { 6 | value = aws_apigatewayv2_api.lambda.execution_arn 7 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/api-gateway/output.tf: -------------------------------------------------------------------------------- 1 | output "api_id" { 2 | value = aws_apigatewayv2_api.lambda.id 3 | } 4 | 5 | output "api_arn" { 6 | value = aws_apigatewayv2_api.lambda.execution_arn 7 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSPublisher/Events/ProductCreatedEvent.cs: -------------------------------------------------------------------------------- 1 | namespace SNSPublisher; 2 | 3 | public class ProductCreatedEvent : EventBase 4 | { 5 | public override string EventName => "product-created"; 6 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSSubscriber/Events/ProductCreatedEvent.cs: -------------------------------------------------------------------------------- 1 | namespace SNSSubscriber; 2 | 3 | public class ProductCreatedEvent : EventBase 4 | { 5 | public override string EventName => "product-created"; 6 | } -------------------------------------------------------------------------------- /src/sample-app/shared-infrastructure/outputs.tf: -------------------------------------------------------------------------------- 1 | output "EventBusArn" { 2 | value = module.eventbridge.eventbridge_bus_arn 3 | } 4 | 5 | output "EventBusName" { 6 | value = module.eventbridge.eventbridge_bus_name 7 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/modules/vendor-loan-request-lambda/output.tf: -------------------------------------------------------------------------------- 1 | output "function_arn" { 2 | value = module.lambda_vendor_loan_quote_generator.function_arn 3 | description = "The arn of the lambda function" 4 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/api-gateway/output.tf: -------------------------------------------------------------------------------- 1 | output "api_id" { 2 | value = aws_apigatewayv2_api.lambda.id 3 | } 4 | 5 | output "api_arn" { 6 | value = aws_apigatewayv2_api.lambda.execution_arn 7 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/api-gateway/output.tf: -------------------------------------------------------------------------------- 1 | output "api_id" { 2 | value = aws_apigatewayv2_api.lambda.id 3 | } 4 | 5 | output "api_arn" { 6 | value = aws_apigatewayv2_api.lambda.execution_arn 7 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgePublisher/Events/ProductCreatedEvent.cs: -------------------------------------------------------------------------------- 1 | namespace EventBridgePublisher; 2 | 3 | public class ProductCreatedEvent : EventBase 4 | { 5 | public override string EventName => "product-created"; 6 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgeSubscriber/Events/ProductCreatedEvent.cs: -------------------------------------------------------------------------------- 1 | namespace EventBridgePublisher; 2 | 3 | public class ProductCreatedEvent : EventBase 4 | { 5 | public override string EventName => "product-created"; 6 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/deploy.ps1: -------------------------------------------------------------------------------- 1 | dotnet publish .\functions\ScatterGatherFunctions.sln --configuration "Release" --framework "net6.0" /p:GenerateRuntimeConfigurationFiles=true --runtime linux-x64 --self-contained false 2 | terraform apply -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/Membership.Shared/NewCustomerCreatedEventReceived.cs: -------------------------------------------------------------------------------- 1 | namespace Membership.Shared; 2 | 3 | public class NewCustomerCreatedEventReceived 4 | { 5 | public string MemberCustomerId { get; set; } 6 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSPublisher/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSSubscriber/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgePublisher/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/Aggregator/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipSendWelcomeEmail/Member.cs: -------------------------------------------------------------------------------- 1 | namespace MembershipSendWelcomeEmail; 2 | 3 | public class Member 4 | { 5 | public string MemberId { get; set; } 6 | 7 | public void SendWelcomeEmail(){} 8 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgeSubscriber/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/pub-sub/deploy.ps1: -------------------------------------------------------------------------------- 1 | dotnet restore .\functions\PubSub.sln 2 | dotnet publish .\functions\PubSub.sln --configuration "Release" --framework "net6.0" /p:GenerateRuntimeConfigurationFiles=true --runtime linux-x64 --self-contained false 3 | terraform apply -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.Core/Services/ILoggingService.cs: -------------------------------------------------------------------------------- 1 | namespace SynchronousApi.Core.Services; 2 | 3 | public interface ILoggingService { 4 | void LogInfo(string message); 5 | 6 | void AddTraceId(string traceId); 7 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipCustomerCreatedAdapter/Events/NewCustomerCreatedEvent.cs: -------------------------------------------------------------------------------- 1 | namespace MembershipCustomerCreatedAdapter.Events; 2 | 3 | public class NewCustomerCreatedEvent 4 | { 5 | public string CustomerId { get; set; } 6 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipCustomerCreatedAdapter/Member.cs: -------------------------------------------------------------------------------- 1 | namespace MembershipAssignPoints; 2 | 3 | public class Member 4 | { 5 | public string MemberId { get; set; } 6 | 7 | public void RegisterInitialMembershipPoints(){} 8 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/NewCustomerPublisher/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteGenerator/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipAssignPoints/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipSendWelcomeEmail/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipUpdateAnalytics/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteResponseHandler/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.Core/Models/IProductRepository.cs: -------------------------------------------------------------------------------- 1 | namespace SynchronousApi.Core.Models; 2 | 3 | public interface IProductRepository 4 | { 5 | Task Create(Product product); 6 | 7 | Task Get(string productId); 8 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/NewCustomerPublisher/CreateCustomerRequest.cs: -------------------------------------------------------------------------------- 1 | namespace NewCustomerPublisher; 2 | 3 | public class CreateCustomerRequest 4 | { 5 | public string EmailAddress { get; set; } 6 | 7 | public string Name { get; set; } 8 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipCustomerCreatedAdapter/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/pub-sub/provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 4.0" 6 | } 7 | } 8 | } 9 | 10 | # Configure the AWS Provider 11 | provider "aws" { 12 | region = "eu-west-1" 13 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 4.0" 6 | } 7 | } 8 | } 9 | 10 | # Configure the AWS Provider 11 | provider "aws" { 12 | region = "eu-west-1" 13 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 4.0" 6 | } 7 | } 8 | } 9 | 10 | # Configure the AWS Provider 11 | provider "aws" { 12 | region = "eu-west-1" 13 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 4.0" 6 | } 7 | } 8 | } 9 | 10 | # Configure the AWS Provider 11 | provider "aws" { 12 | region = "eu-west-1" 13 | } -------------------------------------------------------------------------------- /src/sample-app/customer-service/provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 4.0" 6 | } 7 | } 8 | } 9 | 10 | # Configure the AWS Provider 11 | provider "aws" { 12 | region = "eu-west-1" 13 | } -------------------------------------------------------------------------------- /src/sample-app/modules/iam-policies/variables.tf: -------------------------------------------------------------------------------- 1 | variable "environment" { 2 | type = string 3 | default = "dev" 4 | } 5 | 6 | variable "table_name" { 7 | type = string 8 | default = "" 9 | } 10 | 11 | variable "topic_name" { 12 | type = string 13 | default = "" 14 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 4.0" 6 | } 7 | } 8 | } 9 | 10 | # Configure the AWS Provider 11 | provider "aws" { 12 | region = "eu-west-1" 13 | } -------------------------------------------------------------------------------- /src/sample-app/purchase-order-service/provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 4.0" 6 | } 7 | } 8 | } 9 | 10 | # Configure the AWS Provider 11 | provider "aws" { 12 | region = "eu-west-1" 13 | } -------------------------------------------------------------------------------- /src/sample-app/shared-infrastructure/provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 4.0" 6 | } 7 | } 8 | } 9 | 10 | # Configure the AWS Provider 11 | provider "aws" { 12 | region = "eu-west-1" 13 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/deploy.ps1: -------------------------------------------------------------------------------- 1 | dotnet restore .\functions\AntiCorruptionLayer.sln 2 | dotnet publish .\functions\AntiCorruptionLayer.sln --configuration "Release" --framework "net6.0" /p:GenerateRuntimeConfigurationFiles=true --runtime linux-x64 --self-contained false 3 | terraform apply -------------------------------------------------------------------------------- /src/patterns/synchronous-api/deploy.ps1: -------------------------------------------------------------------------------- 1 | dotnet test .\test\ProductApi.Test\ProductApi.Test.csproj 2 | dotnet publish .\application\SynchronousApi.sln --configuration "Release" --framework "net6.0" /p:GenerateRuntimeConfigurationFiles=true --runtime linux-x64 --self-contained false 3 | terraform apply -------------------------------------------------------------------------------- /src/sample-app/customer-service/deploy.ps1: -------------------------------------------------------------------------------- 1 | dotnet test .\test\ProductApi.Test\ProductApi.Test.csproj 2 | dotnet publish .\application\ApplicationIntegrationPatterns.sln --configuration "Release" --framework "net6.0" /p:GenerateRuntimeConfigurationFiles=true --runtime linux-x64 --self-contained false 3 | terraform apply -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSPublisher/Events/EventBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SNSPublisher; 4 | 5 | public abstract class EventBase 6 | { 7 | public abstract string EventName { get; } 8 | 9 | public string Source => $"/product-service/{Environment.GetEnvironmentVariable("dev")}"; 10 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSSubscriber/Events/EventBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SNSSubscriber; 4 | 5 | public abstract class EventBase 6 | { 7 | public abstract string EventName { get; } 8 | 9 | public string Source => $"/product-service/{Environment.GetEnvironmentVariable("dev")}"; 10 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.Core/Models/PricingHistory.cs: -------------------------------------------------------------------------------- 1 | namespace SynchronousApi.Core.Models; 2 | 3 | public record PricingHistory(DateTime Date, decimal Price) 4 | { 5 | public DateTime Date { get; private set; } = Date; 6 | 7 | public decimal Price { get; private set; } = Price; 8 | } -------------------------------------------------------------------------------- /src/sample-app/purchase-order-service/deploy.ps1: -------------------------------------------------------------------------------- 1 | dotnet test .\test\ProductApi.Test\ProductApi.Test.csproj 2 | dotnet publish .\application\ApplicationIntegrationPatterns.sln --configuration "Release" --framework "net6.0" /p:GenerateRuntimeConfigurationFiles=true --runtime linux-x64 --self-contained false 3 | terraform apply -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/NewCustomerPublisher/Events/IEventBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewCustomerPublisher.Events; 4 | 5 | public interface IEventBase 6 | { 7 | string EventName { get; } 8 | 9 | string Source => $"/product-service/{Environment.GetEnvironmentVariable("dev")}"; 10 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/NewCustomerPublisher/Events/NewCustomerCreatedEvent.cs: -------------------------------------------------------------------------------- 1 | namespace NewCustomerPublisher.Events; 2 | 3 | public class NewCustomerCreatedEvent : EventBase, IEventBase 4 | { 5 | public override string EventName => "customer-created"; 6 | 7 | public string CustomerId { get; set; } 8 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgePublisher/Events/EventBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EventBridgePublisher; 4 | 5 | public abstract class EventBase 6 | { 7 | public abstract string EventName { get; } 8 | 9 | public string Source => $"/product-service/{Environment.GetEnvironmentVariable("dev")}"; 10 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgeSubscriber/Events/EventBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EventBridgePublisher; 4 | 5 | public abstract class EventBase 6 | { 7 | public abstract string EventName { get; } 8 | 9 | public string Source => $"/product-service/{Environment.GetEnvironmentVariable("dev")}"; 10 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.Core/SynchronousApi.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/Aggregator/DataTransfer/GenerateLoanQuoteRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Aggregator.DataTransfer; 2 | 3 | public class GenerateLoanQuoteRequest 4 | { 5 | public string CustomerId { get; set; } 6 | 7 | public string CorrelationId { get; set; } 8 | 9 | public decimal LoanAmount { get; set; } 10 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/Membership.Shared/Membership.Shared.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Core/Models/PricingHistory.cs: -------------------------------------------------------------------------------- 1 | namespace ApplicationIntegrationPatterns.Core.Models; 2 | 3 | public record PricingHistory(DateTime Date, decimal Price) 4 | { 5 | public DateTime Date { get; private set; } = Date; 6 | 7 | public decimal Price { get; private set; } = Price; 8 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/NewCustomerPublisher/Events/EventBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewCustomerPublisher.Events; 4 | 5 | public abstract class EventBase 6 | { 7 | public abstract string EventName { get; } 8 | 9 | public string Source => $"/product-service/{Environment.GetEnvironmentVariable("dev")}"; 10 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/iam-policies/output.tf: -------------------------------------------------------------------------------- 1 | output "event_bridge_put_events" { 2 | value = aws_iam_policy.event_bridge_put_events 3 | } 4 | 5 | output "sns_publish" { 6 | value = aws_iam_policy.sns_publish 7 | } 8 | 9 | output "cloud_watch_put_metrics" { 10 | value = aws_iam_policy.cloud_watch_put_metrics.arn 11 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteGenerator/DataTransfer/LoanQuoteResult.cs: -------------------------------------------------------------------------------- 1 | namespace VendorLoanQuoteGenerator.DataTransfer; 2 | 3 | public class LoanQuoteResult 4 | { 5 | public GenerateLoanQuoteRequest Request { get; set; } 6 | 7 | public string VendorName { get; set; } 8 | 9 | public double InterestRate { get; set; } 10 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/iam-policies/output.tf: -------------------------------------------------------------------------------- 1 | output "dynamo_db_read" { 2 | value = aws_iam_policy.dynamo_db_read.arn 3 | } 4 | 5 | output "dynamo_db_write" { 6 | value = aws_iam_policy.dynamo_db_write.arn 7 | } 8 | 9 | output "cloud_watch_put_metrics" { 10 | value = aws_iam_policy.cloud_watch_put_metrics.arn 11 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/iam-policies/output.tf: -------------------------------------------------------------------------------- 1 | output "event_bridge_put_events" { 2 | value = aws_iam_policy.event_bridge_put_events 3 | } 4 | 5 | output "sns_publish" { 6 | value = aws_iam_policy.sns_publish 7 | } 8 | 9 | output "cloud_watch_put_metrics" { 10 | value = aws_iam_policy.cloud_watch_put_metrics.arn 11 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteGenerator/DataTransfer/GenerateLoanQuoteRequest.cs: -------------------------------------------------------------------------------- 1 | namespace VendorLoanQuoteGenerator.DataTransfer; 2 | 3 | public class GenerateLoanQuoteRequest 4 | { 5 | public string CustomerId { get; set; } 6 | 7 | public string CorrelationId { get; set; } 8 | 9 | public decimal LoanAmount { get; set; } 10 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipUpdateAnalytics/Member.cs: -------------------------------------------------------------------------------- 1 | namespace MembershipUpdateAnalytics; 2 | 3 | public class Member 4 | { 5 | public string MemberId { get; set; } 6 | 7 | public void BeginSignupProcess(){} 8 | 9 | public void SendSignupEmail(){} 10 | 11 | public void RegisterInitialMembershipPoints(){} 12 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteResponseHandler/DataTransfer/LoanQuoteResult.cs: -------------------------------------------------------------------------------- 1 | namespace VendorLoanQuoteResponseHandler.DataTransfer; 2 | 3 | public class LoanQuoteResult 4 | { 5 | public GenerateLoanQuoteRequest Request { get; set; } 6 | 7 | public double InterestRate { get; set; } 8 | 9 | public string VendorName { get; set; } 10 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/variables.tf: -------------------------------------------------------------------------------- 1 | variable "table_name" { 2 | description = "The name of the DyanamoDB table" 3 | type = string 4 | default = "VendorLoanResponseStore" 5 | } 6 | 7 | variable "event_bus_name" { 8 | description = "The name of the EventBridge event bus" 9 | type = string 10 | default = "application-integration-bus" 11 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteResponseHandler/DataTransfer/GenerateLoanQuoteRequest.cs: -------------------------------------------------------------------------------- 1 | namespace VendorLoanQuoteResponseHandler.DataTransfer; 2 | 3 | public class GenerateLoanQuoteRequest 4 | { 5 | public string CustomerId { get; set; } 6 | 7 | public string CorrelationId { get; set; } 8 | 9 | public decimal LoanAmount { get; set; } 10 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipAssignPoints/Member.cs: -------------------------------------------------------------------------------- 1 | using AWS.Lambda.Powertools.Logging; 2 | 3 | namespace MembershipAssignPoints; 4 | 5 | public class Member 6 | { 7 | public string MemberId { get; set; } 8 | 9 | public void RegisterInitialMembershipPoints() 10 | { 11 | Logger.LogInformation("20 signup points added"); 12 | } 13 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/variables.tf: -------------------------------------------------------------------------------- 1 | variable "table_name" { 2 | description = "The name of the DyanamoDB table" 3 | type = string 4 | default = "SynchronousApiExample" 5 | } 6 | 7 | variable "code_bucket_name" { 8 | description = "The name of the S3 bucket to store Lambda source code" 9 | type = string 10 | default = "synchronous-api-source-code-bucket" 11 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSPublisher/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSSubscriber/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/GetProduct/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly:InternalsVisibleTo("ProductApi.Test")] 5 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 6 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/Aggregator/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/CreateProduct/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly:InternalsVisibleTo("ProductApi.Test")] 5 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 6 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/GetProduct/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly:InternalsVisibleTo("ProductApi.Test")] 5 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 6 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Core/Models/IProductRepository.cs: -------------------------------------------------------------------------------- 1 | namespace ApplicationIntegrationPatterns.Core.Models; 2 | 3 | public interface IProductRepository 4 | { 5 | Task Create(Product product); 6 | 7 | Task Get(string productId); 8 | 9 | Task Update(Product product); 10 | 11 | Task Delete(string productId); 12 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/CreateProduct/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly:InternalsVisibleTo("ProductApi.Test")] 5 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 6 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/sample-app/product-api/application/DeleteProduct/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly:InternalsVisibleTo("ProductApi.Test")] 5 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 6 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/sample-app/product-api/application/GetProduct/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/UpdateProduct/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly:InternalsVisibleTo("ProductApi.Test")] 5 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 6 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgePublisher/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgeSubscriber/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/CreateProduct/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/DeleteProduct/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/UpdateProduct/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Core/ApplicationIntegrationPatterns.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | true 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/sample-app/product-api/application/DynamoDbStreamHandler/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly:InternalsVisibleTo("ProductApi.Test")] 5 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 6 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/sample-app/product-api/application/DynamoDbStreamHandler/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ExternalEventPublisher/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly:InternalsVisibleTo("ProductApi.Test")] 5 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 6 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/sample-app/product-api/application/UpdateProductCatalogue/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Amazon.Lambda.Core; 3 | 4 | [assembly:InternalsVisibleTo("ProductApi.Test")] 5 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 6 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] -------------------------------------------------------------------------------- /src/sample-app/product-api/deploy.ps1: -------------------------------------------------------------------------------- 1 | dotnet test .\test\ProductApi.Test\ProductApi.Test.csproj 2 | dotnet publish .\application\ApplicationIntegrationPatterns.sln --configuration "Release" --framework "net6.0" /p:GenerateRuntimeConfigurationFiles=true --runtime linux-x64 --self-contained false 3 | terraform apply --var-file dev.tfvars 4 | dotnet test .\test\ProductApi.IntegrationTest\ProductApi.IntegrationTest.csproj -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/NewCustomerPublisher/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteGenerator/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Core/Events/ProductCreatedEvent.cs: -------------------------------------------------------------------------------- 1 | using ApplicationIntegrationPatterns.Core.DataTransfer; 2 | 3 | namespace ApplicationIntegrationPatterns.Core.Events 4 | { 5 | public record ProductCreatedEvent 6 | { 7 | public string EventName => "product-created"; 8 | 9 | public ProductDTO Product { get; init; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ExternalEventPublisher/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/UpdateProductCatalogue/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipAssignPoints/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipUpdateAnalytics/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteResponseHandler/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/sample-app/modules/api-gateway/variables.tf: -------------------------------------------------------------------------------- 1 | variable "api_name" { 2 | description = "The name of the HTTP API to create." 3 | type = string 4 | } 5 | 6 | variable "stage_name" { 7 | description = "The name of the API stage to create." 8 | type = string 9 | } 10 | 11 | variable "stage_auto_deploy" { 12 | description = "Should the API stage auto deploy." 13 | type = bool 14 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipSendWelcomeEmail/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipCustomerCreatedAdapter/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/api-gateway/variables.tf: -------------------------------------------------------------------------------- 1 | variable "api_name" { 2 | description = "The name of the HTTP API to create." 3 | type = string 4 | } 5 | 6 | variable "stage_name" { 7 | description = "The name of the API stage to create." 8 | type = string 9 | } 10 | 11 | variable "stage_auto_deploy" { 12 | description = "Should the API stage auto deploy." 13 | type = bool 14 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/api-gateway/variables.tf: -------------------------------------------------------------------------------- 1 | variable "api_name" { 2 | description = "The name of the HTTP API to create." 3 | type = string 4 | } 5 | 6 | variable "stage_name" { 7 | description = "The name of the API stage to create." 8 | type = string 9 | } 10 | 11 | variable "stage_auto_deploy" { 12 | description = "Should the API stage auto deploy." 13 | type = bool 14 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/api-gateway/variables.tf: -------------------------------------------------------------------------------- 1 | variable "api_name" { 2 | description = "The name of the HTTP API to create." 3 | type = string 4 | } 5 | 6 | variable "stage_name" { 7 | description = "The name of the API stage to create." 8 | type = string 9 | } 10 | 11 | variable "stage_auto_deploy" { 12 | description = "Should the API stage auto deploy." 13 | type = bool 14 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/Aggregator/DataTransfer/AggregationResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Aggregator.DataTransfer 8 | { 9 | public class AggregationResult 10 | { 11 | public string VendorName { get; set; } 12 | 13 | public double InterestRate { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/sample-app/Shared/TraceUtils.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Shared; 4 | 5 | public static class TraceUtils 6 | { 7 | public static (string filepath, int lineno, string function) 8 | CodeInfo( 9 | [CallerFilePath] string filePath = "", 10 | [CallerLineNumber] int lineno = -1, 11 | [CallerMemberName] string function = "") 12 | => (filePath, lineno, function); 13 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/test/ProductApi.IntegrationTests/Setup.cs: -------------------------------------------------------------------------------- 1 | using Amazon; 2 | using Amazon.CloudFormation; 3 | using Amazon.CloudFormation.Model; 4 | 5 | namespace ProductApi.IntegrationTests; 6 | 7 | public class Setup : IDisposable 8 | { 9 | public static string ApiUrl { get; set; } = ""; 10 | 11 | public Setup() 12 | { 13 | } 14 | 15 | public void Dispose() 16 | { 17 | // Do "global" teardown here; Only called once. 18 | } 19 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Core/Services/IProductCatalogueService.cs: -------------------------------------------------------------------------------- 1 | using ApplicationIntegrationPatterns.Core.Models; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace ApplicationIntegrationPatterns.Core.Services 9 | { 10 | public interface IProductCatalogueService 11 | { 12 | Task UpdateProduct(Product product); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/sample-app/customer-service/variables.tf: -------------------------------------------------------------------------------- 1 | variable "code_bucket_name" { 2 | description = "The name of the S3 bucket to store Lambda source code" 3 | type = string 4 | default = "purchase-order-service-source-code-bucket" 5 | } 6 | 7 | variable "environment" { 8 | description = "The current environment" 9 | type = string 10 | default = "dev" 11 | } 12 | 13 | variable "product_created_topic_arn" { 14 | description = "ARN for the product created topic" 15 | type = string 16 | } -------------------------------------------------------------------------------- /src/sample-app/purchase-order-service/variables.tf: -------------------------------------------------------------------------------- 1 | variable "code_bucket_name" { 2 | description = "The name of the S3 bucket to store Lambda source code" 3 | type = string 4 | default = "purchase-order-service-source-code-bucket" 5 | } 6 | 7 | variable "environment" { 8 | description = "The current environment" 9 | type = string 10 | default = "dev" 11 | } 12 | 13 | variable "product_created_topic_arn" { 14 | description = "ARN for the product created topic" 15 | type = string 16 | } -------------------------------------------------------------------------------- /src/sample-app/modules/sqs-queue-length-alarm/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_metric_alarm" "sqs_queue_length_alarm" { 2 | alarm_name = var.alarm_name 3 | comparison_operator = "GreaterThanOrEqualToThreshold" 4 | evaluation_periods = "1" 5 | metric_name = "ApproximateNumberOfMessagesVisible" 6 | namespace = "AWS/SQS" 7 | period = "60" 8 | statistic = "Average" 9 | threshold = 1 10 | treat_missing_data = "notBreaching" 11 | dimensions = { 12 | "QueueName" = var.queue 13 | } 14 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/test/ProductApi.IntegrationTests/Setup.cs: -------------------------------------------------------------------------------- 1 | using Amazon; 2 | using Amazon.CloudFormation; 3 | using Amazon.CloudFormation.Model; 4 | 5 | namespace ProductApi.IntegrationTests; 6 | 7 | public class Setup : IDisposable 8 | { 9 | public static string ApiUrl { get; set; } = "https://ei1g9jv0j3.execute-api.eu-west-1.amazonaws.com/dev/"; 10 | 11 | public Setup() 12 | { 13 | } 14 | 15 | public void Dispose() 16 | { 17 | // Do "global" teardown here; Only called once. 18 | } 19 | } -------------------------------------------------------------------------------- /src/sample-app/modules/lambda-function/output.tf: -------------------------------------------------------------------------------- 1 | output "function_arn" { 2 | value = aws_lambda_function.function.arn 3 | description = "The arn of the lambda function." 4 | } 5 | 6 | output "function_name" { 7 | value = aws_lambda_function.function.function_name 8 | description = "The name of the lambda function." 9 | } 10 | 11 | output function_role_arn { 12 | value = aws_lambda_function.function.role 13 | } 14 | 15 | output function_role_name { 16 | value = aws_iam_role.lambda_function_role.name 17 | } -------------------------------------------------------------------------------- /src/sample-app/modules/sqs-with-dlq/output.tf: -------------------------------------------------------------------------------- 1 | output "queue_id" { 2 | value = aws_sqs_queue.main_queue.id 3 | } 4 | 5 | output "queue_arn" { 6 | value = aws_sqs_queue.main_queue.arn 7 | } 8 | 9 | output "queue_name" { 10 | value = aws_sqs_queue.main_queue.name 11 | } 12 | 13 | output "dlq_id" { 14 | value = aws_sqs_queue.dead_letter_queue.id 15 | } 16 | 17 | output "dlq_arn" { 18 | value = aws_sqs_queue.dead_letter_queue.arn 19 | } 20 | 21 | output "dlq_name" { 22 | value = aws_sqs_queue.dead_letter_queue.name 23 | } 24 | -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Core/Services/ILoggingService.cs: -------------------------------------------------------------------------------- 1 | namespace ApplicationIntegrationPatterns.Core.Services; 2 | 3 | public interface ILoggingService { 4 | void LogInfo(string message); 5 | 6 | void LogWarning(Exception ex); 7 | 8 | void LogWarning(string message); 9 | 10 | void LogWarning(Exception ex, string message); 11 | 12 | void LogError(Exception ex); 13 | 14 | void LogError(string message); 15 | 16 | void LogError(Exception ex, string message); 17 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/lambda-function/output.tf: -------------------------------------------------------------------------------- 1 | output "function_arn" { 2 | value = aws_lambda_function.function.arn 3 | description = "The arn of the lambda function." 4 | } 5 | 6 | output "function_name" { 7 | value = aws_lambda_function.function.function_name 8 | description = "The name of the lambda function." 9 | } 10 | 11 | output function_role_arn { 12 | value = aws_lambda_function.function.role 13 | } 14 | 15 | output function_role_name { 16 | value = aws_iam_role.lambda_function_role.name 17 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/modules/lambda-function/output.tf: -------------------------------------------------------------------------------- 1 | output "function_arn" { 2 | value = aws_lambda_function.function.arn 3 | description = "The arn of the lambda function." 4 | } 5 | 6 | output "function_name" { 7 | value = aws_lambda_function.function.function_name 8 | description = "The name of the lambda function." 9 | } 10 | 11 | output function_role_arn { 12 | value = aws_lambda_function.function.role 13 | } 14 | 15 | output function_role_name { 16 | value = aws_iam_role.lambda_function_role.name 17 | } -------------------------------------------------------------------------------- /src/sample-app/modules/sqs-sourced-lambda-function/output.tf: -------------------------------------------------------------------------------- 1 | output "function_arn" { 2 | value = aws_lambda_function.function.arn 3 | description = "The arn of the lambda function." 4 | } 5 | 6 | output "function_name" { 7 | value = aws_lambda_function.function.function_name 8 | description = "The name of the lambda function." 9 | } 10 | 11 | output "function_role_arn" { 12 | value = aws_lambda_function.function.role 13 | } 14 | 15 | output "function_role_name" { 16 | value = aws_iam_role.lambda_function_role.name 17 | } 18 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/lambda-function/output.tf: -------------------------------------------------------------------------------- 1 | output "function_arn" { 2 | value = aws_lambda_function.function.arn 3 | description = "The arn of the lambda function." 4 | } 5 | 6 | output "function_name" { 7 | value = aws_lambda_function.function.function_name 8 | description = "The name of the lambda function." 9 | } 10 | 11 | output function_role_arn { 12 | value = aws_lambda_function.function.role 13 | } 14 | 15 | output function_role_name { 16 | value = aws_iam_role.lambda_function_role.name 17 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/lambda-function/output.tf: -------------------------------------------------------------------------------- 1 | output "function_arn" { 2 | value = aws_lambda_function.function.arn 3 | description = "The arn of the lambda function." 4 | } 5 | 6 | output "function_name" { 7 | value = aws_lambda_function.function.function_name 8 | description = "The name of the lambda function." 9 | } 10 | 11 | output function_role_arn { 12 | value = aws_lambda_function.function.role 13 | } 14 | 15 | output function_role_name { 16 | value = aws_iam_role.lambda_function_role.name 17 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/variables.tf: -------------------------------------------------------------------------------- 1 | variable "code_bucket_name" { 2 | description = "The name of the S3 bucket to store Lambda source code" 3 | type = string 4 | default = "pub-sub-source-code-bucket" 5 | } 6 | 7 | variable "event_bus_name" { 8 | description = "The name of the Amazon Event Bridge event bus to publish to" 9 | type = string 10 | default = "pub-sub-event-bridge" 11 | } 12 | 13 | variable "topic_name" { 14 | description = "The name of the AWS SNS Topic to publish to" 15 | type = string 16 | default = "pub-sub-topic" 17 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/variables.tf: -------------------------------------------------------------------------------- 1 | variable "code_bucket_name" { 2 | description = "The name of the S3 bucket to store Lambda source code" 3 | type = string 4 | default = "acl-source-code-bucket" 5 | } 6 | 7 | variable "event_bus_name" { 8 | description = "The name of the Amazon Event Bridge event bus to publish to" 9 | type = string 10 | default = "acl-event-bridge" 11 | } 12 | 13 | variable "topic_name" { 14 | description = "The name of the AWS SNS Topic to publish to" 15 | type = string 16 | default = "membership-customer-created-event" 17 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/NewCustomerPublisher/Customer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace NewCustomerPublisher; 5 | 6 | public class Customer 7 | { 8 | [JsonConstructor] 9 | private Customer() 10 | { 11 | } 12 | 13 | public Customer(string emailAddress, string name) 14 | { 15 | this.Id = Guid.NewGuid().ToString(); 16 | this.EmailAddress = emailAddress; 17 | this.Name = name; 18 | } 19 | public string Id { get; set; } 20 | public string EmailAddress { get; set; } 21 | public string Name { get; set; } 22 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSPublisher/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSSubscriber/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgePublisher/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/Aggregator/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/GetProduct/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/GetProduct/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgeSubscriber/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/CreateProduct/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/CreateProduct/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/DeleteProduct/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/UpdateProduct/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/DynamoDbStreamHandler/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ExternalEventPublisher/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/UpdateProductCatalogue/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/NewCustomerPublisher/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteGenerator/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/variables.tf: -------------------------------------------------------------------------------- 1 | variable "table_name" { 2 | description = "The name of the DyanamoDB table" 3 | type = string 4 | default = "ApplicationIntegrationPatternsExample" 5 | } 6 | 7 | variable "code_bucket_name" { 8 | description = "The name of the S3 bucket to store Lambda source code" 9 | type = string 10 | default = "synchronous-api-source-code-bucket" 11 | } 12 | 13 | variable "environment" { 14 | description = "The current environment" 15 | type = string 16 | default = "dev" 17 | } 18 | 19 | variable "honeycomb_api_key" { 20 | description = "API Key to pass to Honeycomb" 21 | type = string 22 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipAssignPoints/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipSendWelcomeEmail/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipUpdateAnalytics/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteResponseHandler/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipCustomerCreatedAdapter/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "template": "template.yaml" 12 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/iam-policies/main.tf: -------------------------------------------------------------------------------- 1 | # Create a set of IAM policies our application will need 2 | resource "aws_iam_policy" "event_bridge_put_events" { 3 | name = "event_bridge_put_events" 4 | path = "/" 5 | policy = data.aws_iam_policy_document.event_bridge_put_events.json 6 | } 7 | 8 | resource "aws_iam_policy" "sns_publish" { 9 | name = "sns_publish" 10 | path = "/" 11 | policy = data.aws_iam_policy_document.sns_publish.json 12 | } 13 | 14 | resource "aws_iam_policy" "cloud_watch_put_metrics" { 15 | name = "cloud_watch_put_metrics_policy" 16 | path = "/" 17 | policy = data.aws_iam_policy_document.cloud_watch_put_metrics.json 18 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Implementations/Models/SnsToSqsMessageBody.cs: -------------------------------------------------------------------------------- 1 | using Amazon.SimpleNotificationService.Model; 2 | namespace ApplicationIntegrationPatterns.Implementations.Models; 3 | 4 | public record SnsToSqsMessageBody 5 | { 6 | public string MessageId { get; set; } 7 | 8 | public string TopicArn { get; set; } 9 | 10 | public string Message { get; set; } 11 | 12 | public Dictionary MessageAttributes { get; set; } 13 | } 14 | 15 | public record StringMessageAttribute 16 | { 17 | public string Type { get; set; } 18 | 19 | public string Value { get; set; } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/iam-policies/main.tf: -------------------------------------------------------------------------------- 1 | # Create a set of IAM policies our application will need 2 | resource "aws_iam_policy" "dynamo_db_read" { 3 | name = "dynamo_db_read_policy" 4 | path = "/" 5 | policy = data.aws_iam_policy_document.dynamo_db_read.json 6 | } 7 | 8 | resource "aws_iam_policy" "dynamo_db_write" { 9 | name = "dynamo_db_write_policy" 10 | path = "/" 11 | policy = data.aws_iam_policy_document.dynamo_db_write.json 12 | } 13 | 14 | resource "aws_iam_policy" "cloud_watch_put_metrics" { 15 | name = "cloud_watch_put_metrics_policy" 16 | path = "/" 17 | policy = data.aws_iam_policy_document.cloud_watch_put_metrics.json 18 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgeSubscriber/Function.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using System.Text.Json; 4 | using Amazon.Lambda.Core; 5 | using EventBridgePublisher; 6 | using AWS.Lambda.Powertools.Tracing; 7 | using Amazon.Lambda.CloudWatchEvents; 8 | using AWS.Lambda.Powertools.Logging; 9 | 10 | namespace EventBridgeSubscriber 11 | { 12 | public class Function 13 | { 14 | [Tracing] 15 | public async Task FunctionHandler(CloudWatchEvent inputEvent, ILambdaContext context) 16 | { 17 | Logger.LogInformation(inputEvent.Detail.EventName); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/iam-policies/main.tf: -------------------------------------------------------------------------------- 1 | # Create a set of IAM policies our application will need 2 | resource "aws_iam_policy" "event_bridge_put_events" { 3 | name = "acl_event_bridge_put_events" 4 | path = "/" 5 | policy = data.aws_iam_policy_document.event_bridge_put_events.json 6 | } 7 | 8 | resource "aws_iam_policy" "sns_publish" { 9 | name = "acl_sns_publish" 10 | path = "/" 11 | policy = data.aws_iam_policy_document.sns_publish.json 12 | } 13 | 14 | resource "aws_iam_policy" "cloud_watch_put_metrics" { 15 | name = "acl_cloud_watch_put_metrics_policy" 16 | path = "/" 17 | policy = data.aws_iam_policy_document.cloud_watch_put_metrics.json 18 | } -------------------------------------------------------------------------------- /src/sample-app/shared-infrastructure/main.tf: -------------------------------------------------------------------------------- 1 | module "eventbridge" { 2 | source = "terraform-aws-modules/eventbridge/aws" 3 | bus_name = "${var.environment}-application-integration-patterns-samples" 4 | tags = { 5 | Name = "${var.environment}-application-integration-patterns-samples" 6 | } 7 | } 8 | 9 | resource "aws_ssm_parameter" "event_bus_name" { 10 | name = "/${var.environment}/shared/event_bus_name" 11 | type = "String" 12 | value = module.eventbridge.eventbridge_bus_name 13 | } 14 | 15 | resource "aws_ssm_parameter" "event_bus_arn" { 16 | name = "/${var.environment}/shared/event_bus_arn" 17 | type = "String" 18 | value = module.eventbridge.eventbridge_bus_arn 19 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/event-bridge-lambda-target/variables.tf: -------------------------------------------------------------------------------- 1 | variable "event_bridge_name" { 2 | description = "The name of the event bridge to publish to" 3 | type = string 4 | } 5 | 6 | variable "event_bridge_rule_name" { 7 | description = "The name of the event bridge rule" 8 | type = string 9 | } 10 | 11 | variable "lambda_function_name" { 12 | description = "The name of the lambda function to target" 13 | type = string 14 | } 15 | 16 | variable "lambda_function_arn" { 17 | description = "The ARN of the lambda function to target" 18 | type = string 19 | } 20 | 21 | variable "event_pattern" { 22 | description = "The event pattern to match" 23 | type = string 24 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/modules/event-bridge-lambda-target/variables.tf: -------------------------------------------------------------------------------- 1 | variable "event_bridge_name" { 2 | description = "The name of the event bridge to publish to" 3 | type = string 4 | } 5 | 6 | variable "event_bridge_rule_name" { 7 | description = "The name of the event bridge rule" 8 | type = string 9 | } 10 | 11 | variable "lambda_function_name" { 12 | description = "The name of the lambda function to target" 13 | type = string 14 | } 15 | 16 | variable "lambda_function_arn" { 17 | description = "The ARN of the lambda function to target" 18 | type = string 19 | } 20 | 21 | variable "event_pattern" { 22 | description = "The event pattern to match" 23 | type = string 24 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/event-bridge-lambda-target/variables.tf: -------------------------------------------------------------------------------- 1 | variable "event_bridge_name" { 2 | description = "The name of the event bridge to publish to" 3 | type = string 4 | } 5 | 6 | variable "event_bridge_rule_name" { 7 | description = "The name of the event bridge rule" 8 | type = string 9 | } 10 | 11 | variable "lambda_function_name" { 12 | description = "The name of the lambda function to target" 13 | type = string 14 | } 15 | 16 | variable "lambda_function_arn" { 17 | description = "The ARN of the lambda function to target" 18 | type = string 19 | } 20 | 21 | variable "event_pattern" { 22 | description = "The event pattern to match" 23 | type = string 24 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSPublisher/Events/EventProducer.cs: -------------------------------------------------------------------------------- 1 | using Amazon.SimpleNotificationService; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text.Json; 5 | using System.Threading.Tasks; 6 | 7 | namespace SNSPublisher; 8 | 9 | public class EventProducer 10 | { 11 | private readonly AmazonSimpleNotificationServiceClient _snsClient; 12 | 13 | public EventProducer(AmazonSimpleNotificationServiceClient snsClient) 14 | { 15 | this._snsClient = snsClient; 16 | } 17 | 18 | public async Task Publish(EventBase evt) 19 | { 20 | await this._snsClient.PublishAsync(Environment.GetEnvironmentVariable("PRODUCT_CREATED_TOPIC_ARN"), JsonSerializer.Serialize(evt)); 21 | } 22 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Implementations/ProductCatalogueService.cs: -------------------------------------------------------------------------------- 1 | using ApplicationIntegrationPatterns.Core.Models; 2 | using ApplicationIntegrationPatterns.Core.Services; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace ApplicationIntegrationPatterns.Implementations 10 | { 11 | public class ProductCatalogueService : IProductCatalogueService 12 | { 13 | public async Task UpdateProduct(Product product) 14 | { 15 | // Implementation to be added, faking work 16 | await Task.Delay(100); 17 | 18 | return; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/iam-policies/data.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "current" {} 2 | 3 | data "aws_iam_policy_document" "event_bridge_put_events" { 4 | statement { 5 | actions = ["events:PutEvents"] 6 | resources = ["arn:aws:events:*:${data.aws_caller_identity.current.account_id}:event-bus/${var.event_bus_name}"] 7 | } 8 | } 9 | 10 | data "aws_iam_policy_document" "sns_publish" { 11 | statement { 12 | actions = ["sns:Publish"] 13 | resources = ["arn:aws:sns:*:${data.aws_caller_identity.current.account_id}:${var.topic_name}"] 14 | } 15 | } 16 | 17 | data "aws_iam_policy_document" "cloud_watch_put_metrics" { 18 | statement { 19 | actions = ["cloudwatch:PutMetricData"] 20 | resources = ["*"] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/patterns/scatter-gather/modules/vendor-loan-request-lambda/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vendor_name" { 2 | description = "The name of the vendor" 3 | type = string 4 | } 5 | 6 | variable "lambda_bucket_id" { 7 | description = "The id of the bucket lambda function code will be stored" 8 | type = string 9 | } 10 | 11 | variable "event_bridge_arn" { 12 | description = "The ARN of the event bridge to publish to" 13 | type = string 14 | } 15 | 16 | variable "event_bridge_name" { 17 | description = "The name of the event bridge to publish to" 18 | type = string 19 | } 20 | 21 | variable "event_bridge_put_events_policy_arn" { 22 | description = "The arn of the event bridge put events policy" 23 | type = string 24 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/iam-policies/data.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "current" {} 2 | 3 | data "aws_iam_policy_document" "event_bridge_put_events" { 4 | statement { 5 | actions = ["events:PutEvents"] 6 | resources = ["arn:aws:events:*:${data.aws_caller_identity.current.account_id}:event-bus/${var.event_bus_name}"] 7 | } 8 | } 9 | 10 | data "aws_iam_policy_document" "sns_publish" { 11 | statement { 12 | actions = ["sns:Publish"] 13 | resources = ["arn:aws:sns:*:${data.aws_caller_identity.current.account_id}:${var.topic_name}"] 14 | } 15 | } 16 | 17 | data "aws_iam_policy_document" "cloud_watch_put_metrics" { 18 | statement { 19 | actions = ["cloudwatch:PutMetricData"] 20 | resources = ["*"] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/sample-app/modules/api-gateway-lambda-integration/variables.tf: -------------------------------------------------------------------------------- 1 | variable "api_id" { 2 | description = "The ID of the HTTP API to attach to." 3 | type = string 4 | } 5 | 6 | variable "api_arn" { 7 | description = "The ARN of the HTTP API to attach to." 8 | type = string 9 | } 10 | 11 | variable "function_arn" { 12 | description = "The ARN of the Lambda function." 13 | type = string 14 | } 15 | 16 | variable "function_name" { 17 | description = "The name of the Lambda function." 18 | type = string 19 | } 20 | 21 | variable "http_method" { 22 | description = "The HTTP method to use (GET, PUT, POST, DELETE)." 23 | type = string 24 | } 25 | 26 | variable "route" { 27 | description = "The API route." 28 | type = string 29 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/api-gateway-lambda-integration/variables.tf: -------------------------------------------------------------------------------- 1 | variable "api_id" { 2 | description = "The ID of the HTTP API to attach to." 3 | type = string 4 | } 5 | 6 | variable "api_arn" { 7 | description = "The ARN of the HTTP API to attach to." 8 | type = string 9 | } 10 | 11 | variable "function_arn" { 12 | description = "The ARN of the Lambda function." 13 | type = string 14 | } 15 | 16 | variable "function_name" { 17 | description = "The name of the Lambda function." 18 | type = string 19 | } 20 | 21 | variable "http_method" { 22 | description = "The HTTP method to use (GET, PUT, POST, DELETE)." 23 | type = string 24 | } 25 | 26 | variable "route" { 27 | description = "The API route." 28 | type = string 29 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/Aggregator/Aggregator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.Core/Queries/GetProductQuery.cs: -------------------------------------------------------------------------------- 1 | using SynchronousApi.Core.DataTransfer; 2 | using SynchronousApi.Core.Models; 3 | 4 | namespace SynchronousApi.Core.Queries; 5 | 6 | public record GetProductQuery(string ProductId) { } 7 | 8 | public class GetProductQueryHandler 9 | { 10 | private readonly IProductRepository _repo; 11 | 12 | public GetProductQueryHandler(IProductRepository repo) 13 | { 14 | _repo = repo; 15 | } 16 | 17 | public async Task Execute(GetProductQuery query) 18 | { 19 | var product = await this._repo.Get(query.ProductId); 20 | 21 | if (product == null) 22 | { 23 | return null; 24 | } 25 | 26 | return new ProductDTO(product); 27 | } 28 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/api-gateway-lambda-integration/variables.tf: -------------------------------------------------------------------------------- 1 | variable "api_id" { 2 | description = "The ID of the HTTP API to attach to." 3 | type = string 4 | } 5 | 6 | variable "api_arn" { 7 | description = "The ARN of the HTTP API to attach to." 8 | type = string 9 | } 10 | 11 | variable "function_arn" { 12 | description = "The ARN of the Lambda function." 13 | type = string 14 | } 15 | 16 | variable "function_name" { 17 | description = "The name of the Lambda function." 18 | type = string 19 | } 20 | 21 | variable "http_method" { 22 | description = "The HTTP method to use (GET, PUT, POST, DELETE)." 23 | type = string 24 | } 25 | 26 | variable "route" { 27 | description = "The API route." 28 | type = string 29 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/api-gateway-lambda-integration/variables.tf: -------------------------------------------------------------------------------- 1 | variable "api_id" { 2 | description = "The ID of the HTTP API to attach to." 3 | type = string 4 | } 5 | 6 | variable "api_arn" { 7 | description = "The ARN of the HTTP API to attach to." 8 | type = string 9 | } 10 | 11 | variable "function_arn" { 12 | description = "The ARN of the Lambda function." 13 | type = string 14 | } 15 | 16 | variable "function_name" { 17 | description = "The name of the Lambda function." 18 | type = string 19 | } 20 | 21 | variable "http_method" { 22 | description = "The HTTP method to use (GET, PUT, POST, DELETE)." 23 | type = string 24 | } 25 | 26 | variable "route" { 27 | description = "The API route." 28 | type = string 29 | } -------------------------------------------------------------------------------- /src/sample-app/README.md: -------------------------------------------------------------------------------- 1 | # Sample Application 2 | 3 | A sample application demonstrating application integration patterns in a real world setting. The front-end application receives requests to creates new products. On creation events are published to notify other systems, this demonstrates the publish/subscribe pattern. 4 | 5 | ![](./assets//sample-app-architecture.png) 6 | 7 | Product creation requests are created through an API Gateway endpoint and procesed by a Lambda function. Data is persisted into DynamoDB. An event handling Lambda is connected to the DynamoDB stream and for all insert events a 'product-created' event is published to an SNS Topic. 8 | 9 | The customer service and purchasing service are subscribed to product-created events and store the event data in a queue for further processing. 10 | 11 | -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteResponseHandler/VendorLoanQuoteResponseHandler.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/event-bridge-lambda-target/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_event_rule" "event_rule" { 2 | name = var.event_bridge_rule_name 3 | event_bus_name = var.event_bridge_name 4 | event_pattern = var.event_pattern 5 | } 6 | 7 | resource "aws_cloudwatch_event_target" "lambda_target" { 8 | rule = aws_cloudwatch_event_rule.event_rule.name 9 | target_id = var.lambda_function_name 10 | arn = var.lambda_function_arn 11 | event_bus_name = var.event_bridge_name 12 | } 13 | 14 | resource "aws_lambda_permission" "allow_event_bridge_to_call_lambda" { 15 | statement_id = "AllowExecutionFromCloudWatch" 16 | action = "lambda:InvokeFunction" 17 | function_name = var.lambda_function_name 18 | principal = "events.amazonaws.com" 19 | source_arn = aws_cloudwatch_event_rule.event_rule.arn 20 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/modules/event-bridge-lambda-target/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_event_rule" "event_rule" { 2 | name = var.event_bridge_rule_name 3 | event_bus_name = var.event_bridge_name 4 | event_pattern = var.event_pattern 5 | } 6 | 7 | resource "aws_cloudwatch_event_target" "lambda_target" { 8 | rule = aws_cloudwatch_event_rule.event_rule.name 9 | target_id = var.lambda_function_name 10 | arn = var.lambda_function_arn 11 | event_bus_name = var.event_bridge_name 12 | } 13 | 14 | resource "aws_lambda_permission" "allow_event_bridge_to_call_lambda" { 15 | statement_id = "AllowExecutionFromCloudWatch" 16 | action = "lambda:InvokeFunction" 17 | function_name = var.lambda_function_name 18 | principal = "events.amazonaws.com" 19 | source_arn = aws_cloudwatch_event_rule.event_rule.arn 20 | } -------------------------------------------------------------------------------- /src/sample-app/Shared/Messaging/MessageWrapper.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Shared.Messaging; 5 | 6 | public record MessageWrapper() 7 | { 8 | public MessageMetadata Metadata { get; set; } = new MessageMetadata(); 9 | 10 | public T Data { get; set; } 11 | } 12 | 13 | public record MessageMetadata 14 | { 15 | public MessageMetadata() 16 | { 17 | if (Activity.Current != null) 18 | { 19 | this.TraceParent = Activity.Current.TraceId.ToString(); 20 | this.ParentSpan = Activity.Current.SpanId.ToString(); 21 | } 22 | } 23 | 24 | [JsonPropertyName("traceparent")] 25 | public string TraceParent { get; set; } 26 | 27 | [JsonPropertyName("parentspan")] 28 | public string ParentSpan { get; set; } 29 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/event-bridge-lambda-target/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cloudwatch_event_rule" "event_rule" { 2 | name = var.event_bridge_rule_name 3 | event_bus_name = var.event_bridge_name 4 | event_pattern = var.event_pattern 5 | } 6 | 7 | resource "aws_cloudwatch_event_target" "lambda_target" { 8 | rule = aws_cloudwatch_event_rule.event_rule.name 9 | target_id = var.lambda_function_name 10 | arn = var.lambda_function_arn 11 | event_bus_name = var.event_bridge_name 12 | } 13 | 14 | resource "aws_lambda_permission" "allow_event_bridge_to_call_lambda" { 15 | statement_id = "AllowExecutionFromCloudWatch" 16 | action = "lambda:InvokeFunction" 17 | function_name = var.lambda_function_name 18 | principal = "events.amazonaws.com" 19 | source_arn = aws_cloudwatch_event_rule.event_rule.arn 20 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.Implementations/SerilogLogger.cs: -------------------------------------------------------------------------------- 1 | using SynchronousApi.Core.Services; 2 | using Serilog; 3 | using Serilog.Core; 4 | using Serilog.Formatting.Compact; 5 | 6 | namespace SynchronousApi.Implementations; 7 | 8 | public class SerilogLogger : ILoggingService 9 | { 10 | private readonly Logger _log; 11 | private string _traceId; 12 | 13 | public SerilogLogger() 14 | { 15 | _log = new LoggerConfiguration() 16 | .WriteTo.Console(new RenderedCompactJsonFormatter()) 17 | .CreateLogger(); 18 | } 19 | 20 | public void AddTraceId(string traceId) 21 | { 22 | this._traceId = traceId; 23 | } 24 | 25 | public void LogInfo(string message) 26 | { 27 | this._log.ForContext("TraceId", this._traceId).Information(message); 28 | } 29 | } -------------------------------------------------------------------------------- /src/sample-app/modules/api-gateway-lambda-integration/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_apigatewayv2_integration" "lambda_integration" { 2 | api_id = var.api_id 3 | 4 | integration_uri = var.function_arn 5 | integration_type = "AWS_PROXY" 6 | integration_method = var.http_method 7 | } 8 | 9 | resource "aws_apigatewayv2_route" "get_product_route" { 10 | api_id = var.api_id 11 | 12 | route_key = "${var.http_method} ${var.route}" 13 | target = "integrations/${aws_apigatewayv2_integration.lambda_integration.id}" 14 | } 15 | 16 | resource "aws_lambda_permission" "get_lambda_api_gw" { 17 | statement_id = "AllowLambdaExecutionFromAPIGateway_${var.function_name}" 18 | action = "lambda:InvokeFunction" 19 | function_name = var.function_name 20 | principal = "apigateway.amazonaws.com" 21 | 22 | source_arn = "${var.api_arn}/*/*" 23 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/api-gateway-lambda-integration/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_apigatewayv2_integration" "lambda_integration" { 2 | api_id = var.api_id 3 | 4 | integration_uri = var.function_arn 5 | integration_type = "AWS_PROXY" 6 | integration_method = var.http_method 7 | } 8 | 9 | resource "aws_apigatewayv2_route" "get_product_route" { 10 | api_id = var.api_id 11 | 12 | route_key = "${var.http_method} ${var.route}" 13 | target = "integrations/${aws_apigatewayv2_integration.lambda_integration.id}" 14 | } 15 | 16 | resource "aws_lambda_permission" "get_lambda_api_gw" { 17 | statement_id = "AllowLambdaExecutionFromAPIGateway_${var.function_name}" 18 | action = "lambda:InvokeFunction" 19 | function_name = var.function_name 20 | principal = "apigateway.amazonaws.com" 21 | 22 | source_arn = "${var.api_arn}/*/*" 23 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSSubscriber/Function.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Amazon.Lambda.Core; 3 | using AWS.Lambda.Powertools.Tracing; 4 | using Amazon.Lambda.CloudWatchEvents; 5 | using AWS.Lambda.Powertools.Logging; 6 | using Amazon.Lambda.SNSEvents; 7 | using System.Text.Json; 8 | 9 | namespace SNSSubscriber 10 | { 11 | public class Function 12 | { 13 | [Tracing] 14 | public async Task FunctionHandler(SNSEvent inputEvent, ILambdaContext context) 15 | { 16 | foreach (var record in inputEvent.Records) 17 | { 18 | var evtData = JsonSerializer.Deserialize(record.Sns.Message); 19 | 20 | Logger.LogInformation(evtData.EventName); 21 | Logger.LogInformation(evtData.Source); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Core/Queries/GetProductQuery.cs: -------------------------------------------------------------------------------- 1 | using ApplicationIntegrationPatterns.Core.DataTransfer; 2 | using ApplicationIntegrationPatterns.Core.Models; 3 | 4 | namespace ApplicationIntegrationPatterns.Core.Queries; 5 | 6 | public record GetProductQuery(string ProductId) { } 7 | 8 | public class GetProductQueryHandler 9 | { 10 | private readonly IProductRepository _repo; 11 | 12 | public GetProductQueryHandler(IProductRepository repo) 13 | { 14 | _repo = repo; 15 | } 16 | 17 | public async Task Execute(GetProductQuery query) 18 | { 19 | var product = await this._repo.Get(query.ProductId); 20 | 21 | if (product == null) 22 | { 23 | return null; 24 | } 25 | 26 | return new ProductDTO(product); 27 | } 28 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/lambda-function/variables.tf: -------------------------------------------------------------------------------- 1 | variable "publish_dir" { 2 | description = "The location of the published files." 3 | type = string 4 | } 5 | 6 | variable "zip_file" { 7 | description = "The location of the ZIP file" 8 | type = string 9 | } 10 | 11 | variable "lambda_bucket_id" { 12 | description = "The id of the bucket lambda function code will be stored" 13 | type = string 14 | } 15 | 16 | variable "function_name" { 17 | description = "The name of the Lambda function" 18 | type = string 19 | } 20 | 21 | variable "lambda_handler" { 22 | description = "The Lambda handler, defined as classlib::namespace.class::method" 23 | type = string 24 | } 25 | 26 | variable "environment_variables" { 27 | description = "Environment variables to pass to the Lambda function" 28 | type = map(string) 29 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/api-gateway-lambda-integration/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_apigatewayv2_integration" "lambda_integration" { 2 | api_id = var.api_id 3 | 4 | integration_uri = var.function_arn 5 | integration_type = "AWS_PROXY" 6 | integration_method = var.http_method 7 | } 8 | 9 | resource "aws_apigatewayv2_route" "get_product_route" { 10 | api_id = var.api_id 11 | 12 | route_key = "${var.http_method} ${var.route}" 13 | target = "integrations/${aws_apigatewayv2_integration.lambda_integration.id}" 14 | } 15 | 16 | resource "aws_lambda_permission" "get_lambda_api_gw" { 17 | statement_id = "AllowLambdaExecutionFromAPIGateway_${var.function_name}" 18 | action = "lambda:InvokeFunction" 19 | function_name = var.function_name 20 | principal = "apigateway.amazonaws.com" 21 | 22 | source_arn = "${var.api_arn}/*/*" 23 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/api-gateway-lambda-integration/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_apigatewayv2_integration" "lambda_integration" { 2 | api_id = var.api_id 3 | 4 | integration_uri = var.function_arn 5 | integration_type = "AWS_PROXY" 6 | integration_method = var.http_method 7 | } 8 | 9 | resource "aws_apigatewayv2_route" "get_product_route" { 10 | api_id = var.api_id 11 | 12 | route_key = "${var.http_method} ${var.route}" 13 | target = "integrations/${aws_apigatewayv2_integration.lambda_integration.id}" 14 | } 15 | 16 | resource "aws_lambda_permission" "get_lambda_api_gw" { 17 | statement_id = "AllowLambdaExecutionFromAPIGateway_${var.function_name}" 18 | action = "lambda:InvokeFunction" 19 | function_name = var.function_name 20 | principal = "apigateway.amazonaws.com" 21 | 22 | source_arn = "${var.api_arn}/*/*" 23 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/modules/lambda-function/variables.tf: -------------------------------------------------------------------------------- 1 | variable "publish_dir" { 2 | description = "The location of the published files." 3 | type = string 4 | } 5 | 6 | variable "zip_file" { 7 | description = "The location of the ZIP file" 8 | type = string 9 | } 10 | 11 | variable "lambda_bucket_id" { 12 | description = "The id of the bucket lambda function code will be stored" 13 | type = string 14 | } 15 | 16 | variable "function_name" { 17 | description = "The name of the Lambda function" 18 | type = string 19 | } 20 | 21 | variable "lambda_handler" { 22 | description = "The Lambda handler, defined as classlib::namespace.class::method" 23 | type = string 24 | } 25 | 26 | variable "environment_variables" { 27 | description = "Environment variables to pass to the Lambda function" 28 | type = map(string) 29 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/lambda-function/variables.tf: -------------------------------------------------------------------------------- 1 | variable "publish_dir" { 2 | description = "The location of the published files." 3 | type = string 4 | } 5 | 6 | variable "zip_file" { 7 | description = "The location of the ZIP file" 8 | type = string 9 | } 10 | 11 | variable "lambda_bucket_id" { 12 | description = "The id of the bucket lambda function code will be stored" 13 | type = string 14 | } 15 | 16 | variable "function_name" { 17 | description = "The name of the Lambda function" 18 | type = string 19 | } 20 | 21 | variable "lambda_handler" { 22 | description = "The Lambda handler, defined as classlib::namespace.class::method" 23 | type = string 24 | } 25 | 26 | variable "environment_variables" { 27 | description = "Environment variables to pass to the Lambda function" 28 | type = map(string) 29 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/lambda-function/variables.tf: -------------------------------------------------------------------------------- 1 | variable "publish_dir" { 2 | description = "The location of the published files." 3 | type = string 4 | } 5 | 6 | variable "zip_file" { 7 | description = "The location of the ZIP file" 8 | type = string 9 | } 10 | 11 | variable "lambda_bucket_id" { 12 | description = "The id of the bucket lambda function code will be stored" 13 | type = string 14 | } 15 | 16 | variable "function_name" { 17 | description = "The name of the Lambda function" 18 | type = string 19 | } 20 | 21 | variable "lambda_handler" { 22 | description = "The Lambda handler, defined as classlib::namespace.class::method" 23 | type = string 24 | } 25 | 26 | variable "environment_variables" { 27 | description = "Environment variables to pass to the Lambda function" 28 | type = map(string) 29 | } -------------------------------------------------------------------------------- /src/sample-app/modules/iam-policies/output.tf: -------------------------------------------------------------------------------- 1 | output "dynamo_db_read" { 2 | value = aws_iam_policy.dynamo_db_read.arn 3 | } 4 | 5 | output "dynamo_db_write" { 6 | value = aws_iam_policy.dynamo_db_write.arn 7 | } 8 | 9 | output "dynamo_db_crud" { 10 | value = aws_iam_policy.dynamo_db_crud.arn 11 | } 12 | 13 | output "dynamo_db_read_stream" { 14 | value = aws_iam_policy.dynamo_db_stream_read_policy.arn 15 | } 16 | 17 | output "cloud_watch_put_metrics" { 18 | value = aws_iam_policy.cloud_watch_put_metrics.arn 19 | } 20 | 21 | output "sns_publish_message" { 22 | value = aws_iam_policy.sns_publish_message.arn 23 | } 24 | 25 | output "event_bridge_put_events" { 26 | value = aws_iam_policy.event_bridge_put_events.arn 27 | } 28 | 29 | output "ssm_parameter_read" { 30 | value = aws_iam_policy.ssm_parameter_read.arn 31 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Implementations/SystemParameters.cs: -------------------------------------------------------------------------------- 1 | using Amazon.SimpleSystemsManagement; 2 | using Amazon.SimpleSystemsManagement.Model; 3 | 4 | namespace ApplicationIntegrationPatterns.Implementations 5 | { 6 | public class SystemParameters 7 | { 8 | private readonly AmazonSimpleSystemsManagementClient _client; 9 | 10 | public SystemParameters(AmazonSimpleSystemsManagementClient client) 11 | { 12 | this._client = client; 13 | } 14 | 15 | public async Task RetrieveParameter(string name) 16 | { 17 | var paramResult = await this._client.GetParameterAsync(new GetParameterRequest() 18 | { 19 | Name = name 20 | }); 21 | 22 | return paramResult.Parameter.Value; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteGenerator/VendorLoanQuoteGenerator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgeSubscriber/EventBridgeSubscriber.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/sample-app/modules/sqs-with-dlq/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_sqs_queue" "main_queue" { 2 | name = var.queue_name 3 | redrive_policy = jsonencode({ 4 | deadLetterTargetArn = aws_sqs_queue.dead_letter_queue.arn 5 | maxReceiveCount = var.max_receive_count 6 | }) 7 | } 8 | 9 | resource "aws_sqs_queue" "dead_letter_queue" { 10 | name = "${var.queue_name}-dlq" 11 | } 12 | 13 | resource "aws_cloudwatch_metric_alarm" "dlq_alarm" { 14 | alarm_name = "${var.queue_name}-alarm" 15 | comparison_operator = "GreaterThanOrEqualToThreshold" 16 | evaluation_periods = "1" 17 | metric_name = "ApproximateNumberOfMessagesVisible" 18 | namespace = "AWS/SQS" 19 | period = "60" 20 | statistic = "Average" 21 | threshold = 1 22 | treat_missing_data = "notBreaching" 23 | dimensions = { 24 | "QueueName" = aws_sqs_queue.dead_letter_queue.name 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSSubscriber/SNSSubscriber.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/sample-app/modules/lambda-function/variables.tf: -------------------------------------------------------------------------------- 1 | variable "publish_dir" { 2 | description = "The location of the published files." 3 | type = string 4 | } 5 | 6 | variable "zip_file" { 7 | description = "The location of the ZIP file" 8 | type = string 9 | } 10 | 11 | variable "lambda_bucket_id" { 12 | description = "The id of the bucket lambda function code will be stored" 13 | type = string 14 | } 15 | 16 | variable "function_name" { 17 | description = "The name of the Lambda function" 18 | type = string 19 | } 20 | 21 | variable "lambda_handler" { 22 | description = "The Lambda handler, defined as classlib::namespace.class::method" 23 | type = string 24 | } 25 | 26 | variable "environment_variables" { 27 | description = "Environment variables to pass to the Lambda function" 28 | type = map(string) 29 | } 30 | 31 | variable "honeycomb_api_key" { 32 | description = "API Key to pass to Honeycomb" 33 | type = string 34 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipSendWelcomeEmail/Function.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using System.Threading.Tasks; 3 | using Amazon.Lambda.Core; 4 | using Amazon.Lambda.SNSEvents; 5 | using AWS.Lambda.Powertools.Tracing; 6 | using Membership.Shared; 7 | 8 | namespace MembershipSendWelcomeEmail 9 | { 10 | 11 | public class Function 12 | { 13 | [Tracing] 14 | public async Task FunctionHandler(SNSEvent inputEvent, ILambdaContext context) 15 | { 16 | foreach (var snsEvent in inputEvent.Records) 17 | { 18 | var evtPayload = JsonSerializer.Deserialize(snsEvent.Sns.Message); 19 | 20 | var member = new Member() 21 | { 22 | MemberId = evtPayload.MemberCustomerId 23 | }; 24 | 25 | member.SendWelcomeEmail(); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.Implementations/Metrics.cs: -------------------------------------------------------------------------------- 1 | using Amazon.CloudWatch; 2 | using Amazon.CloudWatch.Model; 3 | 4 | namespace SynchronousApi.Implementations; 5 | 6 | public static class Metrics 7 | { 8 | private static AmazonCloudWatchClient _client; 9 | 10 | static Metrics() 11 | { 12 | _client = new AmazonCloudWatchClient(); 13 | } 14 | 15 | public static async Task IncrementMetric(string metric, double value) 16 | { 17 | var request = new PutMetricDataRequest 18 | { 19 | MetricData = new List 20 | { 21 | new MetricDatum 22 | { 23 | MetricName = metric, 24 | Value = value, 25 | Unit = StandardUnit.Count 26 | } 27 | }, 28 | Namespace = "DotnetLambdaSample" 29 | }; 30 | 31 | await _client.PutMetricDataAsync(request); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipUpdateAnalytics/Function.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using System.Threading.Tasks; 3 | using Amazon.Lambda.Core; 4 | using Amazon.Lambda.SNSEvents; 5 | using AWS.Lambda.Powertools.Tracing; 6 | using Membership.Shared; 7 | 8 | namespace MembershipUpdateAnalytics 9 | { 10 | 11 | public class Function 12 | { 13 | [Tracing] 14 | public async Task FunctionHandler(SNSEvent inputEvent, ILambdaContext context) 15 | { 16 | foreach (var snsEvent in inputEvent.Records) 17 | { 18 | var evtPayload = JsonSerializer.Deserialize(snsEvent.Sns.Message); 19 | 20 | var member = new Member() 21 | { 22 | MemberId = evtPayload.MemberCustomerId 23 | }; 24 | 25 | member.RegisterInitialMembershipPoints(); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipAssignPoints/MembershipAssignPoints.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/GetProduct/GetProduct.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipUpdateAnalytics/MembershipUpdateAnalytics.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/CreateProduct/CreateProduct.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipSendWelcomeEmail/MembershipSendWelcomeEmail.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.Core/DataTransfer/ProductDTO.cs: -------------------------------------------------------------------------------- 1 | using SynchronousApi.Core.Models; 2 | 3 | namespace SynchronousApi.Core.DataTransfer; 4 | 5 | public record ProductDTO 6 | { 7 | public ProductDTO(Product product) 8 | { 9 | this.ProductId = product.ProductId; 10 | this.Name = product.Name; 11 | this.Description = product.Description; 12 | this.CurrentPrice = product.Price; 13 | this.PricingHistory = new Dictionary(); 14 | 15 | foreach (var pricingHistory in product.PricingHistory) 16 | { 17 | this.PricingHistory.Add(pricingHistory.Date, pricingHistory.Price); 18 | } 19 | } 20 | 21 | public string ProductId { get; private set; } 22 | 23 | public string Name { get; private set; } 24 | 25 | public string Description { get; private set; } 26 | 27 | public decimal CurrentPrice { get; private set; } 28 | 29 | public Dictionary PricingHistory { get; private set; } 30 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/iam-policies/data.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "current" {} 2 | data "aws_region" "current" {} 3 | 4 | data "aws_iam_policy_document" "dynamo_db_read" { 5 | statement { 6 | actions = ["dynamodb:GetItem", "dynamodb:Scan", "dynamodb:Query", "dynamodb:BatchGetItem", "dynamodb:DescribeTable"] 7 | resources = ["arn:aws:dynamodb:*:${data.aws_caller_identity.current.account_id}:table/${var.table_name}", "arn:aws:dynamodb:*:*:table/${var.table_name}/*"] 8 | } 9 | } 10 | 11 | data "aws_iam_policy_document" "dynamo_db_write" { 12 | statement { 13 | actions = ["dynamodb:PutItem", 14 | "dynamodb:UpdateItem", 15 | "dynamodb:BatchWriteItem"] 16 | resources = ["arn:aws:dynamodb:*:${data.aws_caller_identity.current.account_id}:table/${var.table_name}", "arn:aws:dynamodb:*:${data.aws_caller_identity.current.account_id}:table/${var.table_name}/*"] 17 | } 18 | } 19 | 20 | data "aws_iam_policy_document" "cloud_watch_put_metrics" { 21 | statement { 22 | actions = ["cloudwatch:PutMetricData"] 23 | resources = ["*"] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.Implementations/SynchronousApi.Implementations.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/sample-app/product-api/test/ProductApi.IntegrationTests/ProductApi.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 James Eastham 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/patterns/scatter-gather/tests/ScatterGather.IntegrationTest/ScatterGather.IntegrationTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/test/ProductApi.IntegrationTests/ProductApi.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgePublisher/EventBridgePublisher.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSPublisher/SNSPublisher.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/test/ProductApi.Test/ProductApi.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/NewCustomerPublisher/NewCustomerPublisher.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/patterns/scatter-gather/data.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "current" {} 2 | data "aws_region" "current" {} 3 | 4 | data "aws_iam_policy_document" "dynamo_db_read" { 5 | statement { 6 | actions = ["dynamodb:GetItem", "dynamodb:Scan", "dynamodb:Query", "dynamodb:BatchGetItem", "dynamodb:DescribeTable"] 7 | resources = ["arn:aws:dynamodb:*:${data.aws_caller_identity.current.account_id}:table/${var.table_name}", "arn:aws:dynamodb:*:*:table/${var.table_name}/*"] 8 | } 9 | } 10 | 11 | data "aws_iam_policy_document" "dynamo_db_write" { 12 | statement { 13 | actions = ["dynamodb:PutItem", 14 | "dynamodb:UpdateItem", 15 | "dynamodb:BatchWriteItem"] 16 | resources = ["arn:aws:dynamodb:*:${data.aws_caller_identity.current.account_id}:table/${var.table_name}", "arn:aws:dynamodb:*:${data.aws_caller_identity.current.account_id}:table/${var.table_name}/*"] 17 | } 18 | } 19 | 20 | data "aws_iam_policy_document" "eventbridge_put_events" { 21 | statement { 22 | actions = ["events:PutEvents"] 23 | resources = ["arn:aws:events:*:${data.aws_caller_identity.current.account_id}:event-bus/${var.event_bus_name}"] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/sample-app/product-api/test/ProductApi.Test/ProductApi.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgePublisher/Events/EventProducer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text.Json; 4 | using System.Threading.Tasks; 5 | using Amazon.EventBridge; 6 | using Amazon.EventBridge.Model; 7 | 8 | namespace EventBridgePublisher; 9 | 10 | public class EventProducer 11 | { 12 | private readonly AmazonEventBridgeClient _eventBridgeClient; 13 | 14 | public EventProducer(AmazonEventBridgeClient eventBridgeClient) 15 | { 16 | this._eventBridgeClient = eventBridgeClient; 17 | } 18 | 19 | public async Task Publish(EventBase evt) 20 | { 21 | await this._eventBridgeClient.PutEventsAsync(new PutEventsRequest() 22 | { 23 | Entries = new List() 24 | { 25 | new PutEventsRequestEntry() 26 | { 27 | Source = evt.Source, 28 | Time = DateTime.UtcNow, 29 | EventBusName = Environment.GetEnvironmentVariable("EVENT_BUS_NAME"), 30 | DetailType = evt.EventName, 31 | Detail = JsonSerializer.Serialize(evt) 32 | } 33 | } 34 | }); 35 | } 36 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipCustomerCreatedAdapter/MembershipCustomerCreatedAdapter.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipAssignPoints/Function.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using System.Threading.Tasks; 3 | using Amazon.Lambda.Core; 4 | using Amazon.Lambda.SNSEvents; 5 | using AWS.Lambda.Powertools.Logging; 6 | using AWS.Lambda.Powertools.Tracing; 7 | using Membership.Shared; 8 | 9 | namespace MembershipAssignPoints 10 | { 11 | public class Function 12 | { 13 | [Tracing] 14 | public async Task FunctionHandler(SNSEvent inputEvent, ILambdaContext context) 15 | { 16 | foreach (var snsEvent in inputEvent.Records) 17 | { 18 | var evtPayload = JsonSerializer.Deserialize(snsEvent.Sns.Message); 19 | 20 | Logger.LogInformation($"Received data for member with customer id {evtPayload.MemberCustomerId}"); 21 | 22 | var member = new Member() 23 | { 24 | MemberId = evtPayload.MemberCustomerId 25 | }; 26 | 27 | Logger.LogInformation("Adding additional membership points"); 28 | 29 | member.RegisterInitialMembershipPoints(); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/sample-app/modules/sqs-sourced-lambda-function/variables.tf: -------------------------------------------------------------------------------- 1 | variable "publish_dir" { 2 | description = "The location of the published files." 3 | type = string 4 | } 5 | 6 | variable "zip_file" { 7 | description = "The location of the ZIP file" 8 | type = string 9 | } 10 | 11 | variable "lambda_bucket_id" { 12 | description = "The id of the bucket lambda function code will be stored" 13 | type = string 14 | } 15 | 16 | variable "function_name" { 17 | description = "The name of the Lambda function" 18 | type = string 19 | } 20 | 21 | variable "queue_arn" { 22 | description = "The ARN of the queue to source the Lambda function" 23 | type = string 24 | } 25 | 26 | variable "queue_name" { 27 | description = "The name of the queue to source the Lambda function" 28 | type = string 29 | } 30 | 31 | variable "honeycomb_api_key" { 32 | description = "API Key to pass to Honeycomb" 33 | type = string 34 | } 35 | 36 | variable "lambda_handler" { 37 | description = "The Lambda handler, defined as classlib::namespace.class::method" 38 | type = string 39 | } 40 | 41 | variable "environment_variables" { 42 | description = "Environment variables to pass to the Lambda function" 43 | type = map(string) 44 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.Implementations/Startup.cs: -------------------------------------------------------------------------------- 1 | using Amazon.DynamoDBv2; 2 | using Amazon.XRay.Recorder.Core; 3 | using Amazon.XRay.Recorder.Handlers.AwsSdk; 4 | using SynchronousApi.Core.Command; 5 | using SynchronousApi.Core.Models; 6 | using SynchronousApi.Core.Queries; 7 | using SynchronousApi.Core.Services; 8 | using SynchronousApi.Implementations; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace HelloWorld; 12 | 13 | public static class Startup 14 | { 15 | public static ServiceProvider Services { get; private set; } 16 | 17 | public static void ConfigureServices() 18 | { 19 | var serviceCollection = new ServiceCollection(); 20 | 21 | AWSSDKHandler.RegisterXRayForAllServices(); 22 | 23 | serviceCollection.AddSingleton(new SerilogLogger()); 24 | serviceCollection.AddSingleton(new AmazonDynamoDBClient(new AmazonDynamoDBConfig())); 25 | serviceCollection.AddTransient(); 26 | serviceCollection.AddSingleton(); 27 | serviceCollection.AddSingleton(); 28 | 29 | Services = serviceCollection.BuildServiceProvider(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/sample-app/modules/api-gateway/main.tf: -------------------------------------------------------------------------------- 1 | # Create API Gateway 2 | resource "aws_apigatewayv2_api" "lambda" { 3 | name = var.api_name 4 | protocol_type = "HTTP" 5 | } 6 | 7 | resource "aws_apigatewayv2_stage" "lambda" { 8 | api_id = aws_apigatewayv2_api.lambda.id 9 | 10 | name = var.stage_name 11 | auto_deploy = var.stage_auto_deploy 12 | 13 | access_log_settings { 14 | destination_arn = aws_cloudwatch_log_group.api_gw.arn 15 | 16 | format = jsonencode({ 17 | requestId = "$context.requestId" 18 | sourceIp = "$context.identity.sourceIp" 19 | requestTime = "$context.requestTime" 20 | protocol = "$context.protocol" 21 | httpMethod = "$context.httpMethod" 22 | resourcePath = "$context.resourcePath" 23 | routeKey = "$context.routeKey" 24 | status = "$context.status" 25 | responseLength = "$context.responseLength" 26 | integrationErrorMessage = "$context.integrationErrorMessage" 27 | } 28 | ) 29 | } 30 | } 31 | 32 | resource "aws_cloudwatch_log_group" "api_gw" { 33 | name = "/aws/api_gw/${aws_apigatewayv2_api.lambda.name}" 34 | 35 | retention_in_days = 1 36 | } -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/api-gateway/main.tf: -------------------------------------------------------------------------------- 1 | # Create API Gateway 2 | resource "aws_apigatewayv2_api" "lambda" { 3 | name = var.api_name 4 | protocol_type = "HTTP" 5 | } 6 | 7 | resource "aws_apigatewayv2_stage" "lambda" { 8 | api_id = aws_apigatewayv2_api.lambda.id 9 | 10 | name = var.stage_name 11 | auto_deploy = var.stage_auto_deploy 12 | 13 | access_log_settings { 14 | destination_arn = aws_cloudwatch_log_group.api_gw.arn 15 | 16 | format = jsonencode({ 17 | requestId = "$context.requestId" 18 | sourceIp = "$context.identity.sourceIp" 19 | requestTime = "$context.requestTime" 20 | protocol = "$context.protocol" 21 | httpMethod = "$context.httpMethod" 22 | resourcePath = "$context.resourcePath" 23 | routeKey = "$context.routeKey" 24 | status = "$context.status" 25 | responseLength = "$context.responseLength" 26 | integrationErrorMessage = "$context.integrationErrorMessage" 27 | } 28 | ) 29 | } 30 | } 31 | 32 | resource "aws_cloudwatch_log_group" "api_gw" { 33 | name = "/aws/api_gw/${aws_apigatewayv2_api.lambda.name}" 34 | 35 | retention_in_days = 1 36 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Core/DataTransfer/ProductDTO.cs: -------------------------------------------------------------------------------- 1 | using ApplicationIntegrationPatterns.Core.Models; 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace ApplicationIntegrationPatterns.Core.DataTransfer; 6 | 7 | public record ProductDTO 8 | { 9 | public ProductDTO() 10 | { 11 | } 12 | 13 | public ProductDTO(Product product) 14 | { 15 | this.ProductId = product.ProductId; 16 | this.Name = product.Name; 17 | this.Description = product.Description; 18 | this.CurrentPrice = product.Price; 19 | this.PricingHistory = new Dictionary(); 20 | 21 | foreach (var pricingHistory in product.PricingHistory) 22 | { 23 | this.PricingHistory.Add(pricingHistory.Date, pricingHistory.Price); 24 | } 25 | } 26 | 27 | public string ProductId { get; set; } 28 | 29 | public string Name { get; set; } 30 | 31 | public string Description { get; set; } 32 | 33 | public decimal CurrentPrice { get; set; } 34 | 35 | public Dictionary PricingHistory { get; set; } 36 | 37 | public override string ToString() => JsonSerializer.Serialize(this); 38 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/api-gateway/main.tf: -------------------------------------------------------------------------------- 1 | # Create API Gateway 2 | resource "aws_apigatewayv2_api" "lambda" { 3 | name = var.api_name 4 | protocol_type = "HTTP" 5 | } 6 | 7 | resource "aws_apigatewayv2_stage" "lambda" { 8 | api_id = aws_apigatewayv2_api.lambda.id 9 | 10 | name = var.stage_name 11 | auto_deploy = var.stage_auto_deploy 12 | 13 | access_log_settings { 14 | destination_arn = aws_cloudwatch_log_group.api_gw.arn 15 | 16 | format = jsonencode({ 17 | requestId = "$context.requestId" 18 | sourceIp = "$context.identity.sourceIp" 19 | requestTime = "$context.requestTime" 20 | protocol = "$context.protocol" 21 | httpMethod = "$context.httpMethod" 22 | resourcePath = "$context.resourcePath" 23 | routeKey = "$context.routeKey" 24 | status = "$context.status" 25 | responseLength = "$context.responseLength" 26 | integrationErrorMessage = "$context.integrationErrorMessage" 27 | } 28 | ) 29 | } 30 | } 31 | 32 | resource "aws_cloudwatch_log_group" "api_gw" { 33 | name = "/aws/api_gw/${aws_apigatewayv2_api.lambda.name}" 34 | 35 | retention_in_days = 1 36 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/api-gateway/main.tf: -------------------------------------------------------------------------------- 1 | # Create API Gateway 2 | resource "aws_apigatewayv2_api" "lambda" { 3 | name = var.api_name 4 | protocol_type = "HTTP" 5 | } 6 | 7 | resource "aws_apigatewayv2_stage" "lambda" { 8 | api_id = aws_apigatewayv2_api.lambda.id 9 | 10 | name = var.stage_name 11 | auto_deploy = var.stage_auto_deploy 12 | 13 | access_log_settings { 14 | destination_arn = aws_cloudwatch_log_group.api_gw.arn 15 | 16 | format = jsonencode({ 17 | requestId = "$context.requestId" 18 | sourceIp = "$context.identity.sourceIp" 19 | requestTime = "$context.requestTime" 20 | protocol = "$context.protocol" 21 | httpMethod = "$context.httpMethod" 22 | resourcePath = "$context.resourcePath" 23 | routeKey = "$context.routeKey" 24 | status = "$context.status" 25 | responseLength = "$context.responseLength" 26 | integrationErrorMessage = "$context.integrationErrorMessage" 27 | } 28 | ) 29 | } 30 | } 31 | 32 | resource "aws_cloudwatch_log_group" "api_gw" { 33 | name = "/aws/api_gw/${aws_apigatewayv2_api.lambda.name}" 34 | 35 | retention_in_days = 1 36 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Implementations/ApplicationIntegrationPatterns.Implementations.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/sample-app/product-api/application/CreateProduct/CreateProduct.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/test/ProductApi.IntegrationTests/IntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Text; 3 | using System.Text.Json; 4 | 5 | namespace ProductApi.IntegrationTests; 6 | 7 | internal class CreateProductResponse 8 | { 9 | public string ProductId { get; set; } 10 | } 11 | 12 | public class IntegrationTests : IClassFixture 13 | { 14 | private HttpClient _httpClient = new HttpClient(); 15 | 16 | [Fact] 17 | public async void GetCallingIp_ShouldReturnOk() 18 | { 19 | var createProductBody = new 20 | { 21 | Name = "Integration test product", 22 | Price = 10.00, 23 | Description = "This is a product created from an integration test" 24 | }; 25 | 26 | var httpResponse = await this._httpClient.PostAsync(Setup.ApiUrl, 27 | new StringContent(JsonSerializer.Serialize(createProductBody), Encoding.UTF8, "application/json")); 28 | 29 | Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode); 30 | 31 | var response = 32 | JsonSerializer.Deserialize(await httpResponse.Content.ReadAsStringAsync()); 33 | 34 | var getProductResponse = await this._httpClient.GetAsync($"{Setup.ApiUrl}{response.ProductId}"); 35 | 36 | Assert.Equal(HttpStatusCode.OK, getProductResponse.StatusCode); 37 | } 38 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/UpdateProductCatalogue/UpdateProductCatalogue.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/patterns/scatter-gather/modules/vendor-loan-request-lambda/main.tf: -------------------------------------------------------------------------------- 1 | module lambda_vendor_loan_quote_generator { 2 | source = "../lambda-function" 3 | lambda_bucket_id = var.lambda_bucket_id 4 | publish_dir = "${path.module}/../../functions/VendorLoanQuoteGenerator/bin/Release/net6.0/linux-x64/publish" 5 | zip_file = "VendorLoanQuoteGenerator.zip" 6 | function_name = "VendorLoanQuoteGenerator_${replace(var.vendor_name, " ", "_")}" 7 | lambda_handler = "VendorLoanQuoteGenerator::VendorLoanQuoteGenerator.Function::FunctionHandler" 8 | environment_variables = { 9 | "EVENT_BUS_NAME" = var.event_bridge_name 10 | "VENDOR_NAME" = var.vendor_name 11 | } 12 | } 13 | 14 | resource "aws_iam_role_policy_attachment" "vendor_loan_generator_event_bridge_policy" { 15 | role = module.lambda_vendor_loan_quote_generator.function_role_name 16 | policy_arn = var.event_bridge_put_events_policy_arn 17 | } 18 | 19 | module "request_loan_offers_event_rule" { 20 | source = "../event-bridge-lambda-target" 21 | event_bridge_name = var.event_bridge_name 22 | event_bridge_rule_name = "new-loan-request-${replace(var.vendor_name, " ", "_")}" 23 | lambda_function_name = module.lambda_vendor_loan_quote_generator.function_name 24 | lambda_function_arn = module.lambda_vendor_loan_quote_generator.function_arn 25 | event_pattern = < 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/NewCustomerPublisher/Events/EventProducer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text.Json; 4 | using System.Threading.Tasks; 5 | using Amazon.EventBridge; 6 | using Amazon.EventBridge.Model; 7 | using AWS.Lambda.Powertools.Logging; 8 | 9 | namespace NewCustomerPublisher.Events; 10 | 11 | public class EventProducer 12 | { 13 | private readonly AmazonEventBridgeClient _eventBridgeClient; 14 | 15 | public EventProducer(AmazonEventBridgeClient eventBridgeClient) 16 | { 17 | this._eventBridgeClient = eventBridgeClient; 18 | } 19 | 20 | public async Task Publish(EventBase evt) 21 | { 22 | var evtPayload = JsonSerializer.Serialize(evt, evt.GetType()); 23 | 24 | Logger.LogInformation("Publishing event data:"); 25 | Logger.LogInformation(evtPayload); 26 | 27 | await this._eventBridgeClient.PutEventsAsync(new PutEventsRequest() 28 | { 29 | Entries = new List() 30 | { 31 | new PutEventsRequestEntry() 32 | { 33 | Source = evt.Source, 34 | Time = DateTime.UtcNow, 35 | EventBusName = Environment.GetEnvironmentVariable("EVENT_BUS_NAME"), 36 | DetailType = evt.EventName, 37 | Detail = evtPayload 38 | } 39 | } 40 | }); 41 | } 42 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/tests/ScatterGather.IntegrationTest/TestStartup.cs: -------------------------------------------------------------------------------- 1 | using Amazon.StepFunctions; 2 | using Amazon.StepFunctions.Model; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace ScatterGather.IntegrationTest 10 | { 11 | internal class TestStartup : IDisposable 12 | { 13 | private string stateMachineName = Environment.GetEnvironmentVariable("STATE_MACHINE_NAME") ?? "scatter-gather-orchestrator"; 14 | public static AmazonStepFunctionsClient StepFunctionsClient { get; private set; } 15 | 16 | public static string StateMachineFunctionArn { get; private set; } 17 | 18 | public TestStartup() 19 | { 20 | StepFunctionsClient = new AmazonStepFunctionsClient(); 21 | 22 | var stateMachines = StepFunctionsClient.ListStateMachinesAsync(new ListStateMachinesRequest()).Result; 23 | 24 | var stateMachine = stateMachines.StateMachines.FirstOrDefault(p => p.Name == stateMachineName); 25 | 26 | if (stateMachine == null) 27 | { 28 | throw new Exception($"State machine with name {stateMachineName} not found"); 29 | } 30 | 31 | StateMachineFunctionArn = stateMachine.StateMachineArn; 32 | } 33 | 34 | public void Dispose() 35 | { 36 | // Do "global" teardown here; Only called once. 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/sample-app/product-api/application/DeleteProduct/DeleteProduct.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/sample-app/product-api/application/GetProduct/GetProduct.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/sample-app/product-api/application/UpdateProduct/UpdateProduct.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/test/ProductApi.Test/FunctionTests.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using System.Threading.Tasks; 3 | using Amazon.Lambda.APIGatewayEvents; 4 | using Amazon.Lambda.TestUtilities; 5 | using Amazon.XRay.Recorder.Core; 6 | using SynchronousApi.Core.Models; 7 | using SynchronousApi.Core.Queries; 8 | using SynchronousApi.Core.Services; 9 | using FluentAssertions; 10 | using Moq; 11 | using Newtonsoft.Json; 12 | using Xunit; 13 | 14 | namespace ProductApi.Test 15 | { 16 | public class FunctionTests 17 | { 18 | public FunctionTests() 19 | { 20 | } 21 | 22 | [Fact] 23 | public async Task GetProductHandler_ShouldReturnSuccess() 24 | { 25 | var testProduct = Product.Create("Test product", 10); 26 | 27 | var mockRepo = new Mock(); 28 | mockRepo.Setup(p => p.Get(It.IsAny())).ReturnsAsync(testProduct); 29 | 30 | var mockLogger = new Mock(); 31 | 32 | var handler = new GetProductQueryHandler(mockRepo.Object); 33 | 34 | var getProductFunction = new GetProduct.Function(handler, mockLogger.Object); 35 | 36 | var queryResult = await getProductFunction.FunctionHandler( 37 | JsonConvert.DeserializeObject(EventHelper.ValidGetProductRequest), 38 | new TestLambdaContext()); 39 | 40 | queryResult.StatusCode.Should().Be(200); 41 | queryResult.Body.Should().NotBeNull(); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/sample-app/Shared/Messaging/SqsQueuing.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Text.Json; 3 | using Amazon.SQS; 4 | using Amazon.SQS.Model; 5 | 6 | namespace Shared.Messaging; 7 | 8 | public class SqsQueuing : IQueuing 9 | { 10 | private readonly IAmazonSQS _sqsClient; 11 | 12 | public SqsQueuing(IAmazonSQS sqsClient) 13 | { 14 | _sqsClient = sqsClient; 15 | } 16 | 17 | public async Task Enqueue(string queueUrl, MessageWrapper message) 18 | { 19 | using var activity = Activity.Current?.Source.StartActivity("SQSSendMessage"); 20 | var (filepath, lineno, function) = TraceUtils.CodeInfo(); 21 | activity?.AddTag("code.function", function); 22 | activity?.AddTag("code.lineno", lineno - 2); 23 | activity?.AddTag("code.filepath", filepath); 24 | activity.AddTag("messaging.contents", JsonSerializer.Serialize(message.Data)); 25 | 26 | await this._sqsClient.SendMessageAsync(new SendMessageRequest() 27 | { 28 | QueueUrl = queueUrl, 29 | MessageBody = JsonSerializer.Serialize(message), 30 | MessageAttributes = new Dictionary(1) 31 | { 32 | { 33 | "parentspan", new MessageAttributeValue() 34 | { 35 | StringValue = activity.SpanId.ToString(), 36 | DataType = "String" 37 | } 38 | } 39 | } 40 | }); 41 | 42 | activity.Stop(); 43 | } 44 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Core/Command/DeleteProductCommand.cs: -------------------------------------------------------------------------------- 1 | using ApplicationIntegrationPatterns.Core.DataTransfer; 2 | using ApplicationIntegrationPatterns.Core.Models; 3 | using ApplicationIntegrationPatterns.Core.Services; 4 | 5 | namespace ApplicationIntegrationPatterns.Core.Command; 6 | 7 | public record DeleteProductCommand 8 | { 9 | public string ProductId { get; set; } 10 | 11 | internal bool ValidateProperties() 12 | { 13 | return !string.IsNullOrEmpty(ProductId); 14 | } 15 | } 16 | 17 | public class DeleteProductCommandHandler 18 | { 19 | private readonly IProductRepository _productRepository; 20 | private readonly ILoggingService _loggingService; 21 | 22 | public DeleteProductCommandHandler(IProductRepository productRepository, ILoggingService loggingService) 23 | { 24 | _productRepository = productRepository; 25 | _loggingService = loggingService; 26 | } 27 | 28 | public async Task Handle(DeleteProductCommand command) 29 | { 30 | if (!isCommandValid(command)) 31 | { 32 | return; 33 | } 34 | 35 | this._loggingService.LogInfo("Deleting product"); 36 | 37 | await this._productRepository.Delete(command.ProductId); 38 | 39 | this._loggingService.LogInfo("Product deleted"); 40 | } 41 | 42 | private bool isCommandValid(DeleteProductCommand command) 43 | { 44 | if (command == null) 45 | { 46 | return false; 47 | } 48 | 49 | return command.ValidateProperties(); 50 | } 51 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30114.105 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreateProduct", "CreateProduct\CreateProduct.csproj", "{CBCA1ABC-0E7C-4DB7-8A16-FAF744AE6289}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetProduct", "GetProduct\GetProduct.csproj", "{1BFA378E-CF5A-4B80-A75D-A38CB7F81F70}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(SolutionProperties) = preSolution 16 | HideSolutionNode = FALSE 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {CBCA1ABC-0E7C-4DB7-8A16-FAF744AE6289}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {CBCA1ABC-0E7C-4DB7-8A16-FAF744AE6289}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {CBCA1ABC-0E7C-4DB7-8A16-FAF744AE6289}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {CBCA1ABC-0E7C-4DB7-8A16-FAF744AE6289}.Release|Any CPU.Build.0 = Release|Any CPU 23 | {1BFA378E-CF5A-4B80-A75D-A38CB7F81F70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {1BFA378E-CF5A-4B80-A75D-A38CB7F81F70}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {1BFA378E-CF5A-4B80-A75D-A38CB7F81F70}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {1BFA378E-CF5A-4B80-A75D-A38CB7F81F70}.Release|Any CPU.Build.0 = Release|Any CPU 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /src/sample-app/Shared/Shared.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/patterns/scatter-gather/statemachine/scatter-gather-orchestration.asl.json: -------------------------------------------------------------------------------- 1 | { 2 | "Comment": "A description of my state machine", 3 | "StartAt": "BroadcastRequest", 4 | "States": { 5 | "BroadcastRequest": { 6 | "Type": "Task", 7 | "Resource": "arn:aws:states:::events:putEvents", 8 | "Parameters": { 9 | "Entries": [ 10 | { 11 | "Detail": { 12 | "CustomerId.$": "$.CustomerId", 13 | "LoanAmount.$": "$.LoanAmount", 14 | "CorrelationId.$": "$.CorrelationId" 15 | }, 16 | "DetailType": "com.broken.request-loan-offers", 17 | "EventBusName": "application-integration-bus", 18 | "Source": "com.loanbroker" 19 | } 20 | ] 21 | }, 22 | "ResultPath": null, 23 | "Next": "WaitForResponses" 24 | }, 25 | "WaitForResponses": { 26 | "Type": "Wait", 27 | "Seconds": 10, 28 | "Next": "Aggregator" 29 | }, 30 | "Aggregator": { 31 | "Type": "Task", 32 | "Resource": "arn:aws:states:::lambda:invoke", 33 | "OutputPath": "$.Payload", 34 | "Parameters": { 35 | "Payload.$": "$", 36 | "FunctionName": "{{AGGREGATOR_FUNCTION_ARN}}:$LATEST" 37 | }, 38 | "Retry": [ 39 | { 40 | "ErrorEquals": [ 41 | "Lambda.ServiceException", 42 | "Lambda.AWSLambdaException", 43 | "Lambda.SdkClientException" 44 | ], 45 | "IntervalSeconds": 2, 46 | "MaxAttempts": 6, 47 | "BackoffRate": 2 48 | } 49 | ], 50 | "End": true 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/sample-app/modules/iam-policies/main.tf: -------------------------------------------------------------------------------- 1 | # Create a set of IAM policies our application will need 2 | resource "aws_iam_policy" "dynamo_db_read" { 3 | name = "dynamo_db_read_policy" 4 | path = "/" 5 | policy = data.aws_iam_policy_document.dynamo_db_read.json 6 | } 7 | 8 | resource "aws_iam_policy" "dynamo_db_write" { 9 | name = "dynamo_db_write_policy" 10 | path = "/" 11 | policy = data.aws_iam_policy_document.dynamo_db_write.json 12 | } 13 | 14 | resource "aws_iam_policy" "dynamo_db_crud" { 15 | name = "dynamo_db_crud_policy" 16 | path = "/" 17 | policy = data.aws_iam_policy_document.dynamo_db_crud.json 18 | } 19 | 20 | resource "aws_iam_policy" "cloud_watch_put_metrics" { 21 | name = "cloud_watch_put_metrics_policy" 22 | path = "/" 23 | policy = data.aws_iam_policy_document.cloud_watch_put_metrics.json 24 | } 25 | 26 | resource "aws_iam_policy" "dynamo_db_stream_read_policy" { 27 | name = "dynamo_db_stream_read_policy" 28 | path = "/" 29 | policy = data.aws_iam_policy_document.allow_dynamo_db_streams.json 30 | } 31 | 32 | resource "aws_iam_policy" "sns_publish_message" { 33 | name = "sns_publish_message_policy" 34 | path = "/" 35 | policy = data.aws_iam_policy_document.sns_publish_policy.json 36 | } 37 | 38 | resource "aws_iam_policy" "event_bridge_put_events" { 39 | name = "event_bridge_put_events_policy" 40 | path = "/" 41 | policy = data.aws_iam_policy_document.event_bridge_put_events.json 42 | } 43 | 44 | resource "aws_iam_policy" "ssm_parameter_read" { 45 | name = "ssm_parameter_read_policy" 46 | path = "/" 47 | policy = data.aws_iam_policy_document.ssm_parameter_read.json 48 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/test/ProductApi.Test/QueryTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using SynchronousApi.Core.Models; 3 | using SynchronousApi.Core.Queries; 4 | using FluentAssertions; 5 | using Moq; 6 | using Xunit; 7 | 8 | namespace ProductApi.Test; 9 | 10 | public class QueryTests 11 | { 12 | [Fact] 13 | public async Task RunProductQuery_ShouldReturnDTO() 14 | { 15 | var testProduct = Product.Create("Test product", 10); 16 | 17 | var mockRepo = new Mock(); 18 | mockRepo.Setup(p => p.Get(It.IsAny())).ReturnsAsync(testProduct); 19 | 20 | var handler = new GetProductQueryHandler(mockRepo.Object); 21 | 22 | var queryResult = await handler.Execute(new GetProductQuery(testProduct.ProductId)); 23 | 24 | queryResult.Name.Should().Be("Test product"); 25 | } 26 | 27 | [Fact] 28 | public async Task CanCreateQuery_ShouldSetProperty() 29 | { 30 | var testProduct = Product.Create("Test product", 10); 31 | 32 | var query = new GetProductQuery(testProduct.ProductId); 33 | 34 | query.ProductId.Should().Be(testProduct.ProductId); 35 | } 36 | 37 | [Fact] 38 | public async Task RunProductQuery_RepoReturnsNull_ShouldReturnNull() 39 | { 40 | var testProduct = Product.Create("Test product", 10); 41 | 42 | var mockRepo = new Mock(); 43 | 44 | var handler = new GetProductQueryHandler(mockRepo.Object); 45 | 46 | var queryResult = await handler.Execute(new GetProductQuery(testProduct.ProductId)); 47 | 48 | queryResult.Should().BeNull(); 49 | } 50 | } -------------------------------------------------------------------------------- /src/sample-app/purchase-order-service/ordering.tf: -------------------------------------------------------------------------------- 1 | # Contains logic for the purchase ordering system 2 | module "purchase_ordering_queue" { 3 | source = "../modules/sqs-with-dlq" 4 | queue_name = "${var.environment}-purchase-order-queue" 5 | max_receive_count = 2 6 | } 7 | 8 | # Create a new EventBridge Rule 9 | resource "aws_cloudwatch_event_rule" "product_created_event_rule" { 10 | event_bus_name = "${var.environment}-application-integration-patterns-samples" 11 | event_pattern = <(); 18 | mockRepo.Setup(p => p.Get(It.IsAny())).ReturnsAsync(testProduct); 19 | 20 | var handler = new GetProductQueryHandler(mockRepo.Object); 21 | 22 | var queryResult = await handler.Execute(new GetProductQuery(testProduct.ProductId)); 23 | 24 | queryResult.Name.Should().Be("Test product"); 25 | } 26 | 27 | [Fact] 28 | public void CanCreateQuery_ShouldSetProperty() 29 | { 30 | var testProduct = Product.Create("Test product", 10); 31 | 32 | var query = new GetProductQuery(testProduct.ProductId); 33 | 34 | query.ProductId.Should().Be(testProduct.ProductId); 35 | } 36 | 37 | [Fact] 38 | public async Task RunProductQuery_RepoReturnsNull_ShouldReturnNull() 39 | { 40 | var testProduct = Product.Create("Test product", 10); 41 | 42 | var mockRepo = new Mock(); 43 | 44 | var handler = new GetProductQueryHandler(mockRepo.Object); 45 | 46 | var queryResult = await handler.Execute(new GetProductQuery(testProduct.ProductId)); 47 | 48 | queryResult.Should().BeNull(); 49 | } 50 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/VendorLoanQuoteResponseHandler/Function.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using System.Text.Json; 4 | using Amazon.Lambda.Core; 5 | using Amazon.XRay.Recorder.Core; 6 | using Amazon.Lambda.CloudWatchEvents; 7 | using System; 8 | using VendorLoanQuoteResponseHandler.DataTransfer; 9 | using Amazon.DynamoDBv2; 10 | using Amazon.DynamoDBv2.Model; 11 | 12 | namespace VendorLoanQuoteResponseHandler 13 | { 14 | public class Function 15 | { 16 | private readonly AmazonDynamoDBClient _dynamoDbClient; 17 | 18 | public Function() : this(null) 19 | { 20 | } 21 | 22 | internal Function(AmazonDynamoDBClient dynamoDbClient) 23 | { 24 | this._dynamoDbClient = dynamoDbClient ?? new AmazonDynamoDBClient(); 25 | } 26 | 27 | public async Task FunctionHandler(CloudWatchEvent inputEvent, ILambdaContext context) 28 | { 29 | context.Logger.LogLine($"Received response from {inputEvent.Detail.VendorName} with an interest rate of {inputEvent.Detail.InterestRate}"); 30 | 31 | await this._dynamoDbClient.PutItemAsync(Environment.GetEnvironmentVariable("TABLE_NAME"), new Dictionary() 32 | { 33 | { "PK", new AttributeValue(inputEvent.Detail.Request.CorrelationId) }, 34 | { "SK", new AttributeValue(inputEvent.Detail.VendorName) }, 35 | { "InterestRate", new AttributeValue() 36 | { 37 | N = inputEvent.Detail.InterestRate.ToString("n2") 38 | } 39 | } 40 | }); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/SNSPublisher/Function.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using System.Text.Json; 4 | using Amazon.Lambda.Core; 5 | using Amazon.Lambda.APIGatewayEvents; 6 | using AWS.Lambda.Powertools.Logging; 7 | using Amazon.XRay.Recorder.Handlers.AwsSdk; 8 | using AWS.Lambda.Powertools.Tracing; 9 | using Amazon.SimpleNotificationService; 10 | 11 | namespace SNSPublisher 12 | { 13 | public class Function 14 | { 15 | private readonly EventProducer _eventProducer; 16 | 17 | public Function() : this(null) 18 | { 19 | AWSSDKHandler.RegisterXRayForAllServices(); 20 | } 21 | 22 | internal Function(EventProducer eventProducer) 23 | { 24 | this._eventProducer = eventProducer ?? new EventProducer(new AmazonSimpleNotificationServiceClient()); 25 | } 26 | 27 | [Logging(LogEvent = true)] 28 | [Tracing] 29 | public async Task FunctionHandler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) 30 | { 31 | Logger.LogInformation("Received request to publish event"); 32 | 33 | var evt = new ProductCreatedEvent(); 34 | 35 | Logger.LogInformation("Publishing"); 36 | 37 | await this._eventProducer.Publish(evt); 38 | 39 | Logger.LogInformation("Returning API response"); 40 | 41 | return new APIGatewayProxyResponse 42 | { 43 | Body = JsonSerializer.Serialize(evt), 44 | StatusCode = 200, 45 | Headers = new Dictionary { { "Content-Type", "application/json" } } 46 | }; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/patterns/pub-sub/functions/EventBridgePublisher/Function.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using System.Text.Json; 4 | using Amazon.Lambda.Core; 5 | using Amazon.Lambda.APIGatewayEvents; 6 | using EventBridgePublisher; 7 | using Amazon.EventBridge; 8 | using AWS.Lambda.Powertools.Logging; 9 | using Amazon.XRay.Recorder.Handlers.AwsSdk; 10 | using AWS.Lambda.Powertools.Tracing; 11 | 12 | namespace EventBridgePublisher 13 | { 14 | public class Function 15 | { 16 | private readonly EventProducer _eventProducer; 17 | 18 | public Function() : this(null) 19 | { 20 | AWSSDKHandler.RegisterXRayForAllServices(); 21 | } 22 | 23 | internal Function(EventProducer eventProducer) 24 | { 25 | this._eventProducer = eventProducer ?? new EventProducer(new AmazonEventBridgeClient()); 26 | } 27 | 28 | [Logging(LogEvent = true)] 29 | [Tracing] 30 | public async Task FunctionHandler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) 31 | { 32 | Logger.LogInformation("Received request to publish event"); 33 | 34 | var evt = new ProductCreatedEvent(); 35 | 36 | Logger.LogInformation("Publishing"); 37 | 38 | await this._eventProducer.Publish(evt); 39 | 40 | Logger.LogInformation("Returning API response"); 41 | 42 | return new APIGatewayProxyResponse 43 | { 44 | Body = JsonSerializer.Serialize(evt), 45 | StatusCode = 200, 46 | Headers = new Dictionary { { "Content-Type", "application/json" } } 47 | }; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/patterns/synchronous-api/application/SynchronousApi.Core/Command/CreateProductCommand.cs: -------------------------------------------------------------------------------- 1 | using SynchronousApi.Core.DataTransfer; 2 | using SynchronousApi.Core.Models; 3 | using SynchronousApi.Core.Services; 4 | 5 | namespace SynchronousApi.Core.Command; 6 | 7 | public record CreateProductCommand 8 | { 9 | public string Name { get; set; } 10 | 11 | public decimal Price { get; set; } 12 | 13 | public string Description { get; set; } 14 | 15 | internal bool ValidateProperties() 16 | { 17 | return !string.IsNullOrEmpty(Name) && Price > 0; 18 | } 19 | } 20 | 21 | public class CreateProductCommandHandler 22 | { 23 | private readonly IProductRepository _productRepository; 24 | private readonly ILoggingService _loggingService; 25 | 26 | public CreateProductCommandHandler(IProductRepository productRepository, ILoggingService loggingService) 27 | { 28 | _productRepository = productRepository; 29 | _loggingService = loggingService; 30 | } 31 | 32 | public async Task Handle(CreateProductCommand command) 33 | { 34 | if (!isCommandValid(command)) 35 | { 36 | return null; 37 | } 38 | 39 | this._loggingService.LogInfo("Creating product from new command"); 40 | 41 | var product = Product.Create(command.Name, command.Price); 42 | 43 | product.UpdateDescription(command.Description); 44 | 45 | await this._productRepository.Create(product); 46 | 47 | return new ProductDTO(product); 48 | } 49 | 50 | private bool isCommandValid(CreateProductCommand command) 51 | { 52 | if (command == null) 53 | { 54 | return false; 55 | } 56 | 57 | return command.ValidateProperties(); 58 | } 59 | } -------------------------------------------------------------------------------- /src/sample-app/Shared/Messaging/SnsPublisher.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Text.Json; 3 | using Amazon.SimpleNotificationService; 4 | using Amazon.SimpleNotificationService.Model; 5 | using Amazon.SQS; 6 | using Amazon.SQS.Model; 7 | using MessageAttributeValue = Amazon.SimpleNotificationService.Model.MessageAttributeValue; 8 | 9 | namespace Shared.Messaging; 10 | 11 | public class SnsPublisher : IPublisher 12 | { 13 | private readonly IAmazonSimpleNotificationService _snsClient; 14 | 15 | public SnsPublisher(IAmazonSimpleNotificationService snsClient) 16 | { 17 | _snsClient = snsClient; 18 | } 19 | 20 | public async Task Publish(string publishTo, MessageWrapper message) 21 | { 22 | using var activity = Activity.Current?.Source.StartActivity("SNSPublish"); 23 | var (filepath, lineno, function) = TraceUtils.CodeInfo(); 24 | activity?.AddTag("code.function", function); 25 | activity?.AddTag("code.lineno", lineno - 2); 26 | activity?.AddTag("code.filepath", filepath); 27 | activity.AddTag("messaging.contents", JsonSerializer.Serialize(message.Data)); 28 | 29 | await this._snsClient.PublishAsync(new PublishRequest() 30 | { 31 | TopicArn = publishTo, 32 | Message = JsonSerializer.Serialize(message), 33 | MessageAttributes = new Dictionary(2) 34 | { 35 | {"traceparent", new MessageAttributeValue(){StringValue = activity.TraceId.ToString(), DataType = "String"}}, 36 | {"parentspan", new MessageAttributeValue(){StringValue = activity.SpanId.ToString(), DataType = "String"}} 37 | } 38 | }); 39 | 40 | activity.Stop(); 41 | } 42 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/functions/Aggregator/Function.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using System.Text.Json; 4 | using Amazon.Lambda.Core; 5 | using Amazon.Lambda.CloudWatchEvents; 6 | using System; 7 | using Amazon.DynamoDBv2; 8 | using Amazon.DynamoDBv2.Model; 9 | using Aggregator.DataTransfer; 10 | 11 | namespace Aggregator 12 | { 13 | public class Function 14 | { 15 | private readonly AmazonDynamoDBClient _dynamoDbClient; 16 | 17 | public Function() : this(null) 18 | { 19 | } 20 | 21 | internal Function(AmazonDynamoDBClient dynamoDbClient) 22 | { 23 | this._dynamoDbClient = dynamoDbClient ?? new AmazonDynamoDBClient(); 24 | } 25 | 26 | public async Task> FunctionHandler(GenerateLoanQuoteRequest request, ILambdaContext context) 27 | { 28 | var queryResults = await this._dynamoDbClient.QueryAsync(new QueryRequest() 29 | { 30 | TableName = Environment.GetEnvironmentVariable("TABLE_NAME"), 31 | KeyConditionExpression = "PK = :pk", 32 | ExpressionAttributeValues = new Dictionary() 33 | { 34 | { ":pk", new AttributeValue(request.CorrelationId )} 35 | } 36 | }); 37 | 38 | var results = new List(); 39 | 40 | foreach (var item in queryResults.Items) 41 | { 42 | results.Add(new AggregationResult() 43 | { 44 | VendorName = item["SK"].S, 45 | InterestRate = double.Parse(item["InterestRate"].N) 46 | }); 47 | } 48 | 49 | return results; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/sample-app/Shared/SnsTracedFunction.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Text.Json; 3 | using Amazon.Lambda.Core; 4 | using Amazon.Lambda.SNSEvents; 5 | using Shared.Messaging; 6 | 7 | namespace Shared; 8 | 9 | public abstract class SnsTracedFunction : TracedFunction 10 | { 11 | public override Func ContextPropagator => SnsPropogator; 12 | 13 | public override Func AddRequestAttributes => SnsRequestAttributeLoader; 14 | 15 | public override Func AddResponseAttributes => SnsResponseAttributeLoader; 16 | 17 | private bool SnsPropogator(SNSEvent arg, ILambdaContext context) 18 | { 19 | this.Context = new ActivityContext(); 20 | 21 | return true; 22 | } 23 | 24 | private bool SnsRequestAttributeLoader(SNSEvent arg, Activity activity) 25 | { 26 | activity.AddTag("faas.trigger", "pubsub"); 27 | activity.AddTag("messaging.operation", "process"); 28 | activity.AddTag("messaging.system", "AmazonSNS"); 29 | activity.AddTag("messaging.destination_kind", "topic"); 30 | 31 | return true; 32 | } 33 | 34 | private bool SnsResponseAttributeLoader(TResponse arg, Activity activity) 35 | { 36 | return true; 37 | } 38 | 39 | public ActivityContext HydrateContextFromMessage(SNSEvent.SNSRecord message) 40 | { 41 | var body = JsonSerializer.Deserialize>(message.Sns.Message); 42 | 43 | var hydratedContext = new ActivityContext(ActivityTraceId.CreateFromString(body.Metadata.TraceParent.AsSpan()), 44 | ActivitySpanId.CreateFromString(body.Metadata.ParentSpan.AsSpan()), ActivityTraceFlags.Recorded); 45 | 46 | return hydratedContext; 47 | } 48 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ExternalEventPublisher/ExternalEventPublisher.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | Lambda 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/patterns/pub-sub/modules/lambda-function/main.tf: -------------------------------------------------------------------------------- 1 | data "archive_file" "lambda_archive" { 2 | type = "zip" 3 | 4 | source_dir = var.publish_dir 5 | output_path = "${path.module}/../../${var.zip_file}" 6 | } 7 | 8 | resource "aws_s3_object" "lambda_bundle" { 9 | bucket = var.lambda_bucket_id 10 | 11 | key = var.zip_file 12 | source = data.archive_file.lambda_archive.output_path 13 | 14 | etag = filemd5(data.archive_file.lambda_archive.output_path) 15 | } 16 | 17 | resource "aws_lambda_function" "function" { 18 | function_name = var.function_name 19 | s3_bucket = var.lambda_bucket_id 20 | s3_key = aws_s3_object.lambda_bundle.key 21 | runtime = "dotnet6" 22 | handler = var.lambda_handler 23 | source_code_hash = data.archive_file.lambda_archive.output_base64sha256 24 | role = aws_iam_role.lambda_function_role.arn 25 | timeout = 30 26 | dynamic "environment" { 27 | for_each = length(var.environment_variables) > 0 ? [1] : [] 28 | content { 29 | variables = var.environment_variables 30 | } 31 | } 32 | } 33 | 34 | resource "aws_cloudwatch_log_group" "aggregator" { 35 | name = "/aws/lambda/${aws_lambda_function.function.function_name}" 36 | 37 | retention_in_days = 30 38 | } 39 | 40 | resource "aws_iam_role" "lambda_function_role" { 41 | name = "FunctionIamRole_${var.function_name}" 42 | assume_role_policy = jsonencode({ 43 | Version = "2012-10-17" 44 | Statement = [{ 45 | Action = "sts:AssumeRole" 46 | Effect = "Allow" 47 | Sid = "" 48 | Principal = { 49 | Service = "lambda.amazonaws.com" 50 | } 51 | } 52 | ] 53 | }) 54 | } 55 | 56 | resource "aws_iam_role_policy_attachment" "lambda_policy_attach" { 57 | role = aws_iam_role.lambda_function_role.name 58 | policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 59 | } -------------------------------------------------------------------------------- /src/patterns/scatter-gather/modules/lambda-function/main.tf: -------------------------------------------------------------------------------- 1 | data "archive_file" "lambda_archive" { 2 | type = "zip" 3 | 4 | source_dir = var.publish_dir 5 | output_path = "${path.module}/../../${var.zip_file}" 6 | } 7 | 8 | resource "aws_s3_object" "lambda_bundle" { 9 | bucket = var.lambda_bucket_id 10 | 11 | key = var.zip_file 12 | source = data.archive_file.lambda_archive.output_path 13 | 14 | etag = filemd5(data.archive_file.lambda_archive.output_path) 15 | } 16 | 17 | resource "aws_lambda_function" "function" { 18 | function_name = var.function_name 19 | s3_bucket = var.lambda_bucket_id 20 | s3_key = aws_s3_object.lambda_bundle.key 21 | runtime = "dotnet6" 22 | handler = var.lambda_handler 23 | source_code_hash = data.archive_file.lambda_archive.output_base64sha256 24 | role = aws_iam_role.lambda_function_role.arn 25 | timeout = 30 26 | dynamic "environment" { 27 | for_each = length(var.environment_variables) > 0 ? [1] : [] 28 | content { 29 | variables = var.environment_variables 30 | } 31 | } 32 | } 33 | 34 | resource "aws_cloudwatch_log_group" "aggregator" { 35 | name = "/aws/lambda/${aws_lambda_function.function.function_name}" 36 | 37 | retention_in_days = 30 38 | } 39 | 40 | resource "aws_iam_role" "lambda_function_role" { 41 | name = "FunctionIamRole_${var.function_name}" 42 | assume_role_policy = jsonencode({ 43 | Version = "2012-10-17" 44 | Statement = [{ 45 | Action = "sts:AssumeRole" 46 | Effect = "Allow" 47 | Sid = "" 48 | Principal = { 49 | Service = "lambda.amazonaws.com" 50 | } 51 | } 52 | ] 53 | }) 54 | } 55 | 56 | resource "aws_iam_role_policy_attachment" "lambda_policy_attach" { 57 | role = aws_iam_role.lambda_function_role.name 58 | policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 59 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/modules/lambda-function/main.tf: -------------------------------------------------------------------------------- 1 | data "archive_file" "lambda_archive" { 2 | type = "zip" 3 | 4 | source_dir = var.publish_dir 5 | output_path = "${path.module}/../../${var.zip_file}" 6 | } 7 | 8 | resource "aws_s3_object" "lambda_bundle" { 9 | bucket = var.lambda_bucket_id 10 | 11 | key = var.zip_file 12 | source = data.archive_file.lambda_archive.output_path 13 | 14 | etag = filemd5(data.archive_file.lambda_archive.output_path) 15 | } 16 | 17 | resource "aws_lambda_function" "function" { 18 | function_name = var.function_name 19 | s3_bucket = var.lambda_bucket_id 20 | s3_key = aws_s3_object.lambda_bundle.key 21 | runtime = "dotnet6" 22 | handler = var.lambda_handler 23 | source_code_hash = data.archive_file.lambda_archive.output_base64sha256 24 | role = aws_iam_role.lambda_function_role.arn 25 | timeout = 30 26 | dynamic "environment" { 27 | for_each = length(var.environment_variables) > 0 ? [1] : [] 28 | content { 29 | variables = var.environment_variables 30 | } 31 | } 32 | } 33 | 34 | resource "aws_cloudwatch_log_group" "aggregator" { 35 | name = "/aws/lambda/${aws_lambda_function.function.function_name}" 36 | 37 | retention_in_days = 30 38 | } 39 | 40 | resource "aws_iam_role" "lambda_function_role" { 41 | name = "FunctionIamRole_${var.function_name}" 42 | assume_role_policy = jsonencode({ 43 | Version = "2012-10-17" 44 | Statement = [{ 45 | Action = "sts:AssumeRole" 46 | Effect = "Allow" 47 | Sid = "" 48 | Principal = { 49 | Service = "lambda.amazonaws.com" 50 | } 51 | } 52 | ] 53 | }) 54 | } 55 | 56 | resource "aws_iam_role_policy_attachment" "lambda_policy_attach" { 57 | role = aws_iam_role.lambda_function_role.name 58 | policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 59 | } -------------------------------------------------------------------------------- /src/patterns/synchronous-api/tf-modules/lambda-function/main.tf: -------------------------------------------------------------------------------- 1 | data "archive_file" "lambda_archive" { 2 | type = "zip" 3 | 4 | source_dir = var.publish_dir 5 | output_path = "${path.module}/../../${var.zip_file}" 6 | } 7 | 8 | resource "aws_s3_object" "lambda_bundle" { 9 | bucket = var.lambda_bucket_id 10 | 11 | key = var.zip_file 12 | source = data.archive_file.lambda_archive.output_path 13 | 14 | etag = filemd5(data.archive_file.lambda_archive.output_path) 15 | } 16 | 17 | resource "aws_lambda_function" "function" { 18 | function_name = var.function_name 19 | s3_bucket = var.lambda_bucket_id 20 | s3_key = aws_s3_object.lambda_bundle.key 21 | runtime = "dotnet6" 22 | handler = var.lambda_handler 23 | source_code_hash = data.archive_file.lambda_archive.output_base64sha256 24 | role = aws_iam_role.lambda_function_role.arn 25 | timeout = 30 26 | dynamic "environment" { 27 | for_each = length(var.environment_variables) > 0 ? [1] : [] 28 | content { 29 | variables = var.environment_variables 30 | } 31 | } 32 | } 33 | 34 | resource "aws_cloudwatch_log_group" "aggregator" { 35 | name = "/aws/lambda/${aws_lambda_function.function.function_name}" 36 | 37 | retention_in_days = 30 38 | } 39 | 40 | resource "aws_iam_role" "lambda_function_role" { 41 | name = "FunctionIamRole_${var.function_name}" 42 | assume_role_policy = jsonencode({ 43 | Version = "2012-10-17" 44 | Statement = [{ 45 | Action = "sts:AssumeRole" 46 | Effect = "Allow" 47 | Sid = "" 48 | Principal = { 49 | Service = "lambda.amazonaws.com" 50 | } 51 | } 52 | ] 53 | }) 54 | } 55 | 56 | resource "aws_iam_role_policy_attachment" "lambda_policy_attach" { 57 | role = aws_iam_role.lambda_function_role.name 58 | policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 59 | } -------------------------------------------------------------------------------- /src/patterns/anti-corruption-layer/functions/MembershipCustomerCreatedAdapter/Function.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json; 3 | using System.Threading.Tasks; 4 | using Amazon.Lambda.CloudWatchEvents; 5 | using Amazon.Lambda.Core; 6 | using Amazon.Lambda.SQSEvents; 7 | using Amazon.SimpleNotificationService; 8 | using AWS.Lambda.Powertools.Logging; 9 | using AWS.Lambda.Powertools.Tracing; 10 | using Membership.Shared; 11 | using MembershipCustomerCreatedAdapter.Events; 12 | 13 | namespace MembershipCustomerCreatedAdapter 14 | { 15 | public class Function 16 | { 17 | private AmazonSimpleNotificationServiceClient _snsClient; 18 | 19 | public Function() 20 | { 21 | this._snsClient = new AmazonSimpleNotificationServiceClient(); 22 | } 23 | 24 | [Tracing] 25 | public async Task FunctionHandler(SQSEvent inputEvent, ILambdaContext context) 26 | { 27 | foreach (var queuedMessage in inputEvent.Records) 28 | { 29 | Logger.LogInformation(queuedMessage.Body); 30 | 31 | var receivedEvent = JsonSerializer.Deserialize>(queuedMessage.Body, new JsonSerializerOptions() 32 | { 33 | PropertyNameCaseInsensitive = true 34 | }); 35 | 36 | Logger.LogInformation($"Received event for {receivedEvent.Detail.CustomerId}"); 37 | 38 | await this._snsClient.PublishAsync(Environment.GetEnvironmentVariable("TOPIC_ARN"), 39 | JsonSerializer.Serialize(new NewCustomerCreatedEventReceived() 40 | { 41 | MemberCustomerId = receivedEvent.Detail.CustomerId 42 | })); 43 | } 44 | 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/sample-app/modules/lambda-function/main.tf: -------------------------------------------------------------------------------- 1 | data "archive_file" "lambda_archive" { 2 | type = "zip" 3 | 4 | source_dir = var.publish_dir 5 | output_path = "${path.module}/../../${var.zip_file}" 6 | } 7 | 8 | resource "aws_s3_object" "lambda_bundle" { 9 | bucket = var.lambda_bucket_id 10 | 11 | key = var.zip_file 12 | source = data.archive_file.lambda_archive.output_path 13 | 14 | etag = filemd5(data.archive_file.lambda_archive.output_path) 15 | } 16 | 17 | resource "aws_lambda_function" "function" { 18 | function_name = var.function_name 19 | s3_bucket = var.lambda_bucket_id 20 | s3_key = aws_s3_object.lambda_bundle.key 21 | runtime = "dotnet6" 22 | handler = var.lambda_handler 23 | source_code_hash = data.archive_file.lambda_archive.output_base64sha256 24 | role = aws_iam_role.lambda_function_role.arn 25 | timeout = 30 26 | dynamic "environment" { 27 | for_each = length(var.environment_variables) > 0 ? [1] : [] 28 | content { 29 | variables = merge(var.environment_variables, { 30 | HONEYCOMB_API_KEY = var.honeycomb_api_key 31 | }) 32 | } 33 | } 34 | } 35 | 36 | resource "aws_cloudwatch_log_group" "aggregator" { 37 | name = "/aws/lambda/${aws_lambda_function.function.function_name}" 38 | 39 | retention_in_days = 30 40 | } 41 | 42 | resource "aws_iam_role" "lambda_function_role" { 43 | name = "FunctionIamRole_${var.function_name}" 44 | assume_role_policy = jsonencode({ 45 | Version = "2012-10-17" 46 | Statement = [{ 47 | Action = "sts:AssumeRole" 48 | Effect = "Allow" 49 | Sid = "" 50 | Principal = { 51 | Service = "lambda.amazonaws.com" 52 | } 53 | } 54 | ] 55 | }) 56 | } 57 | 58 | resource "aws_iam_role_policy_attachment" "lambda_policy_attach" { 59 | role = aws_iam_role.lambda_function_role.name 60 | policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 61 | } -------------------------------------------------------------------------------- /src/sample-app/product-api/application/ApplicationIntegrationPatterns.Core/Command/CreateProductCommand.cs: -------------------------------------------------------------------------------- 1 | using ApplicationIntegrationPatterns.Core.DataTransfer; 2 | using ApplicationIntegrationPatterns.Core.Models; 3 | using ApplicationIntegrationPatterns.Core.Services; 4 | 5 | namespace ApplicationIntegrationPatterns.Core.Command; 6 | 7 | public record CreateProductCommand 8 | { 9 | public string Name { get; set; } 10 | 11 | public decimal Price { get; set; } 12 | 13 | public string Description { get; set; } 14 | 15 | internal bool ValidateProperties() 16 | { 17 | return !string.IsNullOrEmpty(Name) && Price > 0; 18 | } 19 | } 20 | 21 | public class CreateProductCommandHandler 22 | { 23 | private readonly IProductRepository _productRepository; 24 | private readonly ILoggingService _loggingService; 25 | 26 | public CreateProductCommandHandler(IProductRepository productRepository, ILoggingService loggingService) 27 | { 28 | _productRepository = productRepository; 29 | _loggingService = loggingService; 30 | } 31 | 32 | public async Task Handle(CreateProductCommand command) 33 | { 34 | if (!isCommandValid(command)) 35 | { 36 | return null; 37 | } 38 | 39 | this._loggingService.LogInfo("Creating product from new command"); 40 | 41 | var product = Product.Create(command.Name, command.Price); 42 | 43 | product.UpdateDescription(command.Description); 44 | 45 | await this._productRepository.Create(product); 46 | 47 | this._loggingService.LogInfo("Product created"); 48 | 49 | return new ProductDTO(product); 50 | } 51 | 52 | private bool isCommandValid(CreateProductCommand command) 53 | { 54 | if (command == null) 55 | { 56 | return false; 57 | } 58 | 59 | return command.ValidateProperties(); 60 | } 61 | } -------------------------------------------------------------------------------- /src/sample-app/Shared/ActivityExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Amazon.Lambda.DynamoDBEvents; 3 | using Amazon.Lambda.SNSEvents; 4 | using Amazon.Lambda.SQSEvents; 5 | 6 | namespace Shared; 7 | 8 | public static class ActivityExtensions 9 | { 10 | public static Activity AddSqsAttributes(this Activity span, SQSEvent.SQSMessage message) 11 | { 12 | span.AddTag("faas.trigger", "pubsub"); 13 | span.AddTag("messaging.operation", "process"); 14 | span.AddTag("messaging.system", "AmazonSQS"); 15 | span.AddTag("messaging.destination_kind", "queue"); 16 | 17 | return span; 18 | } 19 | public static Activity AddDynamoDbAttributes(this Activity span, DynamoDBEvent.DynamodbStreamRecord message) 20 | { 21 | span.AddTag("faas.trigger", "stream"); 22 | span.AddTag("messaging.operation", "process"); 23 | span.AddTag("messaging.system", "DynamoDB"); 24 | span.AddTag("messaging.destination_kind", "stream"); 25 | span.AddTag($"messaging.attribute.source-arn", message.EventSourceArn); 26 | span.AddTag($"messaging.attribute.event-name", message.EventName.Value); 27 | span.AddTag($"messaging.attribute.event-version", message.EventVersion); 28 | span.AddTag($"messaging.attribute.event-id", message.EventID); 29 | 30 | return span; 31 | } 32 | 33 | public static Activity AddSnsAttributes(this Activity span, SNSEvent.SNSMessage message) 34 | { 35 | span.AddTag("faas.trigger", "pubsub"); 36 | span.AddTag("messaging.operation", "process"); 37 | span.AddTag("messaging.system", "AmazonSNS"); 38 | span.AddTag("messaging.destination_kind", "topic"); 39 | 40 | foreach (var attr in message.MessageAttributes) 41 | { 42 | span.AddTag($"messaging.attribute.{attr.Key.ToLower().Replace("-", "_")}", attr.Value.Value); 43 | } 44 | 45 | return span; 46 | } 47 | } --------------------------------------------------------------------------------