Skip to content

Commit a0b02cf

Browse files
authored
Merge pull request #2 from futurice/remove-cloudfront-from-aws-lambda-api
Remove CloudFront from aws_lambda_api
2 parents eae9573 + 3a0da9a commit a0b02cf

File tree

8 files changed

+167
-332
lines changed

8 files changed

+167
-332
lines changed

aws_lambda_api/README.md

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@
33
This module creates a Lambda function, and makes it available via a custom domain, complete with SSL termination: e.g. `https://api.example.com/`. This includes:
44

55
- DNS records on [Route 53](https://aws.amazon.com/route53/)
6-
- A [CloudFront](https://aws.amazon.com/cloudfront/) distribution for SSL termination
7-
- An SSL certificate for the distribution from [ACM](https://aws.amazon.com/certificate-manager/)
8-
- A [Lambda](https://aws.amazon.com/lambda/) function built from your JavaScript code
6+
- An SSL certificate for the domain from [ACM](https://aws.amazon.com/certificate-manager/)
97
- [API Gateway](https://aws.amazon.com/api-gateway/) configuration for invoking the function over HTTP
8+
- A [Lambda](https://aws.amazon.com/lambda/) function built from your JavaScript code
109

1110
## Example 1: Simple API
1211

13-
**Important:** CloudFront operations are generally very slow. Your `terraform apply` may take anywhere **from 10 minutes up to 45 minutes** to complete.
14-
1512
First, write down some simple code to deploy in a file called `index.js`:
1613

1714
```js
@@ -31,15 +28,6 @@ exports.handler = function(event, context, callback) {
3128
Assuming you have the [AWS provider](https://www.terraform.io/docs/providers/aws/index.html) set up, and a DNS zone for `example.com` configured on Route 53:
3229

3330
```tf
34-
# Several AWS services (such as ACM & Lambda@Edge) are presently only available in the US East region.
35-
# To be able to use them, we need a separate AWS provider for that region, which can be used with an alias.
36-
# Make sure you customize this block to match your regular AWS provider configuration.
37-
# https://www.terraform.io/docs/configuration/providers.html#multiple-provider-instances
38-
provider "aws" {
39-
alias = "us_east_1"
40-
region = "us-east-1"
41-
}
42-
4331
# Lambda functions can only be uploaded as ZIP files, so we need to package our JS file into one
4432
data "archive_file" "lambda_zip" {
4533
type = "zip"
@@ -62,7 +50,7 @@ module "my_api" {
6250
}
6351
```
6452

65-
After `terraform apply` (which may take a **very** long time), you should be able to visit `https://api.example.com/`, and be greeted by the above `Hello World!` message.
53+
After `terraform apply`, you should be able to visit `https://api.example.com/`, and be greeted by the above `Hello World!` message.
6654

6755
Because we included the `lambda_logging_enabled` option, you can also log into CloudWatch and check out the properties Lambda makes available in the `event` and `context` properties.
6856

@@ -83,15 +71,6 @@ Importantly, the most recent compiled version of the Lambda function should alwa
8371
Assuming you have the [AWS provider](https://www.terraform.io/docs/providers/aws/index.html) set up, and a DNS zone for `example.com` configured on Route 53:
8472

8573
```tf
86-
# Several AWS services (such as ACM & Lambda@Edge) are presently only available in the US East region.
87-
# To be able to use them, we need a separate AWS provider for that region, which can be used with an alias.
88-
# Make sure you customize this block to match your regular AWS provider configuration.
89-
# https://www.terraform.io/docs/configuration/providers.html#multiple-provider-instances
90-
provider "aws" {
91-
alias = "us_east_1"
92-
region = "us-east-1"
93-
}
94-
9574
module "my_api" {
9675
# Available inputs: https://github.com/futurice/terraform-utils/tree/master/aws_lambda_api#inputs
9776
# Check for updates: https://github.com/futurice/terraform-utils/compare/v9.4...master
@@ -103,7 +82,7 @@ module "my_api" {
10382
}
10483
```
10584

106-
After `terraform apply` (which may take a **very** long time), you should be able to receive a random joke with:
85+
After `terraform apply`, you should be able to receive a random joke with:
10786

10887
```bash
10988
$ curl https://api.example.com
@@ -130,15 +109,6 @@ Bundling the code and build artifacts for your Lambda function is all well and g
130109
This also makes it easy to support multiple environments, and release promotions between them. For example:
131110

132111
```tf
133-
# Several AWS services (such as ACM & Lambda@Edge) are presently only available in the US East region.
134-
# To be able to use them, we need a separate AWS provider for that region, which can be used with an alias.
135-
# Make sure you customize this block to match your regular AWS provider configuration.
136-
# https://www.terraform.io/docs/configuration/providers.html#multiple-provider-instances
137-
provider "aws" {
138-
alias = "us_east_1"
139-
region = "us-east-1"
140-
}
141-
142112
resource "aws_s3_bucket" "my_builds" {
143113
bucket = "my-builds"
144114
}
@@ -250,6 +220,40 @@ EOF
250220

251221
Otherwise API Gateway won't have permission to write logs to CloudWatch.
252222

223+
## Supporting CORS
224+
225+
Your API can easily support CORS, if needed. For example:
226+
227+
```js
228+
// https://enable-cors.org/server_nginx.html
229+
const CORS_HEADERS = {
230+
"Access-Control-Allow-Origin": "*",
231+
"Access-Control-Allow-Methods": "POST,OPTIONS,GET,PUT,PATCH,DELETE",
232+
"Access-Control-Allow-Headers": "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range",
233+
"Access-Control-Expose-Headers": "Content-Length,Content-Range",
234+
};
235+
236+
exports.handler = function(event, context, callback) {
237+
console.log("Lambda function event:", event);
238+
console.log("Lambda function context:", context);
239+
if (event.httpMethod === "OPTIONS") { // this is (probably) a CORS preflight request
240+
callback(null, {
241+
statusCode: 200,
242+
headers: CORS_HEADERS,
243+
});
244+
} else { // this is a regular request
245+
callback(null, {
246+
statusCode: 200,
247+
headers: {
248+
...CORS_HEADERS,
249+
"Content-Type": "application/json"
250+
},
251+
body: JSON.stringify({ Hello: "World!" }),
252+
});
253+
}
254+
};
255+
```
256+
253257
<!-- terraform-docs:begin -->
254258
## Inputs
255259

aws_lambda_api/api_gateway.tf

Lines changed: 0 additions & 155 deletions
This file was deleted.

aws_lambda_api/api_gateway_config.tf

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
resource "aws_api_gateway_rest_api" "this" {
2+
name = "${local.prefix_with_domain}"
3+
description = "${var.comment_prefix}${var.api_domain}"
4+
}
5+
6+
resource "aws_api_gateway_deployment" "this" {
7+
rest_api_id = "${aws_api_gateway_rest_api.this.id}"
8+
9+
depends_on = [
10+
"aws_api_gateway_integration.proxy_root",
11+
"aws_api_gateway_integration.proxy_other",
12+
]
13+
}
14+
15+
resource "aws_api_gateway_stage" "this" {
16+
stage_name = "${var.stage_name}"
17+
description = "${var.comment_prefix}${var.api_domain}"
18+
rest_api_id = "${aws_api_gateway_rest_api.this.id}"
19+
deployment_id = "${aws_api_gateway_deployment.this.id}"
20+
tags = "${var.tags}"
21+
}
22+
23+
resource "aws_api_gateway_method_settings" "this" {
24+
rest_api_id = "${aws_api_gateway_rest_api.this.id}"
25+
stage_name = "${aws_api_gateway_stage.this.stage_name}"
26+
method_path = "*/*"
27+
28+
settings {
29+
metrics_enabled = "${var.api_gateway_cloudwatch_metrics}"
30+
logging_level = "${var.api_gateway_logging_level}"
31+
data_trace_enabled = "${var.api_gateway_logging_level == "OFF" ? false : true}"
32+
throttling_rate_limit = "${var.throttling_rate_limit}"
33+
throttling_burst_limit = "${var.throttling_burst_limit}"
34+
}
35+
}
36+
37+
resource "aws_api_gateway_domain_name" "this" {
38+
domain_name = "${var.api_domain}"
39+
regional_certificate_arn = "${aws_acm_certificate_validation.this.certificate_arn}"
40+
41+
endpoint_configuration {
42+
types = ["REGIONAL"]
43+
}
44+
}
45+
46+
resource "aws_api_gateway_base_path_mapping" "this" {
47+
api_id = "${aws_api_gateway_rest_api.this.id}"
48+
stage_name = "${aws_api_gateway_stage.this.stage_name}"
49+
domain_name = "${aws_api_gateway_domain_name.this.domain_name}"
50+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Add root resource to the API (it it needs to be included separately from the "proxy" resource defined below), which forwards to our Lambda:
2+
3+
resource "aws_api_gateway_method" "proxy_root" {
4+
rest_api_id = "${aws_api_gateway_rest_api.this.id}"
5+
resource_id = "${aws_api_gateway_rest_api.this.root_resource_id}"
6+
http_method = "ANY"
7+
authorization = "NONE"
8+
}
9+
10+
resource "aws_api_gateway_integration" "proxy_root" {
11+
rest_api_id = "${aws_api_gateway_rest_api.this.id}"
12+
resource_id = "${aws_api_gateway_method.proxy_root.resource_id}"
13+
http_method = "${aws_api_gateway_method.proxy_root.http_method}"
14+
integration_http_method = "POST"
15+
type = "AWS_PROXY"
16+
uri = "${local.function_invoke_arn}"
17+
}
18+
19+
# Add a "proxy" resource, that matches all paths (except the root, defined above) and forwards them to our Lambda:
20+
21+
resource "aws_api_gateway_resource" "proxy_other" {
22+
rest_api_id = "${aws_api_gateway_rest_api.this.id}"
23+
parent_id = "${aws_api_gateway_rest_api.this.root_resource_id}"
24+
path_part = "{proxy+}"
25+
}
26+
27+
resource "aws_api_gateway_method" "proxy_other" {
28+
rest_api_id = "${aws_api_gateway_rest_api.this.id}"
29+
resource_id = "${aws_api_gateway_resource.proxy_other.id}"
30+
http_method = "ANY"
31+
authorization = "NONE"
32+
}
33+
34+
resource "aws_api_gateway_integration" "proxy_other" {
35+
rest_api_id = "${aws_api_gateway_rest_api.this.id}"
36+
resource_id = "${aws_api_gateway_method.proxy_other.resource_id}"
37+
http_method = "${aws_api_gateway_method.proxy_other.http_method}"
38+
integration_http_method = "POST"
39+
type = "AWS_PROXY"
40+
uri = "${local.function_invoke_arn}"
41+
}
42+
43+
resource "aws_api_gateway_method_response" "proxy_other" {
44+
rest_api_id = "${aws_api_gateway_rest_api.this.id}"
45+
resource_id = "${aws_api_gateway_resource.proxy_other.id}"
46+
http_method = "${aws_api_gateway_method.proxy_other.http_method}"
47+
status_code = "200"
48+
49+
response_models = {
50+
"application/json" = "Empty"
51+
}
52+
}
53+
54+
resource "aws_api_gateway_integration_response" "proxy_other" {
55+
depends_on = ["aws_api_gateway_integration.proxy_other"]
56+
rest_api_id = "${aws_api_gateway_rest_api.this.id}"
57+
resource_id = "${aws_api_gateway_resource.proxy_other.id}"
58+
http_method = "${aws_api_gateway_method.proxy_other.http_method}"
59+
status_code = "${aws_api_gateway_method_response.proxy_other.status_code}"
60+
61+
response_templates = {
62+
"application/json" = ""
63+
}
64+
}

0 commit comments

Comments
 (0)