This gist represents an API construct on top of API Gateway V2. It's designed to make it easy to add lots of protected endpoints to a serverless API.
It introduces the following opinions:
- Sandbox environments exist in the same AWS account as "dev"
- There are only dev and production accounts - no test account
- Dev and prod have static DNS records, but sandbox DNS records are dynamically generated by AWS
- All API endpoints are authenticated by default. You opt out rather than in to authentication
- All endpoints are either one verb only or all HTTP verbs. You cannot have a handler for only
GETandPOSTbut notPUT, for example. Instead, you must create separate endpoints for each verb (unless you useANY, in which case your lambda will be triggered for all HTTP verbs on that endpoint)
Typescript is used to enforce the pattern for the endpoint. It validates that the endpoint:
- Starts with a HTTP verb (or
ANY) - Followed by a whitespace character
- Followed by any string that starts with
/(just/is a valid string, but so is/parent/{id}/child)
For most endpoints, we'd expect syntax similar to the following:
api.addEndpoints({
'GET /': 'src/helloWorld.ts',
'GET /admin/{resource}': 'src/getAdminResourceList.ts',
'GET /admin/{resource}/{id}': 'src/getAdminResourceById.ts',
});This adds 3 endpoints with 3 separate handlers, which all require authentication as well as various lambda runtime defaults. These defaults include things like ARM CPU architecture, 265MB of memory, bundling (with minification), xray tracing, a NodeJS v20 runtime, and a 30 second timeout.
You can still fallback onto the full flexibility for the lambda runtime if you need to, with options like the following:
api.addEndpoints({
'GET /': {
entry: 'src/myHandler.ts',
architecture: Architecture.X86_64
},
});This would create a handler using the code in src/myHandler.ts, triggered when a GET request is made to /, which runs on X86 CPU architecture. This endpoint would require authentication by default.
A helper function addPublicEndpoints is provided for opting out of the default authentication for a range of endpoints. This means that in order to add a public endpoint, you could use any of the following syntax:
api.addPublicEndpoints({
'GET /': 'src/myHandler.ts',
});
api.addEndpoints({
'GET /': {
entry: 'src/myHandler.ts',
publicEndpoint: true,
},
});
api.addEndpointsWithDefaults({
'GET /': 'src/myHandler.ts',
}, {
publicEndpoint: true,
});
api.addEndpoint('GET /', {
entry: 'src/myHandler.ts',
publicEndpoint: true,
});You can access the functions backing any endpoints you create via the value returned from addEndpoints
const newEndpoints = api.addEndpoints({
'GET /': 'src/myHandler.ts',
});
// The NodejsFunction that was created for `GET /`
const getLambda = newEndpoints['GET /'];Attempting to access endpoints which aren't in the newly added endpoints will cause Typescript errors
const newEndpoints = api.addEndpoints({
'GET /': 'src/myHandler.ts',
});
// Typescript is happy as this endpoint was registered above
newEndpoints['GET /'];
// Typescript error as `GET /non-existent` does not exist above
newEndpoints['GET /non-existent'];Some lambdas require additional permissions (such as read / write to S3 buckets). You can manage those permissions by accessing the returned value from addEndpoints
const newEndpoints = api.addEndpoints({
'GET /': 'src/myHandler.ts',
});
// Grants read access to `myBucket` for the lambda assigned to the `GET /` endpoint
myBucket.grantRead(newEndpoints['GET /']);- Requires
CDK_ENVto be set when runningcdk deployorcdk synth, as this defines whether it's deploying to dev, prod, or a sandbox environment
# Deploy to sandbox
CDK_ENV=sandbox-me cdk deploy
# Deploy to dev
CDK_ENV=dev cdk deploy