From d7847193d5c80781b9b8f9b89d9f844e7db39996 Mon Sep 17 00:00:00 2001 From: Arjun Arippa Date: Tue, 9 Jan 2024 13:17:44 +0530 Subject: [PATCH 01/12] Initial commit. --- apigw-lambda-translate-cdk/DEVELOPMENT.md | 30 ++++++ apigw-lambda-translate-cdk/README.md | 89 ++++++++++++++++ .../apigw-lambda-translate.json | 97 ++++++++++++++++++ apigw-lambda-translate-cdk/app.py | 76 ++++++++++++++ apigw-lambda-translate-cdk/cdk.json | 51 +++++++++ .../example-pattern.json | 56 ++++++++++ apigw-lambda-translate-cdk/requirements.txt | 7 ++ .../src/architecture.png | Bin 0 -> 19972 bytes .../src/lambda_function.py | 45 ++++++++ 9 files changed, 451 insertions(+) create mode 100644 apigw-lambda-translate-cdk/DEVELOPMENT.md create mode 100644 apigw-lambda-translate-cdk/README.md create mode 100644 apigw-lambda-translate-cdk/apigw-lambda-translate.json create mode 100644 apigw-lambda-translate-cdk/app.py create mode 100644 apigw-lambda-translate-cdk/cdk.json create mode 100644 apigw-lambda-translate-cdk/example-pattern.json create mode 100644 apigw-lambda-translate-cdk/requirements.txt create mode 100644 apigw-lambda-translate-cdk/src/architecture.png create mode 100644 apigw-lambda-translate-cdk/src/lambda_function.py diff --git a/apigw-lambda-translate-cdk/DEVELOPMENT.md b/apigw-lambda-translate-cdk/DEVELOPMENT.md new file mode 100644 index 000000000..7604c4ac6 --- /dev/null +++ b/apigw-lambda-translate-cdk/DEVELOPMENT.md @@ -0,0 +1,30 @@ + +### Project Structure within apigw-lambda-translate: +``` +apigw-lambda-translate-cdk +- app.py +- cdk.json +- src/ + - lambda_function.py + - architecture.png +- requirements.txt +``` + +## Common Errors & Troubleshooting + +### "ValueError: Must setup local AWS configuration with a region supported by AWS Services." +Solution: You must set an AWS region with `export AWS_DEFAULT_REGION=` + +### Error creating role +``` +botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the CreateRole operation: User: is not authorized to perform: iam:CreateRole on resource: because no identity-based policy allows the iam:CreateRole action +``` +Solution: you must ensure the IAM role you are using has sufficient permissions to create IAM roles + +#### Error processing tar file(exit status 1): write /path/libcublas.so.11: no space left on device +Issue: Docker has run out of memory due to too many images +Solution: Delete unused images in the Docker application and then [prune docker](https://docs.docker.com/config/pruning/) in command line + +#### ConnectionResetError: [Errno 104] Connection reset by peer +Issue: Pip issue +Solution: Clear pip cache (`python3 -m pip cache purge`) and run again diff --git a/apigw-lambda-translate-cdk/README.md b/apigw-lambda-translate-cdk/README.md new file mode 100644 index 000000000..77a18bce5 --- /dev/null +++ b/apigw-lambda-translate-cdk/README.md @@ -0,0 +1,89 @@ +# API Gateway -> Lambda -> Translate +This patterns shows CDK deployment on how to leverage Amazon API Gateway, AWS Lambda, and Amazon Translate to perform language translation in a serverless fashion. + +## Architecture +![Diagram](src/architecture.png) + +### What resources will be created? +This CDK code will create the following: + - One Lambda function (to invoke the Translate API) + - One API Gateway (to trigger the Lambda function with user input) + - One IAM role (for the Lambda function to invoke Translate service) + +## Requirements + +### Development Environment +**Cloud 9** + +This demonstration for this pattern is executed in an AWS Cloud9 environment. The EC2 instance used is t2.micro (1 GiB RAM + 1 vCPU). However, users have an option to deploy the application using CDK from local environment as well. + +### AWS setup +**Region** + +If you have not yet run `aws configure` and set a default region, you must do so, or you can also run `export AWS_DEFAULT_REGION=`. The region used in the demonstration is us-east-1. Please make sure the region selected supports both Translate and Comprehend service. +(If the user does not know the source language that needs to be translated, the source language is set as `auto` in the lambda function and Translate service internally invokes Comprehend API to detect the source language.) + +**Authorization** + +You must use a role that has sufficient permissions to create IAM roles, as well as CloudFormation resources + +#### Python >=3.8 +Make sure you have [python3](https://www.python.org/downloads/) installed at a version >=3.8.x in the CDK environment. The demonstration uses python 3.10. + +#### AWS CDK +Make sure you have the [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_install) installed in the Cloud9 environment. + + +## Setup + +### Set up environment and gather packages + +``` +cd apigw-lambda-translate-cdk +``` + +Install the required dependencies (aws-cdk-lib and constructs) into your Python environment +``` +pip install -r requirements.txt +``` + +### Gather and deploy resources with the CDK + +First synthesize, which executes the application, defines which resources will be created, and translates this into a CloudFormation template +``` +cdk synth +``` +All AWS CDK v2 deployments use dedicated AWS resources to hold data during deployment. Therefore, your AWS account and Region must be bootstrapped to create these resources before you can deploy. If you haven't already bootstrapped execute the below command +``` +cdk bootstrap +``` +and deploy with +``` +cdk deploy +``` + +The deployment will create a S3 bucket, a Lambda function and a DynamoDB table. + +## How it works +The API Gateway handles the incoming requests from user and it invokes the relevant route. The Lambda, triggered by API Gateway, invokes the Translate's TranslateText API and the analyzed response from Translate service is routed back to the requester. + +## Testing +Upon successful deployment of the stack, the Output section would provide the `APIEndpoint` in the CDK environment. Alternatively, the `APIEndpoint` can be found from the Outputs section of the `CloudFormation` stack. + +Use the below format to the test the API (replace the API Endpoint with the one retrieved from the above step): +```bash +curl -d '{"input": "I love AWS Services."}' -H 'Content-Type: application/json' https://.execute-api..amazonaws.com/TranslateText +``` + +A response as below would be seen on the terminal console: +``` +{ + "Translated Text": "J'adore AWS Services.", + "statusCode": 200, + "Source Text": "I love AWS Services." +} +``` + +## Cleanup + +To clean up the resources created as part of this demonstration, run the command `cdk destroy` in the directory `apigw-lambda-translate-cdk`. In addition, users are advised to terminate the Cloud9 EC2 instance to avoid any unexpected charges. diff --git a/apigw-lambda-translate-cdk/apigw-lambda-translate.json b/apigw-lambda-translate-cdk/apigw-lambda-translate.json new file mode 100644 index 000000000..9fb75256a --- /dev/null +++ b/apigw-lambda-translate-cdk/apigw-lambda-translate.json @@ -0,0 +1,97 @@ +{ + "title": "S3 - Lambda - Comprehend Batch sentiment analysis CDK", + "description": "Perform batch sentiment analysis using Comprehend through Lambda and S3", + "language": "Python", + "level": "200", + "framework": "CDK", + "introBox": { + "headline": "How it works", + "text": [ + "This patterns shows CDK deployment on how to leverage Amazon S3, AWS Lambda, Amazon DynamoDB, and Amazon Comprehend to perform Batch Sentiment Analysis in a serverless fashion." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/s3-lambda-comprehend-cdk-python", + "templateURL": "serverless-patterns/s3-lambda-comprehend-cdk-python", + "projectFolder": "s3-lambda-comprehend-cdk-python", + "templateFile": "app.py" + } + }, + "resources": { + "bullets": [ + { + "text": "Amazon Comprehend Sentiment Analysis", + "link": "https://docs.aws.amazon.com/comprehend/latest/dg/how-sentiment.html" + }, + { + "text": "Amazon Comprehend Features", + "Link": "https://aws.amazon.com/comprehend/features/" + } + ] + }, + "deploy": { + "text": [ + "cdk deploy" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the stack: cdk destroy." + ] + }, + "authors": [ + { + "name": "Arjun Arippa", + "image": "https://github.com/awsarippa/amazon-textract-comprehend-pii-analysis/blob/main/image.png", + "bio": "Arjun Arippa is a Solutions Architect based in Bangalore, India. He works with some of the strategic and global customers in India, to build and architect their applications on AWS. Before joining AWS, Arjun spent over a decade working as a Software Developer. Reach out to him on LinkedIn", + "linkedin": "arjun-arippa" + } + ], + "patternArch": { + "icon1": { + "x": 15, + "y": 45, + "service": "s3", + "label": "S3" + }, + "icon2": { + "x": 42, + "y": 45, + "service": "lambda", + "label": "AWS Lambda" + }, + "icon4": { + "x": 85, + "y": 25, + "service": "comprehend", + "label": "Amazon Comprehend" + }, + "icon3": { + "x": 85, + "y": 70, + "service": "dynamodb", + "label": "Amazon DynamoDB" + }, + "line1": { + "from": "icon1", + "to": "icon2", + "label": "Notification" + }, + "line2": { + "from": "icon2", + "to": "icon3", + "label": "Store results" + }, + "line3": { + "from": "icon2", + "to": "icon4", + "label": "Sentiment Analysis" + } + } +} diff --git a/apigw-lambda-translate-cdk/app.py b/apigw-lambda-translate-cdk/app.py new file mode 100644 index 000000000..5f1d413a7 --- /dev/null +++ b/apigw-lambda-translate-cdk/app.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +import os +import aws_cdk as cdk +from aws_cdk import ( + Duration, + Stack, + aws_iam as iam, + aws_lambda as lambda_, + CfnOutput +) +import aws_cdk.aws_apigatewayv2_alpha as _apigw +from aws_cdk.aws_apigatewayv2_integrations_alpha import HttpLambdaIntegration +from constructs import Construct + +DIRNAME = os.path.dirname(__file__) + + +class ApigwLambdaTranslateServerless(Stack): + def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: + super().__init__(scope, construct_id, **kwargs) + + # IAM role to invoke lambda + lambda_cfn_role = iam.Role( + self, + "CfnRole", + assumed_by=iam.ServicePrincipal("apigateway.amazonaws.com"), + ) + lambda_cfn_role.add_managed_policy( + iam.ManagedPolicy.from_aws_managed_policy_name("AWSLambdaExecute") + ) + + # Lambda function for processing the incoming request from API Gateway. Source and Target language are passed as environment variables to the Lambda function. + lambda_function = lambda_.Function( + self, + "TranslateTextLambda", + runtime=lambda_.Runtime.PYTHON_3_10, + handler="lambda_function.lambda_handler", + code=lambda_.Code.from_asset(os.path.join(DIRNAME, "src")), + timeout=Duration.minutes(1), + memory_size=256, + environment={ + "environment": "dev", + "src_lang": "auto", + "target_lang": "fr" + }, + ) + + # lambda policy + lambda_function.add_to_role_policy( + iam.PolicyStatement( + actions=[ + "translate:TranslateText", + "comprehend:DetectDominantLanguage" + ], + resources=["*"], + ) + ) + + # api gateway with http + http_api = _apigw.HttpApi(self, "TranslateTextApi") + + # added routes with POST method and integrated with the lambda function + http_api.add_routes( + path="/TranslateText", + methods=[_apigw.HttpMethod.ANY], + integration=HttpLambdaIntegration("TranslateTextIntegration", lambda_function) + ) + + # Outputs + CfnOutput(self, "API Endpoint", description="API Endpoint", value=http_api.api_endpoint) + + +app = cdk.App() +filestack = ApigwLambdaTranslateServerless(app, "ApigwLambdaTranslateServerless") + +app.synth() diff --git a/apigw-lambda-translate-cdk/cdk.json b/apigw-lambda-translate-cdk/cdk.json new file mode 100644 index 000000000..095c4b11d --- /dev/null +++ b/apigw-lambda-translate-cdk/cdk.json @@ -0,0 +1,51 @@ +{ + "app": "python3 app.py", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "requirements*.txt", + "source.bat", + "**/__init__.py", + "python/__pycache__", + "tests" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, + "@aws-cdk/aws-iam:standardizedServicePrincipals": true, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "@aws-cdk/customresources:installLatestAwsSdkDefault": false, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, + "@aws-cdk/aws-redshift:columnId": true, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true + } + } \ No newline at end of file diff --git a/apigw-lambda-translate-cdk/example-pattern.json b/apigw-lambda-translate-cdk/example-pattern.json new file mode 100644 index 000000000..a20311ace --- /dev/null +++ b/apigw-lambda-translate-cdk/example-pattern.json @@ -0,0 +1,56 @@ +{ + "title": "API Gateway - Lambda - Translate", + "description": "Perform language translation using Translate through Lambda and API Gateway", + "language": "Python", + "level": "200", + "framework": "CDK", + "introBox": { + "headline": "How it works", + "text": [ + "This patterns shows CDK deployment on how to leverage Amazon API Gateway, AWS Lambda, and Amazon Translate to perform language translation in a serverless fashion." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/apigw-lambda-translate-cdk", + "templateURL": "serverless-patterns/apigw-lambda-translate-cdk", + "projectFolder": "apigw-lambda-translate-cdk", + "templateFile": "app.py" + } + }, + "resources": { + "bullets": [ + { + "text": "Amazon Translate", + "link": "https://docs.aws.amazon.com/translate/latest/dg/what-is.html" + }, + { + "text": "Amazon Translate Features", + "Link": "https://aws.amazon.com/translate/" + } + ] + }, + "deploy": { + "text": [ + "cdk deploy" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the stack: cdk destroy." + ] + }, + "authors": [ + { + "name": "Arjun Arippa", + "image": "https://github.com/awsarippa/amazon-textract-comprehend-pii-analysis/blob/main/image.png", + "bio": "Arjun Arippa is a Solutions Architect based in Bangalore, India. He works with some of the strategic and global customers in India, to build and architect their applications on AWS. Before joining AWS, Arjun spent over a decade working as a Software Developer. Reach out to him on LinkedIn", + "linkedin": "arjun-arippa" + } + ] + } diff --git a/apigw-lambda-translate-cdk/requirements.txt b/apigw-lambda-translate-cdk/requirements.txt new file mode 100644 index 000000000..5e817219b --- /dev/null +++ b/apigw-lambda-translate-cdk/requirements.txt @@ -0,0 +1,7 @@ +boto3>=1.28.57 +awscli>=1.29.57 +botocore>=1.31.57 +aws-cdk-lib==2.111.0 +constructs>=10.0.0,<11.0.0 +aws-cdk.aws-apigatewayv2-alpha +aws-cdk.aws-apigatewayv2-integrations-alpha \ No newline at end of file diff --git a/apigw-lambda-translate-cdk/src/architecture.png b/apigw-lambda-translate-cdk/src/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..0a5f76dc755f0a0ac5efc6cecfd42833f96a2d7e GIT binary patch literal 19972 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 PBSR{v%Rfc@=J&q Date: Tue, 9 Jan 2024 13:20:55 +0530 Subject: [PATCH 02/12] Delete apigw-lambda-translate-cdk/apigw-lambda-translate.json --- .../apigw-lambda-translate.json | 97 ------------------- 1 file changed, 97 deletions(-) delete mode 100644 apigw-lambda-translate-cdk/apigw-lambda-translate.json diff --git a/apigw-lambda-translate-cdk/apigw-lambda-translate.json b/apigw-lambda-translate-cdk/apigw-lambda-translate.json deleted file mode 100644 index 9fb75256a..000000000 --- a/apigw-lambda-translate-cdk/apigw-lambda-translate.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "title": "S3 - Lambda - Comprehend Batch sentiment analysis CDK", - "description": "Perform batch sentiment analysis using Comprehend through Lambda and S3", - "language": "Python", - "level": "200", - "framework": "CDK", - "introBox": { - "headline": "How it works", - "text": [ - "This patterns shows CDK deployment on how to leverage Amazon S3, AWS Lambda, Amazon DynamoDB, and Amazon Comprehend to perform Batch Sentiment Analysis in a serverless fashion." - ] - }, - "gitHub": { - "template": { - "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/s3-lambda-comprehend-cdk-python", - "templateURL": "serverless-patterns/s3-lambda-comprehend-cdk-python", - "projectFolder": "s3-lambda-comprehend-cdk-python", - "templateFile": "app.py" - } - }, - "resources": { - "bullets": [ - { - "text": "Amazon Comprehend Sentiment Analysis", - "link": "https://docs.aws.amazon.com/comprehend/latest/dg/how-sentiment.html" - }, - { - "text": "Amazon Comprehend Features", - "Link": "https://aws.amazon.com/comprehend/features/" - } - ] - }, - "deploy": { - "text": [ - "cdk deploy" - ] - }, - "testing": { - "text": [ - "See the GitHub repo for detailed testing instructions." - ] - }, - "cleanup": { - "text": [ - "Delete the stack: cdk destroy." - ] - }, - "authors": [ - { - "name": "Arjun Arippa", - "image": "https://github.com/awsarippa/amazon-textract-comprehend-pii-analysis/blob/main/image.png", - "bio": "Arjun Arippa is a Solutions Architect based in Bangalore, India. He works with some of the strategic and global customers in India, to build and architect their applications on AWS. Before joining AWS, Arjun spent over a decade working as a Software Developer. Reach out to him on LinkedIn", - "linkedin": "arjun-arippa" - } - ], - "patternArch": { - "icon1": { - "x": 15, - "y": 45, - "service": "s3", - "label": "S3" - }, - "icon2": { - "x": 42, - "y": 45, - "service": "lambda", - "label": "AWS Lambda" - }, - "icon4": { - "x": 85, - "y": 25, - "service": "comprehend", - "label": "Amazon Comprehend" - }, - "icon3": { - "x": 85, - "y": 70, - "service": "dynamodb", - "label": "Amazon DynamoDB" - }, - "line1": { - "from": "icon1", - "to": "icon2", - "label": "Notification" - }, - "line2": { - "from": "icon2", - "to": "icon3", - "label": "Store results" - }, - "line3": { - "from": "icon2", - "to": "icon4", - "label": "Sentiment Analysis" - } - } -} From b19eaa6814800aed83f1c11aea200ce65cf51cd5 Mon Sep 17 00:00:00 2001 From: Arjun Arippa <138874725+awsarippa@users.noreply.github.com> Date: Tue, 9 Jan 2024 14:40:13 +0530 Subject: [PATCH 03/12] Update README.md --- apigw-lambda-translate-cdk/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apigw-lambda-translate-cdk/README.md b/apigw-lambda-translate-cdk/README.md index 77a18bce5..da6e35142 100644 --- a/apigw-lambda-translate-cdk/README.md +++ b/apigw-lambda-translate-cdk/README.md @@ -7,7 +7,7 @@ This patterns shows CDK deployment on how to leverage Amazon API Gateway, AWS La ### What resources will be created? This CDK code will create the following: - One Lambda function (to invoke the Translate API) - - One API Gateway (to trigger the Lambda function with user input) + - One API Gateway (to trigger the Lambda function with user input. The API Gateway does not perform any authorization or authentication of the incoming requests and this pattern should only be used for demonstration purposes only.) - One IAM role (for the Lambda function to invoke Translate service) ## Requirements @@ -62,10 +62,10 @@ and deploy with cdk deploy ``` -The deployment will create a S3 bucket, a Lambda function and a DynamoDB table. +The deployment will create a API Gateway and a Lambda function. ## How it works -The API Gateway handles the incoming requests from user and it invokes the relevant route. The Lambda, triggered by API Gateway, invokes the Translate's TranslateText API and the analyzed response from Translate service is routed back to the requester. +The API Gateway handles the incoming requests from the user and it invokes the relevant route. The Lambda, triggered by API Gateway, invokes the Translate's TranslateText API and the analyzed response from Translate is routed back to the requester. The target language for translation is set to French by default and users are requested to change it as per their use-case. ## Testing Upon successful deployment of the stack, the Output section would provide the `APIEndpoint` in the CDK environment. Alternatively, the `APIEndpoint` can be found from the Outputs section of the `CloudFormation` stack. From abdae2c2d73720029154e1781b5abfa5b69cbb82 Mon Sep 17 00:00:00 2001 From: Arjun Arippa <138874725+awsarippa@users.noreply.github.com> Date: Tue, 9 Jan 2024 14:42:56 +0530 Subject: [PATCH 04/12] Update example-pattern.json --- apigw-lambda-translate-cdk/example-pattern.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apigw-lambda-translate-cdk/example-pattern.json b/apigw-lambda-translate-cdk/example-pattern.json index a20311ace..26abf4d56 100644 --- a/apigw-lambda-translate-cdk/example-pattern.json +++ b/apigw-lambda-translate-cdk/example-pattern.json @@ -27,6 +27,14 @@ { "text": "Amazon Translate Features", "Link": "https://aws.amazon.com/translate/" + }, + { + "text": "Amazon API Gateway", + "link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html" + }, + { + "text": "Amazon API Gateway Features", + "link": "https://aws.amazon.com/api-gateway/" } ] }, From cf1bf8c355089127f30da7a11890502aea61b8c0 Mon Sep 17 00:00:00 2001 From: Arjun Arippa <138874725+awsarippa@users.noreply.github.com> Date: Tue, 9 Jan 2024 14:50:20 +0530 Subject: [PATCH 05/12] Add files via upload --- .../src/architecture.png | Bin 19972 -> 24575 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apigw-lambda-translate-cdk/src/architecture.png b/apigw-lambda-translate-cdk/src/architecture.png index 0a5f76dc755f0a0ac5efc6cecfd42833f96a2d7e..b9b51bbf8c4555bce6bd2540ff4580163687eba5 100644 GIT binary patch literal 24575 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 literal 19972 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 PBSR{v%Rfc@=J&q Date: Tue, 9 Jan 2024 14:51:43 +0530 Subject: [PATCH 06/12] Update README.md --- apigw-lambda-translate-cdk/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apigw-lambda-translate-cdk/README.md b/apigw-lambda-translate-cdk/README.md index da6e35142..d48abebc7 100644 --- a/apigw-lambda-translate-cdk/README.md +++ b/apigw-lambda-translate-cdk/README.md @@ -65,7 +65,7 @@ cdk deploy The deployment will create a API Gateway and a Lambda function. ## How it works -The API Gateway handles the incoming requests from the user and it invokes the relevant route. The Lambda, triggered by API Gateway, invokes the Translate's TranslateText API and the analyzed response from Translate is routed back to the requester. The target language for translation is set to French by default and users are requested to change it as per their use-case. +The API Gateway handles the incoming requests from the user and it invokes the relevant route. The Lambda function, triggered by API Gateway, invokes the Translate's TranslateText API and the analyzed response from Translate is routed back to the requester. The target language for translation is set to French by default and users are requested to change it as per their use-case. ## Testing Upon successful deployment of the stack, the Output section would provide the `APIEndpoint` in the CDK environment. Alternatively, the `APIEndpoint` can be found from the Outputs section of the `CloudFormation` stack. From 6d0ba7e64296d97c44e72f8a7c528a730fcc38ea Mon Sep 17 00:00:00 2001 From: Ben <9841563+bfreiberg@users.noreply.github.com> Date: Wed, 10 Jan 2024 08:27:59 +0100 Subject: [PATCH 07/12] Add final pattern file --- .../apigw-lambda-translate-cdk.json | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json diff --git a/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json new file mode 100644 index 000000000..1c75aee63 --- /dev/null +++ b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json @@ -0,0 +1,94 @@ +{ + "title": "API Gateway - Lambda - Translate", + "description": "Perform language translation using Translate through Lambda and API Gateway", + "language": "Python", + "level": "200", + "framework": "CDK", + "introBox": { + "headline": "How it works", + "text": [ + "This patterns shows CDK deployment on how to leverage Amazon API Gateway, AWS Lambda, and Amazon Translate to perform language translation in a serverless fashion." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/apigw-lambda-translate-cdk", + "templateURL": "serverless-patterns/apigw-lambda-translate-cdk", + "projectFolder": "apigw-lambda-translate-cdk", + "templateFile": "app.py" + } + }, + "resources": { + "bullets": [ + { + "text": "Amazon Translate", + "link": "https://docs.aws.amazon.com/translate/latest/dg/what-is.html" + }, + { + "text": "Amazon Translate Features", + "Link": "https://aws.amazon.com/translate/" + }, + { + "text": "Amazon API Gateway", + "link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html" + }, + { + "text": "Amazon API Gateway Features", + "link": "https://aws.amazon.com/api-gateway/" + } + ] + }, + "deploy": { + "text": [ + "cdk deploy" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the stack: cdk destroy." + ] + }, + "authors": [ + { + "name": "Arjun Arippa", + "image": "https://github.com/awsarippa/amazon-textract-comprehend-pii-analysis/blob/main/image.png", + "bio": "Arjun Arippa is a Solutions Architect based in Bangalore, India. He works with some of the strategic and global customers in India, to build and architect their applications on AWS. Before joining AWS, Arjun spent over a decade working as a Software Developer. Reach out to him on LinkedIn", + "linkedin": "arjun-arippa" + } + ], + "patternArch": { + "icon1": { + "x": 20, + "y": 50, + "service": "apigw", + "label": "API Gateway HTTP API" + }, + "icon2": { + "x": 50, + "y": 50, + "service": "lambda", + "label": "AWS Lambda" + }, + "icon3": { + "x": 80, + "y": 50, + "service": "translate", + "label": "Amazon Translate" + }, + "line1": { + "from": "icon1", + "to": "icon2", + "label": "" + }, + "line2": { + "from": "icon2", + "to": "icon3", + "label": "" + } + } +} From 7df33fa588192498dcedfa00f33b9eaee5ee01c4 Mon Sep 17 00:00:00 2001 From: Arjun Arippa <138874725+awsarippa@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:42:36 +0530 Subject: [PATCH 08/12] Update apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json Co-authored-by: Ben <9841563+bfreiberg@users.noreply.github.com> --- apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json index 1c75aee63..992aaf397 100644 --- a/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json +++ b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json @@ -1,5 +1,5 @@ { - "title": "API Gateway - Lambda - Translate", + "title": "API Gateway to Lambda to Translate", "description": "Perform language translation using Translate through Lambda and API Gateway", "language": "Python", "level": "200", From 54ea5a28b90ca7fb848eb591448269dd9270abb1 Mon Sep 17 00:00:00 2001 From: Arjun Arippa <138874725+awsarippa@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:43:24 +0530 Subject: [PATCH 09/12] Update apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json Co-authored-by: Ben <9841563+bfreiberg@users.noreply.github.com> --- apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json index 992aaf397..5d389bf16 100644 --- a/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json +++ b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json @@ -7,7 +7,7 @@ "introBox": { "headline": "How it works", "text": [ - "This patterns shows CDK deployment on how to leverage Amazon API Gateway, AWS Lambda, and Amazon Translate to perform language translation in a serverless fashion." + "How to leverage Amazon API Gateway, AWS Lambda, and Amazon Translate to perform language translation in a serverless fashion." ] }, "gitHub": { From 86338578a417b8d83bb7a9bc5b29f3fd5553ba22 Mon Sep 17 00:00:00 2001 From: Arjun Arippa <138874725+awsarippa@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:44:12 +0530 Subject: [PATCH 10/12] Update apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json Co-authored-by: Ben <9841563+bfreiberg@users.noreply.github.com> --- apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json index 5d389bf16..a537a5916 100644 --- a/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json +++ b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json @@ -40,7 +40,7 @@ }, "deploy": { "text": [ - "cdk deploy" + "cdk deploy" ] }, "testing": { From 48ef111342483deee53adfc1097833c63b492c38 Mon Sep 17 00:00:00 2001 From: Arjun Arippa <138874725+awsarippa@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:44:25 +0530 Subject: [PATCH 11/12] Update apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json Co-authored-by: Ben <9841563+bfreiberg@users.noreply.github.com> --- apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json index a537a5916..5818c3805 100644 --- a/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json +++ b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json @@ -50,7 +50,7 @@ }, "cleanup": { "text": [ - "Delete the stack: cdk destroy." + "cdk destroy" ] }, "authors": [ From f7ee0e03e93f1e44bf506374681bae5499756598 Mon Sep 17 00:00:00 2001 From: Ben <9841563+bfreiberg@users.noreply.github.com> Date: Fri, 12 Jan 2024 09:35:48 +0100 Subject: [PATCH 12/12] Remove duplicate tag --- apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json index 5818c3805..1ceb3f797 100644 --- a/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json +++ b/apigw-lambda-translate-cdk/apigw-lambda-translate-cdk.json @@ -40,7 +40,7 @@ }, "deploy": { "text": [ - "cdk deploy" + "cdk deploy" ] }, "testing": {