stratosphere-0.9.0: examples/apigw-lambda-dynamodb.hs
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Lens
import Data.Aeson (Value (Array), object)
import qualified Data.ByteString.Lazy.Char8 as B
import Data.Text (Text)
import Stratosphere
-- to curl the endpoints: (substitute your APIGW deployment URL)
-- curl -v -X POST -H "Content-Type: application/json" -d "{\"property\": 3}" "https://k99jn3an8a.execute-api.us-east-1.amazonaws.com/v1/thing"
-- curl -v "https://k99jn3an8a.execute-api.us-east-1.amazonaws.com/v1/thing"
main :: IO ()
main = B.putStrLn $ encodeTemplate myTemplate
myTemplate :: Template
myTemplate = template
[ readLambdaRole
, writeLambdaRole
, readLambda
, writeLambda
, readLambdaPermission
, writeLambdaPermission
, dynamoDbTable
, apiGWRestApi
, apiGWResource
, getMethod
, postMethod
, apiGWDeployment
]
& description ?~ "Simple restful API gateway attached to a Lambda that reads from and writes the request body to a DynamoDB table"
& formatVersion ?~ "2010-09-09"
apiGWRestApi :: Resource
apiGWRestApi =
resource "ApiGWRestApi" $
ApiGatewayRestApiProperties $
apiGatewayRestApi
& agraName ?~ "myApi"
apiGWResource :: Resource
apiGWResource =
resource "ApiGWResource" $
ApiGatewayResourceProperties $
apiGatewayResource
(GetAtt "ApiGWRestApi" "RootResourceId")
"thing"
(toRef apiGWRestApi)
getMethod :: Resource
getMethod = (
resource "ApiGWGetMethod" $
ApiGatewayMethodProperties $
apiGatewayMethod
(Literal GET)
(toRef apiGWResource)
(toRef apiGWRestApi)
& agmeAuthorizationType ?~ Literal NONE
& agmeAuthorizerId ?~ toRef apiGWRestApi
& agmeIntegration ?~ integration
& agmeMethodResponses ?~ [ methodResponse ]
)
& dependsOn ?~ deps [readLambdaPermission]
where
integration =
apiGatewayMethodIntegration
& agmiType ?~ Literal AWS
& agmiIntegrationHttpMethod ?~ Literal POST
& agmiUri ?~ Join "" [
"arn:aws:apigateway:"
, Ref "AWS::Region"
, ":lambda:path/2015-03-31/functions/"
, GetAtt "ReadTableLambda" "Arn"
, "/invocations"]
& agmiIntegrationResponses ?~ [ integrationResponse ]
& agmiPassthroughBehavior ?~ Literal WHEN_NO_TEMPLATES
& agmiRequestTemplates ?~ [ ]
integrationResponse =
apiGatewayMethodIntegrationResponse
"200"
& agmirResponseTemplates ?~ [ ("application/json", "$input.json('$.body')") ]
methodResponse =
apiGatewayMethodMethodResponse
"200"
postMethod :: Resource
postMethod = (
resource "ApiGWPutMethod" $
ApiGatewayMethodProperties $
apiGatewayMethod
(Literal POST)
(toRef apiGWResource)
(toRef apiGWRestApi)
& agmeAuthorizationType ?~ Literal NONE
& agmeAuthorizerId ?~ toRef apiGWRestApi
& agmeIntegration ?~ integration
& agmeMethodResponses ?~ [ methodResponse ]
)
& dependsOn ?~ deps [writeLambdaPermission]
where
integration =
apiGatewayMethodIntegration
& agmiType ?~ Literal AWS
& agmiIntegrationHttpMethod ?~ Literal POST
& agmiUri ?~ Join "" [
"arn:aws:apigateway:"
, Ref "AWS::Region"
, ":lambda:path/2015-03-31/functions/"
, GetAtt "WriteTableLambda" "Arn"
, "/invocations"]
& agmiIntegrationResponses ?~ [integrationResponse]
& agmiPassthroughBehavior ?~ Literal WHEN_NO_TEMPLATES
& agmiRequestTemplates ?~ [ ("application/json", "{\"body\": $input.body}") ]
integrationResponse =
apiGatewayMethodIntegrationResponse
"200"
& agmirResponseTemplates ?~ [ ("application/json", "$input.json('$.body')") ]
methodResponse =
apiGatewayMethodMethodResponse
"200"
apiGWDeployment :: Resource
apiGWDeployment = (resource "ApiGWDeployment" $
ApiGatewayDeploymentProperties $
apiGatewayDeployment
(toRef apiGWRestApi)
& agdStageName ?~ "v1"
)
& dependsOn ?~ deps [
apiGWResource
, getMethod
, postMethod
]
readLambda :: Resource
readLambda = (resource "ReadTableLambda" $
LambdaFunctionProperties $
lambdaFunction
lambdaCode
"index.handler"
(GetAtt "ReadLambdaRole" "Arn")
(Literal NodeJS43)
& lfFunctionName ?~ "readTable"
)
where
lambdaCode :: LambdaFunctionCode
lambdaCode = lambdaFunctionCode
& lfcZipFile ?~ code
code :: Val Text
code = "\
\ var AWS = require('aws-sdk');\n\
\ var awsConfig = { region: 'us-east-1' }; \n\
\ AWS.config.apiVersions = { dynamodb: '2012-08-10' }; \n\
\ var dynamoDoc = new AWS.DynamoDB.DocumentClient(awsConfig); \n\
\ exports.handler = function(event, context, callback) {\n\
\ console.log(JSON.stringify(event));\n\
\ var params = { TableName : 'stratosphere-dynamodb-table', Key: { Id: 'abc123' } }; \n\
\ dynamoDoc.get(params, function(err, data) { \n\
\ if (err) { \n\
\ console.log(\"Error:\", err); \n\
\ callback(err) \n\
\ } else { \n\
\ callback(null, {\"body\": data.Item.Data});\n\
\ } \n\
\ });\n\
\ }\n\
\ "
writeLambda :: Resource
writeLambda =
resource "WriteTableLambda" $
LambdaFunctionProperties $
lambdaFunction
lambdaCode
"index.handler"
(GetAtt "WriteLambdaRole" "Arn")
(Literal NodeJS43)
& lfFunctionName ?~ "writeTable"
where
lambdaCode :: LambdaFunctionCode
lambdaCode = lambdaFunctionCode
& lfcZipFile ?~ code
code :: Val Text
code = "\
\ var AWS = require('aws-sdk');\n\
\ var awsConfig = { region: 'us-east-1' }; \n\
\ AWS.config.apiVersions = { dynamodb: '2012-08-10' }; \n\
\ var dynamoDoc = new AWS.DynamoDB.DocumentClient(awsConfig); \n\
\ exports.handler = function(event, context, callback) {\n\
\ console.log(JSON.stringify(event));\n\
\ var params = { TableName : 'stratosphere-dynamodb-table', Item: { Id: 'abc123', Data: event.body } }; \n\
\ dynamoDoc.put(params, function(err, data) { \n\
\ if (err) { \n\
\ console.log(\"Error:\", err); \n\
\ callback(err) \n\
\ } else { \n\
\ callback(null, {\"body\": 'success!'});\n\
\ } \n\
\ });\n\
\ }\n\
\ "
readLambdaRole :: Resource
readLambdaRole = resource "ReadLambdaRole" $
IAMRoleProperties $
iamRole
rolePolicyDocumentObject
& iamrPolicies ?~ [ executePolicy ]
& iamrRoleName ?~ "ReadLambdaRole"
& iamrPath ?~ "/"
where
executePolicy =
iamRolePolicy
[ ("Version", "2012-10-17")
, ("Statement", statement)
]
"MyLambdaExecutionPolicy"
where
statement = object
[ ("Effect", "Allow")
, ("Action", actions)
, ("Resource", "*")
]
actions = Array
[ "logs:CreateLogGroup"
, "logs:CreateLogStream"
, "logs:PutLogEvents"
, "dynamodb:GetItem"
]
rolePolicyDocumentObject =
[ ("Version", "2012-10-17")
, ("Statement", statement)
]
where
statement = object
[ ("Effect", "Allow")
, ("Principal", principal)
, ("Action", "sts:AssumeRole")
]
principal = object
[ ("Service", "lambda.amazonaws.com") ]
writeLambdaRole :: Resource
writeLambdaRole = resource "WriteLambdaRole" $
IAMRoleProperties $
iamRole
rolePolicyDocumentObject
& iamrPolicies ?~ [ executePolicy ]
& iamrRoleName ?~ "WriteLambdaRole"
& iamrPath ?~ "/"
where
executePolicy =
iamRolePolicy
[ ("Version", "2012-10-17")
, ("Statement", statement)
]
"MyLambdaExecutionPolicy"
where
statement = object
[ ("Effect", "Allow")
, ("Action", actions)
, ("Resource", "*")
]
actions = Array
[ "logs:CreateLogGroup"
, "logs:CreateLogStream"
, "logs:PutLogEvents"
, "dynamodb:PutItem"
]
rolePolicyDocumentObject =
[ ("Version", "2012-10-17")
, ("Statement", statement)
]
where
statement = object
[ ("Effect", "Allow")
, ("Principal", principal)
, ("Action", "sts:AssumeRole")
]
principal = object
[ ("Service", "lambda.amazonaws.com") ]
readLambdaPermission :: Resource
readLambdaPermission = resource "ReadLambdaPermission" $
LambdaPermissionProperties $
lambdaPermission
"lambda:*"
(GetAtt "ReadTableLambda" "Arn")
"apigateway.amazonaws.com"
writeLambdaPermission :: Resource
writeLambdaPermission = resource "WriteLambdaPermission" $
LambdaPermissionProperties $
lambdaPermission
"lambda:*"
(GetAtt "WriteTableLambda" "Arn")
"apigateway.amazonaws.com"
dynamoDbTable :: Resource
dynamoDbTable = resource "Table" $
DynamoDBTableProperties $
dynamoDBTable
keySchema
provisionedThroughput
& ddbtAttributeDefinitions ?~ attributeDefinitions
& ddbtTableName ?~ "stratosphere-dynamodb-table"
where
attributeDefinitions = [
dynamoDBTableAttributeDefinition
(Literal "Id")
(Literal S)
]
keySchema = [
dynamoDBTableKeySchema
(Literal "Id")
(Literal HASH)
]
provisionedThroughput =
dynamoDBTableProvisionedThroughput
(Literal 1)
(Literal 1)
deps :: [Resource] -> [Text]
deps = map (^. resName)