Building a REST API
Choosing an architecture
When building a serverless REST API, there are several architectural patterns you can apply. For most cases we recommend using an API Gateway with individual Lambda functions for each endpoint.
Adding API Gateway to CDK
To set up an API Gateway in your infrastructure code, we recommend to use the SpecRestApi construct from aws-cdk-lib/aws-apigateway
.
This construct enables you to define your API mapping using OpenAPI specs.
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { SpecRestApi, ApiDefinition, EndpointType } from 'aws-cdk-lib/aws-apigateway';
import * as path from 'node:path';
export class AppStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
new SpecRestApi(this, 'MyRestApi', {
apiDefinition: ApiDefinition.fromAsset(
path.join(import.meta.dirname, '/path/to/openapi.json')
),
endpointTypes: [EndpointType.REGIONAL],
});
// make sure to assign the correct permissions to your Lambdas.
}
}
Recommended settings for this construct can be found on our CDK snippet page.
Writing OpenAPI specs
You can use the OpenAPI extensions for API Gateway to add additional API Gateway metadata to your OpenAPI definitions.
A simple OpenAPI document with a single endpoint might look like this:
openapi: 3.0.1
info:
title: Sample API
version: 1.0.0
paths:
/hello:
get:
responses:
'200':
description: A greeting
content:
application/json:
schema:
type: object
properties:
message:
type: string
x-amazon-apigateway-integration:
httpMethod: POST
passthroughBehavior: "when_no_match"
type: aws_proxy
uri:
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloWorld.Arn}/invocations"
In this case, the ${HelloWorld.Arn}
refers to a Lambda function called "HelloWorld" that exists in the same CDK stack.
TIP
If you are writing your OpenAPI specifications manually, you can use Swagger Editor for validation and previewing.
Alternatively, you can generate your OpenAPI specifications using a code-first approach with libraries such as asteasolutions/zod-to-openapi.
Implementing a REST endpoint
To implement a REST endpoint, just add a Lambda function with REST integration.
When dealing with REST Lambdas, you will likely run into common problems that often require repetitive boilerplate code, such as normalising request headers, parsing and validating request parameters or handling errors.
Most of these challenges can be addressed with utilities from @backpack/aws-lambda
:
import { defineRestLambda } from "@backpack/aws-lambda";
import { parseRequest, jsonOk, defaultErrorHandler } from "@backpack/aws-lambda/rest";
import { AsyncResult } from "@backpack/error-handling/async-result";
export const handler = defineRestLambda(async (event) => {
return AsyncResult
// using `AsyncResult` from `@backpack/error-handling` to handle (async) errors
.try(() => {
const request = parseRequest(event);
// parse a required header
const callerId = request.getHeader("X-Caller-Id", { required: true });
// parse a JSON body and validate it against a Zod schema
const book = request.getBody().json({ validated: BookSchema });
// return a HTTP 200 result
return jsonOk({ message: "Hello world" });
})
// apply the default error handler from `@backpack/aws-lambda/rest`
.recover(defaultErrorHandler());
});
Check out the API reference of @backpack/aws-lambda
to learn more. Or have a look at the Bookstore REST API demo.
Deploying with CDK
Now use the CDK CLI to deploy your API Gateway to your preferred environment:
npx cdk deploy -c config=dev
After a successful deployment, you can trigger your endpoint from the AWS console.
Security and API Management
By default, your REST endpoints are publicly accessible. If you want to restrict access, you can integrate it with the API Management portal.