| 1 | --- |
| 2 | title: REST API (API Gateway v1) |
| 3 | description: Expose a Lambda with a regional Amazon API Gateway REST API using RestApi, Resource, Method, Deployment, and Stage primitives. |
| 4 | --- |
| 5 | |
| 6 | The [Deploy a Lambda Function](/aws/compute/lambda) tutorial uses a **Function URL** for HTTP. Many teams still use **Amazon API Gateway** (REST, v1) as the front door. |
| 7 | |
| 8 | Alchemy models the v1 REST control plane as separate resources so you can wire integrations, stages, and custom domains explicitly. |
| 9 | |
| 10 | ## Try the example |
| 11 | |
| 12 | The repo includes **`examples/aws-rest-api`**: a minimal **regional** REST API with `ANY` on the root and a `{proxy+}` resource, **AWS_PROXY** integration to a Lambda, then **Deployment**, **Stage** (`prod`), and **Lambda.Permission** so API Gateway can invoke the function. |
| 13 | |
| 14 | ```sh |
| 15 | cd examples/aws-rest-api |
| 16 | bun install |
| 17 | bun run deploy |
| 18 | ``` |
| 19 | |
| 20 | After deploy, open the printed `invokeUrl` in a browser; you should see the Lambda’s text response. |
| 21 | |
| 22 | ## Shape of the stack |
| 23 | |
| 24 | Typical order inside `Effect.gen`: |
| 25 | |
| 26 | 1. **`AWS.ApiGateway.RestApi`** — creates the API and exposes `restApiId` / `rootResourceId`. |
| 27 | 2. **`AWS.ApiGateway.Resource`** — optional path segments (e.g. `{proxy+}`). |
| 28 | 3. **`AWS.ApiGateway.Method`** — HTTP verb + integration (`AWS_PROXY` Lambda ARNs use `Output.interpolate` with `arn:aws:apigateway:${region}:lambda:path/2015-03-31/functions/${functionArn}/invocations`). |
| 29 | 4. **`AWS.ApiGateway.Deployment`** — snapshots the current resource graph; change **`triggers`** (or other props) to force a new deployment when only integrations changed. |
| 30 | 5. **`AWS.ApiGateway.Stage`** — attaches a deployment to a named stage (`prod`, `dev`, …). |
| 31 | 6. **`AWS.Lambda.Permission`** — `principal: "apigateway.amazonaws.com"` and `sourceArn` covering `execute-api` for your API. |
| 32 | |
| 33 | Use **`yield* AWS.AWSEnvironment`** for `region` and `accountId` when building ARNs (as in the example). |
| 34 | |
| 35 | ## Private integration (VPC link) |
| 36 | |
| 37 | For **private** HTTP integrations, create a **`AWS.ApiGateway.VpcLink`** with your load balancer target ARNs, then reference `vpcLinkId` as **`integration.connectionId`** with **`connectionType: "VPC_LINK"`** on `AWS.ApiGateway.Method` (`integration.uri` points at your private backend URL). |
| 38 | |
| 39 | ```typescript |
| 40 | const link = yield* AWS.ApiGateway.VpcLink("InternalLink", { |
| 41 | name: "internal-nlb", |
| 42 | targetArns: [loadBalancer.loadBalancerArn], |
| 43 | }); |
| 44 | |
| 45 | yield* AWS.ApiGateway.Method("PrivateGet", { |
| 46 | restApiId: api.restApiId, |
| 47 | resourceId: resource.resourceId, |
| 48 | httpMethod: "GET", |
| 49 | integration: { |
| 50 | type: "HTTP_PROXY", |
| 51 | integrationHttpMethod: "GET", |
| 52 | uri: "https://api.internal.example/resource", |
| 53 | connectionType: "VPC_LINK", |
| 54 | connectionId: link.vpcLinkId, |
| 55 | }, |
| 56 | }); |
| 57 | ``` |
| 58 | |
| 59 | See also [VpcLink](/providers/aws/apigateway/vpclink) in the generated API reference. |
| 60 | |
| 61 | ## Custom domain |
| 62 | |
| 63 | Serve the API from your own hostname instead of the default `execute-api` URL. You need a validated ACM certificate, an **`AWS.ApiGateway.DomainName`**, a **`AWS.ApiGateway.BasePathMapping`**, and a DNS record pointing at the domain's regional target. |
| 64 | |
| 65 | ### Request a certificate |
| 66 | |
| 67 | ```typescript |
| 68 | const cert = yield* AWS.ACM.Certificate("ApiCertificate", { |
| 69 | domainName: "api.example.com", |
| 70 | hostedZoneId: "Z1234567890", |
| 71 | }); |
| 72 | ``` |
| 73 | |
| 74 | With `hostedZoneId` set, the provider creates the DNS validation records in Route 53 and waits for the certificate to be issued. Note that `AWS.ACM.Certificate` always requests the certificate in **`us-east-1`** (the region CloudFront and **EDGE** endpoints require) — a **REGIONAL** domain name needs a certificate in the API's own region, so outside `us-east-1` pass a pre-provisioned regional certificate ARN instead. |
| 75 | |
| 76 | ### Create the domain name |
| 77 | |
| 78 | ```typescript |
| 79 | const domain = yield* AWS.ApiGateway.DomainName("ApiDomain", { |
| 80 | domainName: "api.example.com", |
| 81 | regionalCertificateArn: cert.certificateArn, |
| 82 | endpointConfiguration: { types: ["REGIONAL"] }, |
| 83 | securityPolicy: "TLS_1_2", |
| 84 | }); |
| 85 | ``` |
| 86 | |
| 87 | A regional domain exposes `regionalDomainName` and `regionalHostedZoneId` — the alias target for DNS. (EDGE domains use `certificateArn` and the `distributionDomainName` / `distributionHostedZoneId` attributes instead.) |
| 88 | |
| 89 | ### Map the API to the domain |
| 90 | |
| 91 | ```typescript |
| 92 | yield* AWS.ApiGateway.BasePathMapping("Root", { |
| 93 | domainName: domain.domainName, |
| 94 | restApiId: api.restApiId, |
| 95 | stage: stage.stageName, |
| 96 | }); |
| 97 | ``` |
| 98 | |
| 99 | Omitting `basePath` maps the domain root; set `basePath: "v1"` to serve the stage under `https://api.example.com/v1`. |
| 100 | |
| 101 | ### Point DNS at the domain |
| 102 | |
| 103 | ```typescript |
| 104 | yield* AWS.Route53.Record("ApiAlias", { |
| 105 | hostedZoneId: "Z1234567890", |
| 106 | name: "api.example.com", |
| 107 | type: "A", |
| 108 | aliasTarget: { |
| 109 | hostedZoneId: domain.regionalHostedZoneId.as<string>(), |
| 110 | dnsName: domain.regionalDomainName.as<string>(), |
| 111 | }, |
| 112 | }); |
| 113 | ``` |
| 114 | |
| 115 | An alias **A** record targets the regional endpoint; `.as<string>()` narrows the optional outputs. See [DomainName](/providers/aws/apigateway/domainname) and [BasePathMapping](/providers/aws/apigateway/basepathmapping) in the API reference, and the [custom domains guide](/aws/networking/custom-domains) for the broader pattern (CloudFront, static sites). |
| 116 | |
| 117 | ## API reference |
| 118 | |
| 119 | Generated docs for each primitive live under **Providers → AWS → ApiGateway** in the sidebar (for example [RestApi](/providers/aws/apigateway/restapi)). Run `bun generate:api-reference` locally after changing JSDoc on resources. |
| 120 | |
| 121 | ## Next steps |
| 122 | |
| 123 | - **Custom domains:** covered [above](#custom-domain); see also the [custom domains guide](/aws/networking/custom-domains). |
| 124 | - **API keys / throttling:** `ApiKey`, `UsagePlan`, `UsagePlanKey`. |
| 125 | - **Authorizers:** `Authorizer` for Cognito or Lambda TOKEN / REQUEST flows. |
| 126 | - **Gateway responses:** `GatewayResponse` for consistent 4xx/5xx bodies. |
| 127 | |
| 128 | HTTP APIs (v2) are a different product; this tutorial is **REST v1** only. |