Skip to content

Instantly share code, notes, and snippets.

@singledigit
Created September 24, 2020 17:42
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save singledigit/df585310188f9c4ae3c8349c34cccd2f to your computer and use it in GitHub Desktop.
Example of an AWS Lambda Destinations configuration for AWS Lambda functions within an application.
# You don't need this, but here it is anyways :)
openapi: "3.0.1"
info:
title: "Translation API (Async)"
version: "1.0.0"
paths:
/:
post:
summary: Create new translation request
responses:
"200":
headers:
Access-Control-Allow-Origin:
type: "string"
"400":
headers:
Access-Control-Allow-Origin:
type: "string"
x-amazon-apigateway-integration:
type: "aws"
credentials:
Fn::GetAtt: [ DDBCrudRole, Arn ]
uri: { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:dynamodb:action/UpdateItem" }
httpMethod: "POST"
requestTemplates:
application/json: { "Fn::Sub": "{\"TableName\": \"${TranslationsTable}\",\
\"ConditionExpression\":\"attribute_not_exists(id)\",\
\"Key\": {\"id\": {\"S\": \"$context.requestId\"}, \"type\": {\"S\": \"original\"}},\
\"ExpressionAttributeNames\": {\"#ts\": \"timestamp\", \"#oi\": \"originalId\", \"#d\": \"data\", \"#c\": \"culture\"},\
\"ExpressionAttributeValues\":{\
\":ts\": {\"S\": \"$context.requestTimeEpoch\"},\
\":oi\": {\"S\": \"original-$context.requestId\"},\
\":d\": {\"S\": $input.json('$.data')},\
\":c\": {\"L\": [#foreach($culture in $input.path('$.culture')){\"S\": \"$culture\"}#if($foreach.hasNext),#end#end]}
}, \
\"UpdateExpression\": \"SET #ts = :ts, #oi = :oi, #d = :d, #c = :c\",\
\"ReturnValues\": \"ALL_NEW\"}" }
passthroughBehavior: "when_no_templates"
responses:
"200":
statusCode: "200"
responseParameters:
method.response.header.Access-Control-Allow-Origin: "'*'"
responseTemplates:
application/json: "{\"success\": true}"
default:
statusCode: "400"
responseParameters:
method.response.header.Access-Control-Allow-Origin: "'*'"
responseTemplates:
application/json: "{\"success\": false}"
get:
summary: Fetch all translations request
responses:
"200":
description: "succesful response"
headers:
Access-Control-Allow-Origin:
type: "string"
"400":
description: "unsuccesful response"
headers:
Access-Control-Allow-Origin:
type: "string"
x-amazon-apigateway-integration:
type: "AWS"
credentials:
Fn::GetAtt: [ DDBReadRole, Arn ]
uri: { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:dynamodb:action/Scan" }
httpMethod: "POST"
requestTemplates:
application/json: { "Fn::Sub": "{\"TableName\": \"${TranslationsTable}\",\"IndexName\":\"Originals\"}" }
passthroughBehavior: "when_no_templates"
responses:
"200":
statusCode: "200"
responseParameters:
method.response.header.Access-Control-Allow-Origin: "'*'"
responseTemplates:
application/json: "#set($items = $input.path('$.Items')){\
\"success\": true,\
\"Items\": [#foreach($item in $items){\
\"id\":\"$item.id.S\",\
\"data\":\"$item.data.S\",\
\"sentiment\": \"$item.sentiment.S\",\
\"timestamp\": \"$item.timestamp.S\",\
\"culture\": [#foreach($c in $item.culture.L)\"$c.S\"#if($foreach.hasNext), #end#end]\
}#if($foreach.hasNext),#end#end]}"
default:
statusCode: "400"
responseParameters:
method.response.header.Access-Control-Allow-Origin: "'*'"
responseTemplates:
application/json: "{\"success\": false}"
/{id}:
get:
summary: Fetch all translations request
parameters:
- in: path
name: id
schema:
type: string
required: true
description: Tranlation id
responses:
"200":
description: "succesful response"
headers:
Access-Control-Allow-Origin:
type: "string"
"400":
description: "unsuccesful response"
headers:
Access-Control-Allow-Origin:
type: "string"
x-amazon-apigateway-integration:
type: "AWS"
credentials:
Fn::GetAtt: [ DDBReadRole, Arn ]
uri: { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:dynamodb:action/Query" }
httpMethod: "POST"
requestTemplates:
application/json: { "Fn::Sub": "{\
\"TableName\": \"${TranslationsTable}\",\
\"KeyConditionExpression\": \"id = :hkey\",\
\"ExpressionAttributeValues\": {\":hkey\": {\"S\": \"$input.params().path.id\"}}}"
}
passthroughBehavior: "when_no_templates"
responses:
"200":
statusCode: "200"
responseParameters:
method.response.header.Access-Control-Allow-Origin: "'*'"
responseTemplates:
application/json: "#set($items = $input.path('$.Items')){\
\"success\": true,\
\"Items\": [#foreach($item in $items){\
\"id\":\"$item.id.S\",\
\"data\":\"$item.data.S\",\
\"timestamp\": \"$item.timestamp.N\",\
\"type\": \"$item.type.S\",\
#if($item.originalId.S.toString() != \"\")\
\"sentiment\": \"$item.sentiment.S\",\
\"originalId\": \"$item.originalId.S\",\
\"culture\": [#foreach($c in $item.culture.L)\"$c.S\"#if($foreach.hasNext), #end#end]\
#else\"culture\": \"$item.culture.S\"#end\
}#if($foreach.hasNext),#end#end]}"
default:
statusCode: "400"
responseParameters:
method.response.header.Access-Control-Allow-Origin: "'*'"
responseTemplates:
application/json: "{\"success\": false}"
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Asynchronous Serverless Translation Application
Globals:
Function:
Timeout: 10
Handler: app.lambdaHandler
Runtime: nodejs12.x
Layers:
- arn:aws:lambda:us-west-2:700336187521:layer:aws-sdk:9
Api:
Cors:
AllowOrigin: "'*'"
AllowHeaders: "'*'"
Resources:
SiteAPI:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
EndpointConfiguration: REGIONAL
TracingEnabled: true
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location: './api.yaml'
AudioBucket:
Type: AWS::S3::Bucket
ErrorDestination:
Type: AWS::Serverless::Function
Properties:
CodeUri: error/
Policies:
- DynamoDBCrudPolicy: {TableName: !Ref TranslationsTable}
Environment:
Variables:
TRANSLATIONS_TABLE: !Ref TranslationsTable
StreamFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: stream/
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'events:PutEvents'
Resource: '*'
Events:
DDBStream:
Type: DynamoDB
Properties:
Stream: !GetAtt TranslationsTable.StreamArn
StartingPosition: LATEST ##TRIM_HORIZON
BatchSize: 10
Enabled: true
TranslateFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: translate/
Policies:
- DynamoDBCrudPolicy: {TableName: !Ref TranslationsTable}
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'translate:TranslateText'
- 'comprehend:DetectDominantLanguage'
Resource: '*'
Events:
TranslateEvent:
Type: CloudWatchEvent
Properties:
Pattern:
source:
- "DBStream"
detail-type:
- "translation"
Environment:
Variables:
TRANSLATIONS_TABLE: !Ref TranslationsTable
EventInvokeConfig:
DestinationConfig:
OnFailure:
Type: Lambda
Destination: !GetAtt ErrorDestination.Arn
AudioFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: audio/
Policies:
- S3CrudPolicy: {BucketName: !Ref AudioBucket}
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'polly:SynthesizeSpeech'
- 'polly:StartSpeechSynthesisTask'
Resource: '*'
Events:
AudioEvent:
Type: CloudWatchEvent
Properties:
Pattern:
source:
- "DBStream"
detail-type:
- "audio"
Environment:
Variables:
AUDIO_BUCKET: !Ref AudioBucket
FinalFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: final/
Policies:
- DynamoDBCrudPolicy: {TableName: !Ref TranslationsTable}
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 's3:PutObjectACL'
Resource: '*'
Events:
AudioComplete:
Type: S3
Properties:
Bucket: !Ref AudioBucket
Events: s3:ObjectCreated:*
Environment:
Variables:
TRANSLATIONS_TABLE: !Ref TranslationsTable
SentimentFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: sentiment/
Policies:
- DynamoDBCrudPolicy: {TableName: !Ref TranslationsTable}
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'comprehend:DetectSentiment'
Resource: '*'
Events:
SentimentEvent:
Type: CloudWatchEvent
Properties:
Pattern:
source:
- "DBStream"
detail-type:
- "translation"
Environment:
Variables:
TRANSLATIONS_TABLE: !Ref TranslationsTable
TranslationsTable:
Type: AWS::DynamoDB::Table
Properties:
BillingMode: PAY_PER_REQUEST
KeySchema:
- AttributeName: id
KeyType: HASH
- AttributeName: type
KeyType: RANGE
AttributeDefinitions:
- AttributeName: id
AttributeType: S
- AttributeName: type
AttributeType: S
- AttributeName: originalId
AttributeType: S
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES
GlobalSecondaryIndexes:
- IndexName: Originals
KeySchema:
- AttributeName: originalId
KeyType: HASH
Projection:
NonKeyAttributes:
- data
- culture
- timestamp
- sentiment
ProjectionType: INCLUDE
## Dynamo DB Read Role
DDBReadRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
Service: "apigateway.amazonaws.com"
Action:
- "sts:AssumeRole"
Policies:
- PolicyName: DDBReadPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
Action:
- dynamodb:GetItem
- dynamodb:Scan
- dynamodb:Query
Effect: Allow
Resource:
- !GetAtt TranslationsTable.Arn
## Dynamo DB Read/Write Role
DDBCrudRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Principal:
Service: "apigateway.amazonaws.com"
Action:
- "sts:AssumeRole"
Policies:
- PolicyName: DDBCrudPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
Action:
- dynamodb:DeleteItem
- dynamodb:UpdateItem
Effect: Allow
Resource: !GetAtt TranslationsTable.Arn
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment