|
| 1 | +terraform { |
| 2 | + required_providers { |
| 3 | + aws = { |
| 4 | + source = "hashicorp/aws" |
| 5 | + version = "~> 4.0.0" |
| 6 | + } |
| 7 | + random = { |
| 8 | + source = "hashicorp/random" |
| 9 | + version = "~> 3.1.0" |
| 10 | + } |
| 11 | + archive = { |
| 12 | + source = "hashicorp/archive" |
| 13 | + version = "~> 2.2.0" |
| 14 | + } |
| 15 | + } |
| 16 | + |
| 17 | + required_version = ">= 0.14.9" |
| 18 | +} |
| 19 | + |
| 20 | +provider "aws" { |
| 21 | + region = "eu-west-1" |
| 22 | +} |
| 23 | +data "aws_region" "current" {} |
| 24 | + |
| 25 | +locals { |
| 26 | + stack_name = "template" |
| 27 | +} |
| 28 | + |
| 29 | +variable "api_stage_name" { |
| 30 | + description = "Name of WebSocket API stage" |
| 31 | + type = string |
| 32 | + default = "production" |
| 33 | +} |
| 34 | + |
| 35 | +resource "aws_sns_topic" "sns_topic" { |
| 36 | + display_name = "${local.stack_name}-SNSTopic" |
| 37 | +} |
| 38 | + |
| 39 | +resource "aws_apigatewayv2_api" "web_socket_api" { |
| 40 | + name = "${local.stack_name}-WebSocketApi" |
| 41 | + protocol_type = "WEBSOCKET" |
| 42 | + route_selection_expression = "$request.body.action" |
| 43 | +} |
| 44 | + |
| 45 | + |
| 46 | +resource "aws_apigatewayv2_stage" "MyApiGatewayStage" { |
| 47 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 48 | + name = var.api_stage_name |
| 49 | + auto_deploy = true |
| 50 | +} |
| 51 | + |
| 52 | +resource "aws_apigatewayv2_route" "connect_route" { |
| 53 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 54 | + route_key = "$connect" |
| 55 | + authorization_type = "NONE" |
| 56 | + route_response_selection_expression = "$default" |
| 57 | + operation_name = "ConnectRoute" |
| 58 | + target = join("/", ["integrations", aws_apigatewayv2_integration.connect_route_integration.id]) |
| 59 | +} |
| 60 | + |
| 61 | +resource "aws_apigatewayv2_integration" "connect_route_integration" { |
| 62 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 63 | + integration_type = "MOCK" |
| 64 | + request_templates = { |
| 65 | + 200 = "{\"statusCode\":200}" |
| 66 | + } |
| 67 | + template_selection_expression = "200" |
| 68 | + passthrough_behavior = "WHEN_NO_MATCH" |
| 69 | +} |
| 70 | + |
| 71 | +resource "aws_apigatewayv2_route_response" "connect_route_response" { |
| 72 | + route_id = aws_apigatewayv2_route.connect_route.id |
| 73 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 74 | + route_response_key = "$default" |
| 75 | +} |
| 76 | + |
| 77 | +resource "aws_apigatewayv2_integration_response" "connect_route_integration_response" { |
| 78 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 79 | + integration_id = aws_apigatewayv2_integration.connect_route_integration.id |
| 80 | + integration_response_key = "/200/" |
| 81 | + template_selection_expression = "\\$default" |
| 82 | + response_templates = { |
| 83 | + 200 = "{\"statusCode\":, \"message\":\"order initiated\"}" |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +resource "aws_iam_role" "apigw_sns_demo_functionrole" { |
| 88 | + #name = "apigw_sns_demo_functionrole" |
| 89 | + assume_role_policy = <<EOF |
| 90 | +{ |
| 91 | + "Version": "2012-10-17", |
| 92 | + "Statement": [ |
| 93 | + { |
| 94 | + "Action": "sts:AssumeRole", |
| 95 | + "Principal": { |
| 96 | + "Service": "apigateway.amazonaws.com" |
| 97 | + }, |
| 98 | + "Effect": "Allow", |
| 99 | + "Sid": "" |
| 100 | + } |
| 101 | + ] |
| 102 | +} |
| 103 | +EOF |
| 104 | +} |
| 105 | + |
| 106 | +# Custom policy |
| 107 | +resource "aws_iam_policy" "apigw_sns_demo_policy" { |
| 108 | + name = "apigw-sns-demo-policy" |
| 109 | + path = "/" |
| 110 | + description = "Policy for APIGW to SNS demo" |
| 111 | + policy = <<EOF |
| 112 | +{ |
| 113 | + "Version" : "2012-10-17", |
| 114 | + "Statement" : [ |
| 115 | + { |
| 116 | + "Effect": "Allow", |
| 117 | + "Action": [ |
| 118 | + "sns:Publish" |
| 119 | + ], |
| 120 | + "Resource": "${aws_sns_topic.sns_topic.arn}" |
| 121 | + } |
| 122 | + ] |
| 123 | +} |
| 124 | +EOF |
| 125 | +} |
| 126 | + |
| 127 | +resource "aws_iam_role_policy_attachment" "apigw_policy_attachment" { |
| 128 | + role = aws_iam_role.apigw_sns_demo_functionrole.name |
| 129 | + policy_arn = aws_iam_policy.apigw_sns_demo_policy.arn |
| 130 | +} |
| 131 | + |
| 132 | + |
| 133 | +resource "aws_apigatewayv2_route" "disconnect_route" { |
| 134 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 135 | + route_key = "$disconnect" |
| 136 | + operation_name = "DisconnectRoute" |
| 137 | + target = join("/", ["integrations", aws_apigatewayv2_integration.disconnect_route_integration.id]) |
| 138 | +} |
| 139 | + |
| 140 | +resource "aws_apigatewayv2_integration" "disconnect_route_integration" { |
| 141 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 142 | + integration_type = "MOCK" |
| 143 | + request_templates = { |
| 144 | + 200 = "{\"statusCode\":200}" |
| 145 | + } |
| 146 | + template_selection_expression = "200" |
| 147 | + passthrough_behavior = "WHEN_NO_MATCH" |
| 148 | +} |
| 149 | + |
| 150 | +resource "aws_apigatewayv2_integration_response" "disconnect_route_integration_response" { |
| 151 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 152 | + integration_id = aws_apigatewayv2_integration.disconnect_route_integration.id |
| 153 | + integration_response_key = "/200/" |
| 154 | + template_selection_expression = "\\$default" |
| 155 | +} |
| 156 | + |
| 157 | + |
| 158 | +resource "aws_apigatewayv2_integration" "send_order_route_integration" { |
| 159 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 160 | + integration_type = "AWS" |
| 161 | + integration_uri = "arn:aws:apigateway:${data.aws_region.current.name}:sns:action/Publish" |
| 162 | + credentials_arn = aws_iam_role.apigw_sns_demo_functionrole.arn |
| 163 | + integration_method = "POST" |
| 164 | + content_handling_strategy = "CONVERT_TO_TEXT" |
| 165 | + request_parameters = { |
| 166 | + "integration.request.header.Content-Type" = "'application/x-www-form-urlencoded'" |
| 167 | + } |
| 168 | + request_templates = { |
| 169 | + "$default" = "Action=Publish&TopicArn=$util.urlEncode(\"${aws_sns_topic.sns_topic.id}\")&Message=$input.json('$')" |
| 170 | + } |
| 171 | + template_selection_expression = "$request.body.action" |
| 172 | +} |
| 173 | + |
| 174 | +resource "aws_apigatewayv2_model" "food_order_model" { |
| 175 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 176 | + content_type = "application/json" |
| 177 | + description = "this model helps us to ensure that all the required parameters are passed on to the SNS topic" |
| 178 | + name = "orderModel" |
| 179 | + schema = "{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"title\":\"orderInputModel\",\"type\":\"object\",\"properties\":{\"Number\":{\"type\":\"string\"},\"SirName\":{\"type\":\"string\"},\"Name\":{\"type\":\"string\"}},\"required\":[\"Name\",\"SirName\",\"Number\"]}" |
| 180 | +} |
| 181 | + |
| 182 | +resource "aws_apigatewayv2_route" "send_order" { |
| 183 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 184 | + route_key = "sendOrder" |
| 185 | + authorization_type = "NONE" |
| 186 | + model_selection_expression = "$request.body.action" |
| 187 | + request_models = { |
| 188 | + sendOrder = "orderModel" |
| 189 | + } |
| 190 | + target = join("/", ["integrations", aws_apigatewayv2_integration.send_order_route_integration.id]) |
| 191 | +} |
| 192 | + |
| 193 | +resource "aws_apigatewayv2_route_response" "send_order_route_response" { |
| 194 | + route_id = aws_apigatewayv2_route.send_order.id |
| 195 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 196 | + route_response_key = "$default" |
| 197 | +} |
| 198 | + |
| 199 | +resource "aws_apigatewayv2_integration_response" "send_order_route_integration_response" { |
| 200 | + api_id = aws_apigatewayv2_api.web_socket_api.id |
| 201 | + integration_id = aws_apigatewayv2_integration.send_order_route_integration.id |
| 202 | + integration_response_key = "$default" |
| 203 | +} |
| 204 | + |
| 205 | + |
| 206 | + |
| 207 | +output "api_endpoint" { |
| 208 | + description = "API Gateway endpoint URL" |
| 209 | + value = "wss://${aws_apigatewayv2_api.web_socket_api.id}.execute-api.${data.aws_region.current.name}.amazonaws.com/${var.api_stage_name}" |
| 210 | +} |
0 commit comments