Skip to content

Commit 4879911

Browse files
feat: API & Domain Association (#27)
Co-authored-by: Anton Babenko <[email protected]>
1 parent 4e9038d commit 4879911

File tree

8 files changed

+168
-5
lines changed

8 files changed

+168
-5
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/antonbabenko/pre-commit-terraform
3-
rev: v1.62.3
3+
rev: v1.64.0
44
hooks:
55
- id: terraform_fmt
66
- id: terraform_validate

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ No modules.
132132
| [aws_appsync_api_cache.example](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appsync_api_cache) | resource |
133133
| [aws_appsync_api_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appsync_api_key) | resource |
134134
| [aws_appsync_datasource.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appsync_datasource) | resource |
135+
| [aws_appsync_domain_name.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appsync_domain_name) | resource |
136+
| [aws_appsync_domain_name_api_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appsync_domain_name_api_association) | resource |
135137
| [aws_appsync_function.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appsync_function) | resource |
136138
| [aws_appsync_graphql_api.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appsync_graphql_api) | resource |
137139
| [aws_appsync_resolver.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appsync_resolver) | resource |
@@ -156,11 +158,15 @@ No modules.
156158
| <a name="input_cache_type"></a> [cache\_type](#input\_cache\_type) | The cache instance type. | `string` | `"SMALL"` | no |
157159
| <a name="input_caching_behavior"></a> [caching\_behavior](#input\_caching\_behavior) | Caching behavior. | `string` | `"FULL_REQUEST_CACHING"` | no |
158160
| <a name="input_caching_enabled"></a> [caching\_enabled](#input\_caching\_enabled) | Whether caching with Elasticache is enabled. | `bool` | `false` | no |
161+
| <a name="input_certificate_arn"></a> [certificate\_arn](#input\_certificate\_arn) | The Amazon Resource Name (ARN) of the certificate. | `string` | `""` | no |
159162
| <a name="input_create_graphql_api"></a> [create\_graphql\_api](#input\_create\_graphql\_api) | Whether to create GraphQL API | `bool` | `true` | no |
160163
| <a name="input_create_logs_role"></a> [create\_logs\_role](#input\_create\_logs\_role) | Whether to create service role for Cloudwatch logs | `bool` | `true` | no |
161164
| <a name="input_datasources"></a> [datasources](#input\_datasources) | Map of datasources to create | `any` | `{}` | no |
162165
| <a name="input_direct_lambda_request_template"></a> [direct\_lambda\_request\_template](#input\_direct\_lambda\_request\_template) | VTL request template for the direct lambda integrations | `string` | `"{\n \"version\" : \"2017-02-28\",\n \"operation\": \"Invoke\",\n \"payload\": {\n \"arguments\": $util.toJson($ctx.arguments),\n \"identity\": $util.toJson($ctx.identity),\n \"source\": $util.toJson($ctx.source),\n \"request\": $util.toJson($ctx.request),\n \"prev\": $util.toJson($ctx.prev),\n \"info\": {\n \"selectionSetList\": $util.toJson($ctx.info.selectionSetList),\n \"selectionSetGraphQL\": $util.toJson($ctx.info.selectionSetGraphQL),\n \"parentTypeName\": $util.toJson($ctx.info.parentTypeName),\n \"fieldName\": $util.toJson($ctx.info.fieldName),\n \"variables\": $util.toJson($ctx.info.variables)\n },\n \"stash\": $util.toJson($ctx.stash)\n }\n}\n"` | no |
163166
| <a name="input_direct_lambda_response_template"></a> [direct\_lambda\_response\_template](#input\_direct\_lambda\_response\_template) | VTL response template for the direct lambda integrations | `string` | `"$util.toJson($ctx.result)\n"` | no |
167+
| <a name="input_domain_name"></a> [domain\_name](#input\_domain\_name) | The domain name that AppSync gets associated with. | `string` | `""` | no |
168+
| <a name="input_domain_name_association_enabled"></a> [domain\_name\_association\_enabled](#input\_domain\_name\_association\_enabled) | Whether to enable domain name association on GraphQL API | `bool` | `false` | no |
169+
| <a name="input_domain_name_description"></a> [domain\_name\_description](#input\_domain\_name\_description) | A description of the Domain Name. | `string` | `null` | no |
164170
| <a name="input_dynamodb_allowed_actions"></a> [dynamodb\_allowed\_actions](#input\_dynamodb\_allowed\_actions) | List of allowed IAM actions for datasources type AMAZON\_DYNAMODB | `list(string)` | <pre>[<br> "dynamodb:GetItem",<br> "dynamodb:PutItem",<br> "dynamodb:DeleteItem",<br> "dynamodb:UpdateItem",<br> "dynamodb:Query",<br> "dynamodb:Scan",<br> "dynamodb:BatchGetItem",<br> "dynamodb:BatchWriteItem"<br>]</pre> | no |
165171
| <a name="input_elasticsearch_allowed_actions"></a> [elasticsearch\_allowed\_actions](#input\_elasticsearch\_allowed\_actions) | List of allowed IAM actions for datasources type AMAZON\_ELASTICSEARCH | `list(string)` | <pre>[<br> "es:ESHttpDelete",<br> "es:ESHttpHead",<br> "es:ESHttpGet",<br> "es:ESHttpPost",<br> "es:ESHttpPut"<br>]</pre> | no |
166172
| <a name="input_functions"></a> [functions](#input\_functions) | Map of functions to create | `any` | `{}` | no |
@@ -190,6 +196,9 @@ No modules.
190196
| <a name="output_appsync_api_key_id"></a> [appsync\_api\_key\_id](#output\_appsync\_api\_key\_id) | Map of API Key ID (Formatted as ApiId:Key) |
191197
| <a name="output_appsync_api_key_key"></a> [appsync\_api\_key\_key](#output\_appsync\_api\_key\_key) | Map of API Keys |
192198
| <a name="output_appsync_datasource_arn"></a> [appsync\_datasource\_arn](#output\_appsync\_datasource\_arn) | Map of ARNs of datasources |
199+
| <a name="output_appsync_domain_hosted_zone_id"></a> [appsync\_domain\_hosted\_zone\_id](#output\_appsync\_domain\_hosted\_zone\_id) | The ID of your Amazon Route 53 hosted zone. |
200+
| <a name="output_appsync_domain_id"></a> [appsync\_domain\_id](#output\_appsync\_domain\_id) | The Appsync Domain Name. |
201+
| <a name="output_appsync_domain_name"></a> [appsync\_domain\_name](#output\_appsync\_domain\_name) | The domain name that AppSync provides. |
193202
| <a name="output_appsync_function_arn"></a> [appsync\_function\_arn](#output\_appsync\_function\_arn) | Map of ARNs of functions |
194203
| <a name="output_appsync_function_function_id"></a> [appsync\_function\_function\_id](#output\_appsync\_function\_function\_id) | Map of function IDs of functions |
195204
| <a name="output_appsync_function_id"></a> [appsync\_function\_id](#output\_appsync\_function\_id) | Map of IDs of functions |

examples/complete/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Note that this example may create resources which cost money. Run `terraform des
3535

3636
| Name | Source | Version |
3737
|------|--------|---------|
38+
| <a name="module_acm"></a> [acm](#module\_acm) | terraform-aws-modules/acm/aws | ~> 3 |
3839
| <a name="module_appsync"></a> [appsync](#module\_appsync) | ../../ | n/a |
3940
| <a name="module_disabled"></a> [disabled](#module\_disabled) | ../../ | n/a |
4041

@@ -43,7 +44,10 @@ Note that this example may create resources which cost money. Run `terraform des
4344
| Name | Type |
4445
|------|------|
4546
| [aws_cognito_user_pool.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_user_pool) | resource |
47+
| [aws_route53_record.api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |
48+
| [aws_route53_zone.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone) | resource |
4649
| [random_pet.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/pet) | resource |
50+
| [aws_route53_zone.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |
4751

4852
## Inputs
4953

@@ -56,6 +60,9 @@ No inputs.
5660
| <a name="output_appsync_api_key_id"></a> [appsync\_api\_key\_id](#output\_appsync\_api\_key\_id) | Map of API Key ID (Formatted as ApiId:Key) |
5761
| <a name="output_appsync_api_key_key"></a> [appsync\_api\_key\_key](#output\_appsync\_api\_key\_key) | Map of API Keys |
5862
| <a name="output_appsync_datasource_arn"></a> [appsync\_datasource\_arn](#output\_appsync\_datasource\_arn) | Map of ARNs of datasources |
63+
| <a name="output_appsync_domain_hosted_zone_id"></a> [appsync\_domain\_hosted\_zone\_id](#output\_appsync\_domain\_hosted\_zone\_id) | The ID of your Amazon Route 53 hosted zone |
64+
| <a name="output_appsync_domain_id"></a> [appsync\_domain\_id](#output\_appsync\_domain\_id) | The Appsync Domain name |
65+
| <a name="output_appsync_domain_name"></a> [appsync\_domain\_name](#output\_appsync\_domain\_name) | The domain name AppSync provides |
5966
| <a name="output_appsync_graphql_api_arn"></a> [appsync\_graphql\_api\_arn](#output\_appsync\_graphql\_api\_arn) | ARN of GraphQL API |
6067
| <a name="output_appsync_graphql_api_fqdns"></a> [appsync\_graphql\_api\_fqdns](#output\_appsync\_graphql\_api\_fqdns) | Map of FQDNs associated with the API (no protocol and path) |
6168
| <a name="output_appsync_graphql_api_id"></a> [appsync\_graphql\_api\_id](#output\_appsync\_graphql\_api\_id) | ID of GraphQL API |

examples/complete/main.tf

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,88 @@ provider "aws" {
1111
skip_requesting_account_id = false
1212
}
1313

14+
provider "aws" {
15+
region = "us-east-1"
16+
alias = "us-east-1"
17+
18+
# Make it faster by skipping something
19+
skip_get_ec2_platforms = true
20+
skip_metadata_api_check = true
21+
skip_region_validation = true
22+
skip_credentials_validation = true
23+
24+
# skip_requesting_account_id should be disabled to generate valid ARN in apigatewayv2_api_execution_arn
25+
skip_requesting_account_id = false
26+
}
27+
28+
locals {
29+
# Use existing (via data source) or create new zone (will fail validation, if zone is not reachable)
30+
use_existing_route53_zone = true
31+
32+
domain = "terraform-aws-modules.modules.tf"
33+
34+
# Removing trailing dot from domain - just to be sure :)
35+
domain_name = trimsuffix(local.domain, ".")
36+
}
37+
38+
data "aws_route53_zone" "this" {
39+
count = local.use_existing_route53_zone ? 1 : 0
40+
41+
name = local.domain_name
42+
private_zone = false
43+
}
44+
45+
resource "aws_route53_zone" "this" {
46+
count = !local.use_existing_route53_zone ? 1 : 0
47+
name = local.domain_name
48+
}
49+
50+
resource "aws_route53_record" "api" {
51+
zone_id = data.aws_route53_zone.this[0].zone_id
52+
name = "api.${local.domain}"
53+
type = "CNAME"
54+
ttl = "300"
55+
records = [module.appsync.appsync_domain_name]
56+
}
57+
58+
module "acm" {
59+
source = "terraform-aws-modules/acm/aws"
60+
version = "~> 3"
61+
62+
domain_name = local.domain_name
63+
zone_id = coalescelist(data.aws_route53_zone.this.*.zone_id, aws_route53_zone.this.*.zone_id)[0]
64+
65+
subject_alternative_names = [
66+
"*.alerts.${local.domain_name}",
67+
"new.sub.${local.domain_name}",
68+
"*.${local.domain_name}",
69+
"alerts.${local.domain_name}",
70+
]
71+
72+
wait_for_validation = true
73+
74+
tags = {
75+
Name = local.domain_name
76+
}
77+
78+
providers = {
79+
aws = aws.us-east-1
80+
}
81+
}
82+
1483
module "appsync" {
1584
source = "../../"
1685

1786
name = random_pet.this.id
1887

1988
schema = file("schema.graphql")
2089

21-
caching_enabled = true
90+
domain_name_association_enabled = true
91+
caching_enabled = true
92+
93+
domain_name = "api.${local.domain}"
94+
domain_name_description = "My ${random_pet.this.id} AppSync Domain"
95+
certificate_arn = module.acm.acm_certificate_arn
2296

2397
caching_behavior = "PER_RESOLVER_CACHING"
2498
cache_type = "SMALL"

examples/complete/outputs.tf

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,22 @@ output "appsync_graphql_api_uris" {
1414
value = module.appsync.appsync_graphql_api_uris
1515
}
1616

17+
#Domain
18+
output "appsync_domain_id" {
19+
description = "The Appsync Domain name"
20+
value = module.appsync.appsync_domain_id
21+
}
22+
23+
output "appsync_domain_name" {
24+
description = "The domain name AppSync provides"
25+
value = module.appsync.appsync_domain_name
26+
}
27+
28+
output "appsync_domain_hosted_zone_id" {
29+
description = "The ID of your Amazon Route 53 hosted zone"
30+
value = module.appsync.appsync_domain_hosted_zone_id
31+
}
32+
1733
# API Key
1834
output "appsync_api_key_id" {
1935
description = "Map of API Key ID (Formatted as ApiId:Key)"

main.tf

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,22 @@ resource "aws_appsync_graphql_api" "this" {
8888
tags = merge({ Name = var.name }, var.graphql_api_tags)
8989
}
9090

91+
# API Association & Domain Name
92+
resource "aws_appsync_domain_name" "this" {
93+
count = var.create_graphql_api && var.domain_name_association_enabled ? 1 : 0
94+
95+
domain_name = var.domain_name
96+
description = var.domain_name_description
97+
certificate_arn = var.certificate_arn
98+
}
99+
100+
resource "aws_appsync_domain_name_api_association" "this" {
101+
count = var.create_graphql_api && var.domain_name_association_enabled ? 1 : 0
102+
103+
api_id = aws_appsync_graphql_api.this[0].id
104+
domain_name = aws_appsync_domain_name.this[0].domain_name
105+
}
106+
91107
# API Cache
92108
resource "aws_appsync_api_cache" "example" {
93109
count = var.create_graphql_api && var.caching_enabled ? 1 : 0

outputs.tf

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
# GraphQL API
22
output "appsync_graphql_api_id" {
33
description = "ID of GraphQL API"
4-
value = element(concat(aws_appsync_graphql_api.this.*.id, [""]), 0)
4+
value = try(aws_appsync_graphql_api.this[0].id, null)
55
}
66

77
output "appsync_graphql_api_arn" {
88
description = "ARN of GraphQL API"
9-
value = element(concat(aws_appsync_graphql_api.this.*.arn, [""]), 0)
9+
value = try(aws_appsync_graphql_api.this[0].arn, null)
1010
}
1111

1212
output "appsync_graphql_api_uris" {
1313
description = "Map of URIs associated with the API"
14-
value = element(concat(aws_appsync_graphql_api.this.*.uris, [""]), 0)
14+
value = try(aws_appsync_graphql_api.this.*.uris, null)
1515
}
1616

1717
# API Key
@@ -53,6 +53,22 @@ output "appsync_function_function_id" {
5353
value = { for k, v in aws_appsync_function.this : k => v.function_id }
5454
}
5555

56+
# Domain
57+
output "appsync_domain_id" {
58+
description = "The Appsync Domain Name."
59+
value = try(aws_appsync_domain_name.this[0].id, null)
60+
}
61+
62+
output "appsync_domain_name" {
63+
description = "The domain name that AppSync provides."
64+
value = try(aws_appsync_domain_name.this[0].appsync_domain_name, null)
65+
}
66+
67+
output "appsync_domain_hosted_zone_id" {
68+
description = "The ID of your Amazon Route 53 hosted zone."
69+
value = try(aws_appsync_domain_name.this[0].hosted_zone_id, null)
70+
}
71+
5672
# Extra
5773
output "appsync_graphql_api_fqdns" {
5874
description = "Map of FQDNs associated with the API (no protocol and path)"

variables.tf

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ variable "logging_enabled" {
1010
default = false
1111
}
1212

13+
variable "domain_name_association_enabled" {
14+
description = "Whether to enable domain name association on GraphQL API"
15+
type = bool
16+
default = false
17+
}
1318
variable "caching_enabled" {
1419
description = "Whether caching with Elasticache is enabled."
1520
type = bool
@@ -112,6 +117,25 @@ variable "tags" {
112117
default = {}
113118
}
114119

120+
# API Association & Domain Name
121+
variable "domain_name" {
122+
description = "The domain name that AppSync gets associated with."
123+
type = string
124+
default = ""
125+
}
126+
127+
variable "domain_name_description" {
128+
description = "A description of the Domain Name."
129+
type = string
130+
default = null
131+
}
132+
133+
variable "certificate_arn" {
134+
description = "The Amazon Resource Name (ARN) of the certificate."
135+
type = string
136+
default = ""
137+
}
138+
115139
# API Cache
116140
variable "caching_behavior" {
117141
description = "Caching behavior."
@@ -179,6 +203,7 @@ variable "api_keys" {
179203
default = {}
180204
}
181205

206+
182207
# IAM service roles
183208
variable "lambda_allowed_actions" {
184209
description = "List of allowed IAM actions for datasources type AWS_LAMBDA"

0 commit comments

Comments
 (0)