@aws/nx-plugin-mcp 1.0.0-rc.9 → 1.0.0-rc.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/bin/aws-nx-mcp.js +13439 -11631
  2. package/docs/get_started/building-with-ai.mdx +116 -0
  3. package/docs/get_started/concepts.mdx +67 -0
  4. package/docs/get_started/existing-project.mdx +180 -0
  5. package/docs/get_started/graph-builder.mdx +39 -0
  6. package/docs/get_started/quick-start.mdx +277 -0
  7. package/docs/get_started/tutorials/contribute-generator.mdx +408 -0
  8. package/docs/get_started/tutorials/dungeon-game/1.mdx +1578 -0
  9. package/docs/get_started/tutorials/dungeon-game/2.mdx +245 -0
  10. package/docs/get_started/tutorials/dungeon-game/3.mdx +66 -0
  11. package/docs/get_started/tutorials/dungeon-game/4.mdx +164 -0
  12. package/docs/get_started/tutorials/dungeon-game/overview.mdx +145 -0
  13. package/docs/get_started/tutorials/dungeon-game/wrap-up.mdx +41 -0
  14. package/docs/get_started/upgrading.mdx +157 -0
  15. package/docs/guides/agentcore-gateway.mdx +490 -0
  16. package/docs/guides/agentcore-harness.mdx +312 -0
  17. package/docs/guides/astro-docs.mdx +8 -0
  18. package/docs/guides/connection/agentcore-gateway-agent.mdx +222 -0
  19. package/docs/guides/connection/agentcore-gateway-gateway.mdx +154 -0
  20. package/docs/guides/connection/agentcore-gateway-mcp.mdx +134 -0
  21. package/docs/guides/connection/py-agent-a2a.mdx +48 -16
  22. package/docs/guides/connection/py-agent-dynamodb.mdx +115 -0
  23. package/docs/guides/connection/py-agent-gateway.mdx +182 -0
  24. package/docs/guides/connection/py-agent-mcp.mdx +43 -14
  25. package/docs/guides/connection/py-agent-rdb.mdx +169 -0
  26. package/docs/guides/connection/py-fast-api-dynamodb.mdx +56 -0
  27. package/docs/guides/connection/py-fast-api-rdb.mdx +175 -0
  28. package/docs/guides/connection/py-mcp-server-dynamodb.mdx +115 -0
  29. package/docs/guides/connection/py-mcp-server-rdb.mdx +178 -0
  30. package/docs/guides/connection/react-agentcore-gateway.mdx +112 -0
  31. package/docs/guides/connection/react-agui.mdx +33 -14
  32. package/docs/guides/connection/react-fastapi.mdx +39 -3
  33. package/docs/guides/connection/react-py-agent.mdx +10 -16
  34. package/docs/guides/connection/react-smithy.mdx +4 -4
  35. package/docs/guides/connection/react-trpc.mdx +1 -1
  36. package/docs/guides/connection/react-ts-agent.mdx +9 -9
  37. package/docs/guides/connection/smithy-dynamodb.mdx +5 -5
  38. package/docs/guides/connection/smithy-rdb.mdx +9 -9
  39. package/docs/guides/connection/trpc-dynamodb.mdx +4 -4
  40. package/docs/guides/connection/trpc-rdb.mdx +5 -5
  41. package/docs/guides/connection/ts-agent-a2a.mdx +14 -11
  42. package/docs/guides/connection/ts-agent-dynamodb.mdx +35 -36
  43. package/docs/guides/connection/ts-agent-gateway.mdx +147 -0
  44. package/docs/guides/connection/ts-agent-mcp.mdx +12 -9
  45. package/docs/guides/connection/ts-agent-rdb.mdx +61 -25
  46. package/docs/guides/connection/ts-mcp-server-dynamodb.mdx +35 -36
  47. package/docs/guides/connection/ts-mcp-server-rdb.mdx +59 -18
  48. package/docs/guides/connection.mdx +122 -5
  49. package/docs/guides/docker-bundling.mdx +82 -14
  50. package/docs/guides/fastapi.mdx +253 -12
  51. package/docs/guides/local-development.mdx +87 -0
  52. package/docs/guides/nx-generator.mdx +4 -3
  53. package/docs/guides/nx-migration.mdx +165 -0
  54. package/docs/guides/py-agent.mdx +332 -55
  55. package/docs/guides/py-dynamodb.mdx +476 -0
  56. package/docs/guides/py-mcp-server.mdx +57 -2
  57. package/docs/guides/py-rdb.mdx +269 -0
  58. package/docs/guides/python-lambda-function.mdx +1 -1
  59. package/docs/guides/python-project.mdx +31 -0
  60. package/docs/guides/react-website-auth.mdx +104 -5
  61. package/docs/guides/react-website.mdx +409 -95
  62. package/docs/guides/runtime-config.mdx +17 -4
  63. package/docs/guides/security.mdx +75 -0
  64. package/docs/guides/smithy-project.mdx +167 -0
  65. package/docs/guides/terraform-project.mdx +119 -8
  66. package/docs/guides/trpc.mdx +55 -14
  67. package/docs/guides/ts-agent.mdx +207 -23
  68. package/docs/guides/ts-dcr-proxy.mdx +569 -0
  69. package/docs/guides/ts-dynamodb.mdx +66 -242
  70. package/docs/guides/ts-lambda-function.mdx +1 -1
  71. package/docs/guides/ts-mcp-server.mdx +111 -29
  72. package/docs/guides/ts-nx-plugin.mdx +4 -4
  73. package/docs/guides/ts-rdb.mdx +116 -466
  74. package/docs/guides/ts-smithy-api.mdx +260 -16
  75. package/docs/guides/typescript-infrastructure.mdx +79 -25
  76. package/docs/guides/typescript-project.mdx +157 -24
  77. package/docs/guides/workspace.mdx +31 -2
  78. package/docs/snippets/agent/architecture.mdx +1 -1
  79. package/docs/snippets/agent/bedrock-deployment.mdx +9 -5
  80. package/docs/snippets/agent/runtime-arn.mdx +23 -2
  81. package/docs/snippets/agent/securing-your-agent.mdx +39 -0
  82. package/docs/snippets/api/access-logging.mdx +38 -0
  83. package/docs/snippets/api/cors-configuration-cdk-note.mdx +1 -1
  84. package/docs/snippets/api/cors-configuration-terraform-note.mdx +1 -1
  85. package/docs/snippets/api/type-safe-api-integrations.mdx +218 -373
  86. package/docs/snippets/api/waf-configuration.mdx +3 -3
  87. package/docs/snippets/connection/a2a-infrastructure.mdx +1 -1
  88. package/docs/snippets/connection/dynamodb-local-development.mdx +2 -2
  89. package/docs/snippets/connection/lambda-dynamodb-access.mdx +2 -2
  90. package/docs/snippets/connection/py-dynamodb-local-development.mdx +7 -0
  91. package/docs/snippets/connection/py-lambda-rdb-ssl-requirements.mdx +7 -0
  92. package/docs/snippets/connection/rdb-api-infrastructure.mdx +42 -19
  93. package/docs/snippets/dynamodb/deploying-table.mdx +176 -0
  94. package/docs/snippets/dynamodb/encryption-options.mdx +168 -0
  95. package/docs/snippets/dynamodb/gsi-config.mdx +38 -0
  96. package/docs/snippets/dynamodb/infrastructure.mdx +33 -0
  97. package/docs/snippets/dynamodb/local-dev-start.mdx +13 -0
  98. package/docs/snippets/dynamodb/local-dev-windows.mdx +15 -0
  99. package/docs/snippets/experimental-generator.mdx +8 -0
  100. package/docs/snippets/lambda-function/deploying-your-function.mdx +3 -3
  101. package/docs/snippets/mcp/architecture.mdx +1 -1
  102. package/docs/snippets/mcp/bedrock-deployment.mdx +9 -5
  103. package/docs/snippets/mcp/config.mdx +3 -2
  104. package/docs/snippets/mcp/shared-constructs.mdx +4 -5
  105. package/docs/snippets/pdk-migration/example/01-migrate-api.mdx +7 -5
  106. package/docs/snippets/pdk-migration/example/02-migrate-website.mdx +29 -10
  107. package/docs/snippets/pdk-migration/example/03-migrate-infra.mdx +4 -4
  108. package/docs/snippets/pdk-migration/faq/type-safe-api.mdx +5 -111
  109. package/docs/snippets/prerequisites.mdx +1 -4
  110. package/docs/snippets/rdb/admin-credentials.mdx +42 -0
  111. package/docs/snippets/rdb/architecture.mdx +39 -0
  112. package/docs/snippets/rdb/cluster-instances.mdx +31 -0
  113. package/docs/snippets/rdb/deletion-protection.mdx +64 -0
  114. package/docs/snippets/rdb/deploying.mdx +178 -0
  115. package/docs/snippets/rdb/encryption-key-rotation.mdx +30 -0
  116. package/docs/snippets/rdb/engine-version.mdx +63 -0
  117. package/docs/snippets/rdb/infrastructure.mdx +35 -0
  118. package/docs/snippets/rdb/logging-mysql.mdx +5 -0
  119. package/docs/snippets/rdb/logging-postgres.mdx +5 -0
  120. package/docs/snippets/rdb/performance-insights.mdx +36 -0
  121. package/docs/snippets/rdb/rds-proxy.mdx +50 -0
  122. package/docs/snippets/rdb/removal-policy.mdx +57 -0
  123. package/docs/snippets/rdb/serverless-capacity.mdx +32 -0
  124. package/docs/snippets/recommended-prerequisites.mdx +10 -0
  125. package/docs/snippets/required-prerequisites.mdx +1 -4
  126. package/docs/snippets/runtime-config-app-id-note.mdx +8 -0
  127. package/docs/snippets/shared-constructs.mdx +1 -1
  128. package/docs/snippets/trivy-image-scan.mdx +37 -0
  129. package/generators.json +170 -10
  130. package/package.json +1 -1
  131. package/src/agentcore-gateway/agent-connection/schema.json +31 -0
  132. package/src/agentcore-gateway/gateway-connection/schema.json +31 -0
  133. package/src/agentcore-gateway/mcp-connection/schema.json +31 -0
  134. package/src/agentcore-gateway/react-connection/schema.json +31 -0
  135. package/src/agentcore-gateway/schema.json +72 -0
  136. package/src/agentcore-harness/schema.json +53 -0
  137. package/src/connection/schema.json +5 -0
  138. package/src/infra/app/schema.json +5 -0
  139. package/src/init/schema.json +35 -0
  140. package/src/internal/test-matrix/schema.json +21 -0
  141. package/src/license/schema.json +5 -0
  142. package/src/open-api/json-metadata/schema.json +20 -0
  143. package/src/preset/schema.json +16 -5
  144. package/src/py/agent/a2a-connection/schema.json +5 -0
  145. package/src/py/agent/gateway-connection/schema.json +31 -0
  146. package/src/py/agent/mcp-connection/schema.json +5 -0
  147. package/src/py/agent/react-connection/schema.json +5 -0
  148. package/src/py/agent/schema.json +15 -1
  149. package/src/py/api/schema.json +5 -0
  150. package/src/py/dynamodb/agent-connection/schema.json +27 -0
  151. package/src/py/dynamodb/fast-api-connection/schema.json +23 -0
  152. package/src/py/dynamodb/mcp-server-connection/schema.json +27 -0
  153. package/src/py/dynamodb/schema.json +76 -0
  154. package/src/py/fast-api/react/schema.json +5 -0
  155. package/src/py/fast-api/schema.json +6 -0
  156. package/src/py/lambda-function/schema.json +6 -1
  157. package/src/py/mcp-server/schema.json +6 -0
  158. package/src/py/project/schema.json +6 -0
  159. package/src/py/rdb/agent-connection/schema.json +27 -0
  160. package/src/py/rdb/fast-api-connection/schema.json +23 -0
  161. package/src/py/rdb/mcp-server-connection/schema.json +27 -0
  162. package/src/py/rdb/schema.json +78 -0
  163. package/src/smithy/project/schema.json +28 -1
  164. package/src/smithy/react-connection/schema.json +5 -0
  165. package/src/smithy/ts/api/schema.json +6 -0
  166. package/src/terraform/project/schema.json +5 -0
  167. package/src/trpc/backend/schema.json +6 -0
  168. package/src/trpc/react/schema.json +5 -0
  169. package/src/ts/agent/a2a-connection/schema.json +5 -0
  170. package/src/ts/agent/gateway-connection/schema.json +31 -0
  171. package/src/ts/agent/mcp-connection/schema.json +5 -0
  172. package/src/ts/agent/react-connection/schema.json +5 -0
  173. package/src/ts/agent/schema.json +14 -0
  174. package/src/ts/api/schema.json +5 -0
  175. package/src/ts/astro-docs/schema.json +3 -3
  176. package/src/ts/dcr-proxy/schema.json +44 -0
  177. package/src/ts/docs/schema.json +3 -3
  178. package/src/ts/dynamodb/agent-connection/schema.json +5 -0
  179. package/src/ts/dynamodb/mcp-server-connection/schema.json +5 -0
  180. package/src/ts/dynamodb/schema.json +26 -2
  181. package/src/ts/dynamodb/smithy-connection/schema.json +5 -0
  182. package/src/ts/dynamodb/trpc-connection/schema.json +5 -0
  183. package/src/ts/lambda-function/schema.json +5 -0
  184. package/src/ts/lib/schema.json +5 -0
  185. package/src/ts/mcp-server/schema.json +6 -0
  186. package/src/ts/nx-generator/schema.json +5 -0
  187. package/src/ts/nx-migration/schema.json +63 -0
  188. package/src/ts/nx-plugin/schema.json +5 -0
  189. package/src/ts/rdb/agent-connection/schema.json +5 -0
  190. package/src/ts/rdb/mcp-server-connection/schema.json +5 -0
  191. package/src/ts/rdb/schema.json +7 -1
  192. package/src/ts/rdb/smithy-connection/schema.json +5 -0
  193. package/src/ts/rdb/trpc-connection/schema.json +5 -0
  194. package/src/ts/react-website/app/schema.json +12 -6
  195. package/src/ts/react-website/cognito-auth/schema.json +5 -0
  196. package/src/ts/react-website/runtime-config/schema.json +5 -0
  197. package/src/ts/website/app/schema.json +11 -6
  198. package/src/ts/website/auth/schema.json +5 -0
  199. /package/docs/snippets/connection/{lambda-rdb-ssl-requirements.mdx → ts-lambda-rdb-ssl-requirements.mdx} +0 -0
  200. /package/docs/snippets/connection/{mcp-server-rdb-ssl-requirements.mdx → ts-mcp-server-rdb-ssl-requirements.mdx} +0 -0
@@ -1,24 +1,14 @@
1
1
  ---
2
2
  title: Type-Safe API Integrations
3
3
  ---
4
- import { Tabs, TabItem } from '@astrojs/starlight/components';
4
+ import { Steps } from '@astrojs/starlight/components';
5
5
  import Infrastructure from '@components/infrastructure.astro';
6
+ import Drawer from '@components/drawer.astro';
7
+ import OptionFilter from '@components/option-filter.astro';
8
+ import RunGenerator from '@components/run-generator.astro';
6
9
 
7
10
  The REST/HTTP API CDK constructs are configured to provide a type-safe interface for defining integrations for each of your operations.
8
11
 
9
- <Infrastructure>
10
- <Fragment slot="cdk">
11
- The CDK constructs provide full type-safe integration support as described below.
12
- </Fragment>
13
- <Fragment slot="terraform">
14
- :::note[Router Pattern]
15
- Terraform modules use the "router pattern" with a single Lambda function serving all operations. Type-safe integrations are not supported - the module creates one Lambda function that handles all API requests.
16
-
17
- For explicit per-operation integrations with Terraform, you would need to manually create individual Lambda functions and API Gateway routes. See the [Explicit Integrations](#explicit-integrations) section for examples.
18
- :::
19
- </Fragment>
20
- </Infrastructure>
21
-
22
12
  #### Default Integrations
23
13
 
24
14
  <Infrastructure>
@@ -32,7 +22,7 @@ new MyApi(this, 'MyApi', {
32
22
  ```
33
23
  </Fragment>
34
24
  <Fragment slot="terraform">
35
- Terraform modules automatically use the router pattern with a single Lambda function. No additional configuration is needed:
25
+ The generated module already defines the default integrations for the pattern the API was generated with, so no additional configuration is needed:
36
26
 
37
27
  ```hcl
38
28
  module "my_api" {
@@ -40,11 +30,11 @@ module "my_api" {
40
30
 
41
31
  asset_bucket_name = module.asset_bucket.bucket_name
42
32
 
43
- # The module automatically creates a single Lambda function
44
- # that handles all API operations
45
33
  tags = local.common_tags
46
34
  }
47
35
  ```
36
+
37
+ With the default `isolated` pattern, this creates one Lambda function per operation.
48
38
  </Fragment>
49
39
  </Infrastructure>
50
40
 
@@ -69,7 +59,7 @@ api.integrations.sayHello.handler.addToRolePolicy(new PolicyStatement({
69
59
 
70
60
  If your API uses the `shared` pattern, the shared router Lambda is exposed as `api.integrations.$router`:
71
61
 
72
- ```ts {6}
62
+ ```ts {5}
73
63
  const api = new MyApi(this, 'MyApi', {
74
64
  integrations: MyApi.defaultIntegrations(this).build(),
75
65
  });
@@ -78,13 +68,13 @@ api.integrations.$router.handler.addEnvironment('LOG_LEVEL', 'DEBUG');
78
68
  ```
79
69
  </Fragment>
80
70
  <Fragment slot="terraform">
81
- With Terraform's router pattern, there's only one Lambda function. You can access it via the module outputs:
71
+ With the `isolated` pattern, the module's outputs are maps keyed by operation name, so you can reach a single operation's resources. For example, to grant one operation's Lambda function extra permissions:
82
72
 
83
73
  ```hcl
84
- # Grant additional permissions to the single Lambda function
85
- resource "aws_iam_role_policy" "additional_permissions" {
86
- name = "additional-api-permissions"
87
- role = module.my_api.lambda_execution_role_name
74
+ # Grant additional permissions to just the sayHello operation's function
75
+ resource "aws_iam_role_policy" "say_hello_permissions" {
76
+ name = "say-hello-additional-permissions"
77
+ role = module.my_api.lambda_execution_role_names["sayHello"]
88
78
 
89
79
  policy = jsonencode({
90
80
  Version = "2012-10-17"
@@ -101,6 +91,48 @@ resource "aws_iam_role_policy" "additional_permissions" {
101
91
  })
102
92
  }
103
93
  ```
94
+
95
+ To grant the same permissions to every operation, iterate the `operations` output:
96
+
97
+ ```hcl
98
+ resource "aws_iam_role_policy" "additional_permissions" {
99
+ for_each = toset(module.my_api.operations)
100
+
101
+ name = "additional-api-permissions"
102
+ role = module.my_api.lambda_execution_role_names[each.key]
103
+
104
+ policy = jsonencode({
105
+ Version = "2012-10-17"
106
+ Statement = [
107
+ {
108
+ Effect = "Allow"
109
+ Action = ["s3:GetObject"]
110
+ Resource = "arn:aws:s3:::my-bucket/*"
111
+ }
112
+ ]
113
+ })
114
+ }
115
+ ```
116
+
117
+ The module also exposes `lambda_function_names`, `lambda_function_arns`, `lambda_invoke_arns`, `integration_ids` and `lambda_log_group_names` as maps keyed by operation name. With the `shared` pattern the equivalent singular outputs (`lambda_execution_role_name`, `lambda_function_name`, …) are exposed instead, since there is only one function.
118
+
119
+ Permissions every operation needs are better passed to the module, which applies them to each function's role:
120
+
121
+ ```hcl
122
+ module "my_api" {
123
+ source = "../../common/terraform/src/app/apis/my-api"
124
+
125
+ asset_bucket_name = module.asset_bucket.bucket_name
126
+
127
+ additional_iam_policy_statements = [
128
+ {
129
+ Effect = "Allow"
130
+ Action = ["s3:GetObject"]
131
+ Resource = ["arn:aws:s3:::my-bucket/*"]
132
+ }
133
+ ]
134
+ }
135
+ ```
104
136
  </Fragment>
105
137
  </Infrastructure>
106
138
 
@@ -125,48 +157,67 @@ new MyApi(this, 'MyApi', {
125
157
 
126
158
  </Fragment>
127
159
  <Fragment slot="terraform">
128
- To customize options like VPC configuration, you need to edit the generated Terraform module. For example, to add VPC support to all Lambda functions:
160
+ VPC configuration is already supported by the generated module — set `enable_vpc` along with `vpc_id` and `subnet_ids`, and the module deploys every Lambda function into your VPC behind a shared security group it creates for you:
129
161
 
130
162
  ```hcl
131
- # packages/common/terraform/src/app/apis/my-api/my-api.tf
132
- # Add VPC variables
133
- variable "vpc_subnet_ids" {
134
- description = "List of VPC subnet IDs for Lambda function"
135
- type = list(string)
136
- default = []
137
- }
163
+ module "my_api" {
164
+ source = "../../common/terraform/src/app/apis/my-api"
138
165
 
139
- variable "vpc_security_group_ids" {
140
- description = "List of VPC security group IDs for Lambda function"
141
- type = list(string)
142
- default = []
143
- }
166
+ asset_bucket_name = module.asset_bucket.bucket_name
144
167
 
145
- # Update the Lambda function resource
146
- resource "aws_lambda_function" "api_lambda" {
147
- # ... existing configuration ...
168
+ # VPC configuration
169
+ enable_vpc = true
170
+ vpc_id = aws_vpc.main.id
171
+ subnet_ids = [aws_subnet.private_a.id, aws_subnet.private_b.id]
148
172
 
149
- # Add VPC configuration
150
- vpc_config {
151
- subnet_ids = var.vpc_subnet_ids
152
- security_group_ids = var.vpc_security_group_ids
153
- }
173
+ tags = local.common_tags
154
174
  }
155
175
  ```
156
176
 
157
- Then use the module with VPC configuration:
177
+ For options the module does not expose, edit the `aws_lambda_function` resource in the generated Terraform module directly. With the `isolated` pattern that single resource is declared `for_each = local.operations`, so an edit there applies to every operation.
178
+ </Fragment>
179
+ </Infrastructure>
158
180
 
159
- ```hcl
160
- module "my_api" {
161
- source = "../../common/terraform/src/app/apis/my-api"
181
+ #### Customising Options Per-Operation
162
182
 
163
- asset_bucket_name = module.asset_bucket.bucket_name
183
+ <Infrastructure>
184
+ <Fragment slot="cdk">
185
+ To customise the options used to create the default integration for _specific_ operations (without affecting the others), you can use the `withOperationOptions` method. For example, if you would like to increase the Lambda function timeout for just one operation:
164
186
 
165
- # VPC configuration
166
- vpc_subnet_ids = [aws_subnet.private_a.id, aws_subnet.private_b.id]
167
- vpc_security_group_ids = [aws_security_group.lambda_sg.id]
187
+ ```ts {4-6}
188
+ const api = new MyApi(this, 'MyApi', {
189
+ integrations: MyApi.defaultIntegrations(this)
190
+ .withOperationOptions({
191
+ sayHello: {
192
+ timeout: Duration.seconds(60),
193
+ },
194
+ })
195
+ .build(),
196
+ });
168
197
 
169
- tags = local.common_tags
198
+ // The selected operations remain default integrations, so they're still typed accordingly:
199
+ api.integrations.sayHello.handler.addToRolePolicy(new PolicyStatement({ ... }));
200
+ ```
201
+
202
+ The options you specify are merged with the default integration options (and any options set via `withDefaultOptions`). Note that you cannot specify options for operations which you have replaced via `withOverrides`, since these no longer use the default integration.
203
+
204
+ You will encounter a type error if the same operation is targeted by both `withOperationOptions` and `withOverrides`, regardless of the order in which you call them.
205
+
206
+ </Fragment>
207
+ <Fragment slot="terraform">
208
+ With the `isolated` pattern the Lambda function resource is already per-operation, so options can be varied by operation name. For example, to give one operation a longer timeout, edit the `aws_lambda_function` resource in the generated module:
209
+
210
+ ```hcl
211
+ # packages/common/terraform/src/app/apis/my-api/my-api.tf
212
+ resource "aws_lambda_function" "api_lambda" {
213
+ for_each = local.operations
214
+
215
+ # Default to 30 seconds, but allow longer for specific operations
216
+ timeout = lookup({
217
+ sayHello = 60
218
+ }, each.key, 30)
219
+
220
+ # ... rest of configuration
170
221
  }
171
222
  ```
172
223
  </Fragment>
@@ -239,11 +290,36 @@ api.integrations.getFile.bucket.grantRead(...);
239
290
  ```
240
291
  </Fragment>
241
292
  <Fragment slot="terraform">
242
- :::note[Integration Overrides]
243
- Overriding specific integrations is not supported with Terraform modules since they use the router pattern. All operations are handled by the single Lambda function.
293
+ To point a specific operation at a different integration type, exclude it from the default `for_each` and declare its integration separately. For example, to serve `getDocumentation` from an external website:
244
294
 
245
- For different integration types per operation, you would need to implement explicit integrations manually (see the [Explicit Integrations](#explicit-integrations) section below).
246
- :::
295
+ ```hcl
296
+ # packages/common/terraform/src/app/apis/my-api/my-api.tf
297
+
298
+ # Exclude the overridden operation from the default per-operation resources
299
+ locals {
300
+ overridden_operations = ["getDocumentation"]
301
+ default_operations = {
302
+ for op, details in local.operations : op => details
303
+ if !contains(local.overridden_operations, op)
304
+ }
305
+ }
306
+
307
+ # Then use local.default_operations in place of local.operations for the
308
+ # aws_lambda_function, aws_iam_role, aws_apigatewayv2_integration and
309
+ # aws_lambda_permission resources, and add the override:
310
+ resource "aws_apigatewayv2_integration" "get_documentation" {
311
+ api_id = module.http_api.api_id
312
+ integration_type = "HTTP_PROXY"
313
+ integration_uri = "https://example.com/documentation"
314
+ integration_method = "GET"
315
+ }
316
+
317
+ resource "aws_apigatewayv2_route" "get_documentation" {
318
+ api_id = module.http_api.api_id
319
+ route_key = local.route_key["getDocumentation"]
320
+ target = "integrations/${aws_apigatewayv2_integration.get_documentation.id}"
321
+ }
322
+ ```
247
323
  </Fragment>
248
324
  </Infrastructure>
249
325
 
@@ -269,11 +345,20 @@ new MyApi(this, 'MyApi', {
269
345
  ```
270
346
  </Fragment>
271
347
  <Fragment slot="terraform">
272
- :::note[Authorizer Overrides]
273
- Per-operation authorizer overrides are not supported with Terraform modules. The entire API uses the authentication method specified when generating the API (IAM, Cognito, or Custom).
348
+ Authorization is set on the route (HTTP API) or method (REST API) for each operation, so it can be varied by operation name. For example, to leave one operation unauthenticated on an HTTP API:
274
349
 
275
- For per-operation authorization, you would need to implement explicit integrations manually as below.
276
- :::
350
+ ```hcl
351
+ # packages/common/terraform/src/app/apis/my-api/my-api.tf
352
+ resource "aws_apigatewayv2_route" "operation_routes" {
353
+ for_each = local.operations
354
+
355
+ # ... rest of configuration
356
+
357
+ authorization_type = each.key == "getDocumentation" ? "NONE" : "AWS_IAM"
358
+ }
359
+ ```
360
+
361
+ For an IAM-authenticated REST API, also add a resource policy statement allowing unauthenticated access to that operation's path.
277
362
  </Fragment>
278
363
  </Infrastructure>
279
364
 
@@ -297,319 +382,28 @@ new MyApi(this, 'MyApi', {
297
382
  ```
298
383
  </Fragment>
299
384
  <Fragment slot="terraform">
300
- For explicit per-operation integrations with Terraform, you should modify the generated app-specific module to replace the default proxy integration with specific integrations for each operation.
301
-
302
- Edit `packages/common/terraform/src/app/apis/my-api/my-api.tf`:
303
-
304
- 1. **Remove the default proxy routes** (e.g., `resource "aws_apigatewayv2_route" "proxy_routes"`)
305
- 2. **Replace the single Lambda function** with individual functions for each operation
306
- 3. **Create specific integrations and routes** for each operation, reusing the same ZIP bundle:
307
-
308
- <Tabs syncKey="http-rest">
309
- <TabItem label="HTTP API" _filter={{ infra: 'http-lambda' }}>
310
-
311
- ```diff
312
- # packages/common/terraform/src/app/apis/my-api/my-api.tf
313
-
314
- # Remove the default single Lambda function
315
- - resource "aws_lambda_function" "api_lambda" {
316
- - filename = data.archive_file.lambda_zip.output_path
317
- - function_name = "MyApiHandler"
318
- - role = aws_iam_role.lambda_execution_role.arn
319
- - handler = "index.handler"
320
- - runtime = "nodejs22.x"
321
- - timeout = 30
322
- - # ... rest of configuration
323
- - }
324
-
325
- # Remove the default proxy integration
326
- - resource "aws_apigatewayv2_integration" "lambda_integration" {
327
- - api_id = module.http_api.api_id
328
- - integration_type = "AWS_PROXY"
329
- - integration_uri = aws_lambda_function.api_lambda.invoke_arn
330
- - # ... rest of configuration
331
- - }
332
-
333
- # Remove the default proxy routes
334
- - resource "aws_apigatewayv2_route" "proxy_routes" {
335
- - for_each = toset(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"])
336
- - api_id = module.http_api.api_id
337
- - route_key = "${each.key} /{proxy+}"
338
- - target = "integrations/${aws_apigatewayv2_integration.lambda_integration.id}"
339
- - # ... rest of configuration
340
- - }
341
-
342
- # Add individual Lambda functions for each operation using the same bundle
343
- + resource "aws_lambda_function" "say_hello_handler" {
344
- + filename = data.archive_file.lambda_zip.output_path
345
- + function_name = "MyApi-SayHello"
346
- + role = aws_iam_role.lambda_execution_role.arn
347
- + handler = "sayHello.handler" # Specific handler for this operation
348
- + runtime = "nodejs22.x"
349
- + timeout = 30
350
- + source_code_hash = data.archive_file.lambda_zip.output_base64sha256
351
- +
352
- + tracing_config {
353
- + mode = "Active"
354
- + }
355
- +
356
- + environment {
357
- + variables = var.env
358
- + }
359
- +
360
- + tags = var.tags
361
- + }
362
-
363
- + resource "aws_lambda_function" "get_documentation_handler" {
364
- + filename = data.archive_file.lambda_zip.output_path
365
- + function_name = "MyApi-GetDocumentation"
366
- + role = aws_iam_role.lambda_execution_role.arn
367
- + handler = "getDocumentation.handler" # Specific handler for this operation
368
- + runtime = "nodejs22.x"
369
- + timeout = 30
370
- + source_code_hash = data.archive_file.lambda_zip.output_base64sha256
371
- +
372
- + tracing_config {
373
- + mode = "Active"
374
- + }
375
- +
376
- + environment {
377
- + variables = var.env
378
- + }
379
- +
380
- + tags = var.tags
381
- + }
382
-
383
- # Add specific integrations for each operation
384
- + resource "aws_apigatewayv2_integration" "say_hello_integration" {
385
- + api_id = module.http_api.api_id
386
- + integration_type = "AWS_PROXY"
387
- + integration_uri = aws_lambda_function.say_hello_handler.invoke_arn
388
- + payload_format_version = "2.0"
389
- + timeout_milliseconds = 30000
390
- + }
391
-
392
- + resource "aws_apigatewayv2_integration" "get_documentation_integration" {
393
- + api_id = module.http_api.api_id
394
- + integration_type = "HTTP_PROXY"
395
- + integration_uri = "https://example.com/documentation"
396
- + integration_method = "GET"
397
- + }
398
-
399
- # Add specific routes for each operation
400
- + resource "aws_apigatewayv2_route" "say_hello_route" {
401
- + api_id = module.http_api.api_id
402
- + route_key = "POST /sayHello"
403
- + target = "integrations/${aws_apigatewayv2_integration.say_hello_integration.id}"
404
- + authorization_type = "AWS_IAM"
405
- + }
406
-
407
- + resource "aws_apigatewayv2_route" "get_documentation_route" {
408
- + api_id = module.http_api.api_id
409
- + route_key = "GET /documentation"
410
- + target = "integrations/${aws_apigatewayv2_integration.get_documentation_integration.id}"
411
- + authorization_type = "NONE"
412
- + }
413
-
414
- # Add Lambda permissions for each function
415
- + resource "aws_lambda_permission" "say_hello_permission" {
416
- + statement_id = "AllowExecutionFromAPIGateway-SayHello"
417
- + action = "lambda:InvokeFunction"
418
- + function_name = aws_lambda_function.say_hello_handler.function_name
419
- + principal = "apigateway.amazonaws.com"
420
- + source_arn = "${module.http_api.api_execution_arn}/*/*"
421
- + }
422
-
423
- + resource "aws_lambda_permission" "get_documentation_permission" {
424
- + statement_id = "AllowExecutionFromAPIGateway-GetDocumentation"
425
- + action = "lambda:InvokeFunction"
426
- + function_name = aws_lambda_function.get_documentation_handler.function_name
427
- + principal = "apigateway.amazonaws.com"
428
- + source_arn = "${module.http_api.api_execution_arn}/*/*"
429
- + }
430
- ```
431
- </TabItem>
432
- <TabItem label="REST API" _filter={{ infra: 'rest-lambda' }}>
433
-
434
- ```diff
435
- # packages/common/terraform/src/app/apis/my-api/my-api.tf
436
-
437
- # Remove the default single Lambda function
438
- - resource "aws_lambda_function" "api_lambda" {
439
- - filename = data.archive_file.lambda_zip.output_path
440
- - function_name = "MyApiHandler"
441
- - role = aws_iam_role.lambda_execution_role.arn
442
- - handler = "index.handler"
443
- - runtime = "nodejs22.x"
444
- - timeout = 30
445
- - # ... rest of configuration
446
- - }
447
-
448
- # Remove the default proxy integration
449
- - resource "aws_apigatewayv2_integration" "lambda_integration" {
450
- - api_id = module.http_api.api_id
451
- - integration_type = "AWS_PROXY"
452
- - integration_uri = aws_lambda_function.api_lambda.invoke_arn
453
- - # ... rest of configuration
454
- - }
455
-
456
- # Remove the default proxy routes
457
- - resource "aws_apigatewayv2_route" "proxy_routes" {
458
- - for_each = toset(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"])
459
- - api_id = module.http_api.api_id
460
- - route_key = "${each.key} /{proxy+}"
461
- - target = "integrations/${aws_apigatewayv2_integration.lambda_integration.id}"
462
- - # ... rest of configuration
463
- - }
464
-
465
- # Add individual Lambda functions for each operation using the same bundle
466
- + resource "aws_lambda_function" "say_hello_handler" {
467
- + filename = data.archive_file.lambda_zip.output_path
468
- + function_name = "MyApi-SayHello"
469
- + role = aws_iam_role.lambda_execution_role.arn
470
- + handler = "sayHello.handler" # Specific handler for this operation
471
- + runtime = "nodejs22.x"
472
- + timeout = 30
473
- + source_code_hash = data.archive_file.lambda_zip.output_base64sha256
474
- +
475
- + tracing_config {
476
- + mode = "Active"
477
- + }
478
- +
479
- + environment {
480
- + variables = var.env
481
- + }
482
- +
483
- + tags = var.tags
484
- + }
485
-
486
- + resource "aws_lambda_function" "get_documentation_handler" {
487
- + filename = data.archive_file.lambda_zip.output_path
488
- + function_name = "MyApi-GetDocumentation"
489
- + role = aws_iam_role.lambda_execution_role.arn
490
- + handler = "getDocumentation.handler" # Specific handler for this operation
491
- + runtime = "nodejs22.x"
492
- + timeout = 30
493
- + source_code_hash = data.archive_file.lambda_zip.output_base64sha256
494
- +
495
- + tracing_config {
496
- + mode = "Active"
497
- + }
498
- +
499
- + environment {
500
- + variables = var.env
501
- + }
502
- +
503
- + tags = var.tags
504
- + }
505
-
506
- # Add specific resources and methods for each operation
507
- + resource "aws_api_gateway_resource" "say_hello_resource" {
508
- + rest_api_id = module.rest_api.api_id
509
- + parent_id = module.rest_api.api_root_resource_id
510
- + path_part = "sayHello"
511
- + }
512
-
513
- + resource "aws_api_gateway_method" "say_hello_method" {
514
- + rest_api_id = module.rest_api.api_id
515
- + resource_id = aws_api_gateway_resource.say_hello_resource.id
516
- + http_method = "POST"
517
- + authorization = "AWS_IAM"
518
- + }
519
-
520
- + resource "aws_api_gateway_integration" "say_hello_integration" {
521
- + rest_api_id = module.rest_api.api_id
522
- + resource_id = aws_api_gateway_resource.say_hello_resource.id
523
- + http_method = aws_api_gateway_method.say_hello_method.http_method
524
- +
525
- + integration_http_method = "POST"
526
- + type = "AWS_PROXY"
527
- + uri = aws_lambda_function.say_hello_handler.invoke_arn
528
- + }
529
-
530
- + resource "aws_api_gateway_resource" "get_documentation_resource" {
531
- + rest_api_id = module.rest_api.api_id
532
- + parent_id = module.rest_api.api_root_resource_id
533
- + path_part = "documentation"
534
- + }
535
-
536
- + resource "aws_api_gateway_method" "get_documentation_method" {
537
- + rest_api_id = module.rest_api.api_id
538
- + resource_id = aws_api_gateway_resource.get_documentation_resource.id
539
- + http_method = "GET"
540
- + authorization = "NONE"
541
- + }
542
-
543
- + resource "aws_api_gateway_integration" "get_documentation_integration" {
544
- + rest_api_id = module.rest_api.api_id
545
- + resource_id = aws_api_gateway_resource.get_documentation_resource.id
546
- + http_method = aws_api_gateway_method.get_documentation_method.http_method
547
- +
548
- + integration_http_method = "GET"
549
- + type = "HTTP"
550
- + uri = "https://example.com/documentation"
551
- + }
552
-
553
- # Update deployment to depend on new integrations
554
- ~ resource "aws_api_gateway_deployment" "api_deployment" {
555
- rest_api_id = module.rest_api.api_id
556
-
557
- depends_on = [
558
- - aws_api_gateway_integration.lambda_integration,
559
- + aws_api_gateway_integration.say_hello_integration,
560
- + aws_api_gateway_integration.get_documentation_integration,
561
- ]
562
-
563
- lifecycle {
564
- create_before_destroy = true
565
- }
566
-
567
- + triggers = {
568
- + redeployment = sha1(jsonencode([
569
- + aws_api_gateway_integration.say_hello_integration,
570
- + aws_api_gateway_integration.get_documentation_integration,
571
- + ]))
572
- + }
573
- }
574
-
575
- # Add Lambda permissions for each function
576
- + resource "aws_lambda_permission" "say_hello_permission" {
577
- + statement_id = "AllowExecutionFromAPIGateway-SayHello"
578
- + action = "lambda:InvokeFunction"
579
- + function_name = aws_lambda_function.say_hello_handler.function_name
580
- + principal = "apigateway.amazonaws.com"
581
- + source_arn = "${module.rest_api.api_execution_arn}/*/*"
582
- + }
583
-
584
- + resource "aws_lambda_permission" "get_documentation_permission" {
585
- + statement_id = "AllowExecutionFromAPIGateway-GetDocumentation"
586
- + action = "lambda:InvokeFunction"
587
- + function_name = aws_lambda_function.get_documentation_handler.function_name
588
- + principal = "apigateway.amazonaws.com"
589
- + source_arn = "${module.rest_api.api_execution_arn}/*/*"
590
- + }
591
- ```
592
- </TabItem>
593
- </Tabs>
385
+ Replace the `for_each` used by the `isolated` pattern with explicit instantiations of the Lambda functions, integrations and permissions for each operation.
594
386
 
387
+ :::caution
388
+ Unlike CDK, there is no type-safety in Terraform which will give you a type error if you add a new operation in your application code but forget to declare it in your infrastructure.
389
+ :::
595
390
  </Fragment>
596
391
  </Infrastructure>
597
392
 
598
393
  #### Integration Pattern
599
394
 
600
- <Infrastructure>
601
- <Fragment slot="cdk">
395
+ Generated APIs support two integration patterns:
602
396
 
603
- Generated CDK API constructs support two integration patterns:
604
-
605
- - `isolated` creates one Lambda function per operation. This is the default for generated APIs.
397
+ - `isolated` creates one Lambda function per operation. This is the default and recommended option for APIs.
606
398
  - `shared` creates a single default router Lambda and reuses it for every operation unless you override specific integrations.
607
399
 
608
- `isolated` gives you finer-grained permissions and configuration per operation. `shared` reduces Lambda and API Gateway integration sprawl while still allowing selective overrides.
400
+ `isolated` gives you finer-grained permissions and configuration per operation, as well as better separation for logs and traces. `shared` reduces the likelihood of encountering cold-starts for low-usage APIs.
609
401
 
610
- For example, setting `pattern` to `'shared'` creates a single function instead of one per integration:
402
+ <Infrastructure>
403
+ <Fragment slot="cdk">
404
+ The integration pattern can be changed at any time in CDK by updating your API construct. For example, setting `pattern` to `'shared'` creates a single function instead of one per integration:
611
405
 
612
- ```ts {5,11-12}
406
+ ```ts {6}
613
407
  // packages/common/constructs/src/app/apis/my-api.ts
614
408
  export class MyApi<...> extends ... {
615
409
 
@@ -624,20 +418,71 @@ export class MyApi<...> extends ... {
624
418
  ```
625
419
  </Fragment>
626
420
  <Fragment slot="terraform">
627
- Terraform modules automatically use the router pattern - this is the default and only supported approach. The generated module creates a single Lambda function that handles all API operations.
421
+ Unlike CDK, the integration pattern is baked into the generated module. To change the integration pattern:
628
422
 
629
- You can simply instantiate the default module to get the router pattern:
423
+ <Steps>
424
+ 1. Delete the previously generated API module in `packages/common/terraform/src/app/apis`
425
+ 2. Re-run the API generator with the other integration pattern:
426
+ <RunGenerator generator="ts#api" requiredParameters={{ integrationPattern: 'shared' }} />
427
+ </Steps>
630
428
 
631
- ```hcl
632
- # Default router pattern - single Lambda function for all operations
633
- module "my_api" {
634
- source = "../../common/terraform/src/app/apis/my-api"
429
+ With the `isolated` pattern, the module reads the operations from a generated file:
635
430
 
636
- asset_bucket_name = module.asset_bucket.bucket_name
637
-
638
- # Single Lambda function handles all operations automatically
639
- tags = local.common_tags
431
+ ```hcl
432
+ # packages/common/terraform/src/app/apis/my-api/my-api.tf
433
+ locals {
434
+ operations_file = "${path.module}/../../../generated/my-api/operations.json"
435
+ operations = fileexists(local.operations_file) ? jsondecode(file(local.operations_file)) : {}
640
436
  }
641
437
  ```
438
+
439
+ This file is generated from your API, so you do not need to edit this by hand. Adding an operation to your API application code adds the route and lambda function on the next deploy. It is `.gitignore`d by default; remove the entry if you prefer to check it in.
642
440
  </Fragment>
643
441
  </Infrastructure>
442
+
443
+ <OptionFilter when={{ iac: 'terraform', infra: 'rest-lambda' }} description="Raising the REST API path depth limit in Terraform">
444
+ ##### Terraform REST API Path Depth Limit
445
+
446
+ :::caution
447
+ Due to a limitation with Terraform where instances of resources can't reference one another (see [hashicorp/terraform#26697](https://github.com/hashicorp/terraform/issues/26697)), the API Gateway resource tree is built one level at a time rather than recursively, supporting operation paths of up to 16 segments. If an operation's path exceeds this, the plan fails with a message naming the paths that are too deep.
448
+
449
+ <Drawer title="Supporting deeper paths" trigger="Click here for instructions to support deeper paths should your API require it">
450
+
451
+ Edit `packages/common/terraform/src/app/apis/<my-api>/<my-api>.tf`:
452
+
453
+ <Steps>
454
+ 1. Increment `max_path_depth` in `locals`:
455
+
456
+ ```hcl
457
+ locals {
458
+ max_path_depth = 17
459
+ }
460
+ ```
461
+
462
+ 2. Copy the last `aws_api_gateway_resource` block, incrementing both the resource name and its parent:
463
+
464
+ ```hcl
465
+ resource "aws_api_gateway_resource" "path_depth_16" {
466
+ for_each = local.path_nodes_by_depth[16]
467
+
468
+ rest_api_id = module.rest_api.api_id
469
+ parent_id = aws_api_gateway_resource.path_depth_15[each.value.parent].id
470
+ path_part = each.value.part
471
+ }
472
+ ```
473
+
474
+ 3. Add the new level to the `resource_ids` local:
475
+
476
+ ```hcl
477
+ locals {
478
+ resource_ids = merge(
479
+ ...
480
+ { for path, resource in aws_api_gateway_resource.path_depth_16 : path => resource.id },
481
+ )
482
+ }
483
+ ```
484
+ </Steps>
485
+
486
+ </Drawer>
487
+ :::
488
+ </OptionFilter>