Build cloud applications in minutes instead of days
With Zephyr, even the most complex cloud systems can be made simple, elegant, and succinct.
Build cloud applications in minutes instead of days
With Zephyr, even the most complex cloud systems can be made simple, elegant, and succinct.
provider "aws" {
region = "us-east-1"
}
# Queue and dead-letter queue for widget updates
resource "aws_sqs_queue" "widget_updates_queue" {
name = "results-updates-queue"
redrive_policy = "{\"deadLetterTargetArn\":\"${aws_sqs_queue.results_updates_dl_queue.arn}\",\"maxReceiveCount\":5}"
visibility_timeout_seconds = 300
tags = {
Environment = "dev"
}
}
resource "aws_sqs_queue" "results_updates_dl_queue" {
name = "results-updates-dl-queue"
}
# IAM role and policy for POST /widgets lambda
resource "aws_iam_role" "post_lambda_role" {
name = "Post_Lambda_Function_Role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_policy" "iam_policy_for_post_lambda" {
name = "aws_iam_policy_for_terraform_aws_lambda_role"
path = "/"
description = "AWS IAM Policy for managing aws lambda role"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*",
"Effect": "Allow"
},
{
"Action": [
"sqs:GetQueueAttributes",
"sqs:SendMessage"
],
"Effect": "Allow",
"Resource": "${aws_sqs_queue.widget_updates_queue.arn}"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "attach_iam_policy_to_iam_role" {
role = aws_iam_role.post_lambda_role.name
policy_arn = aws_iam_policy.iam_policy_for_post_lambda.arn
}
# Create the POST /widgets lambda
resource "aws_lambda_function" "post_widgets_func" {
filename = "post-widgets/dist.zip"
function_name = "Post_Widgets_Lambda_Function"
role = aws_iam_role.post_lambda_role.arn
handler = "index.lambda_handler"
runtime = "python3.8"
depends_on = [aws_iam_role_policy_attachment.attach_iam_policy_to_iam_role]
}
# Create an API gateway and route POST /widgets to our lambda
resource "aws_apigatewayv2_api" "widgets_api" {
name = "serverless_lambda_gw"
protocol_type = "HTTP"
}
resource "aws_apigatewayv2_stage" "prod" {
api_id = aws_apigatewayv2_api.widgets_api.id
name = "serverless_lambda_stage"
auto_deploy = true
}
resource "aws_apigatewayv2_integration" "post_widgets" {
api_id = aws_apigatewayv2_api.widgets_api.id
integration_uri = aws_lambda_function.post_widgets_func.invoke_arn
integration_type = "AWS_PROXY"
integration_method = "POST"
}
resource "aws_apigatewayv2_route" "post_widgets_func" {
api_id = aws_apigatewayv2_api.widgets_api.id
route_key = "POST /widgets"
target = "integrations/${aws_apigatewayv2_integration.post_widgets.id}"
}
resource "aws_lambda_permission" "api_gw" {
statement_id = "AllowExecutionFromAPIGateway"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.post_widgets_func.function_name
principal = "apigateway.amazonaws.com"
source_arn = "${aws_apigatewayv2_api.lambda.execution_arn}/*/*"
}
# IAM role and policy for lambda that updates reporting db
resource "aws_iam_role" "update_reporting_lambda_role" {
name = "Update_Reporting_Function_Role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_policy" "iam_policy_for_reporting_lambda" {
name = "aws_iam_policy_for_terraform_aws_lambda_role"
path = "/"
description = "AWS IAM Policy for managing aws lambda role"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*",
"Effect": "Allow"
},
{
"Action": [
"sqs:ChangeMessageVisibility",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes",
"sqs:ReceiveMessage"
],
"Effect": "Allow",
"Resource": "${aws_sqs_queue.widget_updates_queue.arn}"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "attach_iam_policy_to_iam_role" {
role = aws_iam_role.update_reporting_lambda_role.name
policy_arn = aws_iam_policy.iam_policy_for_reporting_lambda.arn
}
# Create the lambda that updates the reporting db
resource "aws_lambda_function" "update_reporting_func" {
filename = "update-reporting/dist.zip"
function_name = "Update_Reporting_Lambda_Function"
role = aws_iam_role.update_reporting_lambda_role.arn
handler = "index.lambda_handler"
runtime = "python3.8"
depends_on = [aws_iam_role_policy_attachment.attach_iam_policy_to_iam_role]
}
# Event source from our queue into our reporting lambda
resource "aws_lambda_event_source_mapping" "event_source_mapping" {
event_source_arn = "${aws_sqs_queue.widget_updates_queue.arn}"
enabled = true
function_name = "${aws_lambda_function.update_reporting_func.arn}"
batch_size = 1
}
use aws::lambda
op addWidget(widget) = lambda!(
#pkg::src('./operations/add-widget'), widget
)
op addToReportingDatabase(widget) = lambda!(
#pkg::src('./operations/update-reporting'), widget
)
api 'widgets-service.example.com' = REST {
POST /widgets widget = addWidget(widget)
}
addWidget(widget) --> addToReportingDatabase(widget)
Architecture-as-code
Human-friendly syntax for common patterns. Instead of writing infrastructure boilerplate, directly express your system design with high-level "architecture-as-code."
Learn More// Define operations
op removeOutliers(data)
op normalize(row)
op updateModel(data)
// Define events
evt NewData(data)
// Data pipeline
NewData(dataPoints) --> removeOutliers(dataPoints)
// Map
-=> [row] normalize(row): normalized
// Collect
=-> []collected updateModel(collected)
// Define operations
op eventListener(x)
op otherListener(y)
// Define events
evt FooEvent(x, y)
api 'async-api.my-org.co' = REST {
// POST endpoint that generates an event
POST /foo { field1, field2 } --> FooEvent(
field1, field2
)
}
// Multiple asynchronous event listeners
FooEvent(field1, _) --> eventListener(field1)
FooEvent(_, field2) --> otherListener(field2)
// Define operations
op createOrUpdateWidget(widget)
api 'api.my-org.co' = REST {
// Map endpoints
POST /widgets body = createOrUpdateWidget(body)
PUT /widgets/:id body = createOrUpdateWidget({
id, ...body
})
PATCH /widgets/:id body = createOrUpdateWidget({
id, ...body
})
}
Easy adoption, total flexibility
Use any language or tech stack. Integrates seamlessly with the tools you already use.
Learn More