Last updated: Jan 26, 2024
Reading timeยท4 min
We're going to create an HTTP API with 2 routes:
/todos
- with a Lambda function integration./todos/{todoId}
- with a Lambda function integration.HTTP APIs have 2 main components:
routes
- the HTTP method and path of the request, e.g. GET /articles
integration
- how the HTTP API should respond to requests to a specific
route, e.g. a Lambda function gets invoked and returns a responseIn order to create an HTTP API in CDK, we have to instantiate and configure the HttpApi class.
Let's start by creating an HTTP API, a
lambda function and an API route at GET
/todos
:
import {HttpLambdaIntegration} from 'aws-cdk-lib/aws-apigatewayv2-integrations'; import { CorsHttpMethod, HttpApi, HttpMethod, } from 'aws-cdk-lib/aws-apigatewayv2'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as cdk from 'aws-cdk-lib'; import * as path from 'path'; export class CdkStarterStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); // ๐ create our HTTP Api const httpApi = new HttpApi(this, 'http-api-example', { description: 'HTTP API example', corsPreflight: { allowHeaders: [ 'Content-Type', 'X-Amz-Date', 'Authorization', 'X-Api-Key', ], allowMethods: [ CorsHttpMethod.OPTIONS, CorsHttpMethod.GET, CorsHttpMethod.POST, CorsHttpMethod.PUT, CorsHttpMethod.PATCH, CorsHttpMethod.DELETE, ], allowCredentials: true, allowOrigins: ['http://localhost:3000'], }, }); // ๐ create get-todos Lambda const getTodosLambda = new lambda.Function(this, 'get-todos', { runtime: lambda.Runtime.NODEJS_18_X, handler: 'index.main', code: lambda.Code.fromAsset(path.join(__dirname, '/../src/get-todos')), }); // ๐ add route for GET /todos httpApi.addRoutes({ path: '/todos', methods: [HttpMethod.GET], integration: new HttpLambdaIntegration( 'get-todos-integration', getTodosLambda, ), }); } }
Let's go over what we did in the code sample.
We created an Http API by instantiating the HttpApi
class. We've enabled
CORS on the API, even though we won't need it, because we'll be testing the
API through the CLI. You can read more about CORS with HTTP APIs in my other
article - Enable CORS for HTTP API in AWS CDK
We created a Lambda function, which we will integrate with our HTTP API at
GET /todos
We added a route to our API, specifying that all GET
requests made to the
/todos
path should get routed to our lambda function
Let's add the code for our lambda function at src/get-todos/index.js
:
async function main(event) { return { body: JSON.stringify([ {taskId: 1, text: 'buy groceries ๐๏ธ'}, {taskId: 2, text: 'wash the dishes ๐ฝ๏ธ'}, ]), statusCode: 200, }; } module.exports = {main};
The lambda function simply returns a JSON response of an array with to-do items.
Before we deploy and test our API, let's also add a route with a path parameter
at DELETE /todos/{todoId}
.
import {HttpLambdaIntegration} from 'aws-cdk-lib/aws-apigatewayv2-integrations'; import { CorsHttpMethod, HttpApi, HttpMethod, } from 'aws-cdk-lib/aws-apigatewayv2'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as cdk from 'aws-cdk-lib'; import * as path from 'path'; export class CdkStarterStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); // ... rest // ๐ create delete-todos Lambda const deleteTodoLambda = new lambda.Function(this, 'delete-todo', { runtime: lambda.Runtime.NODEJS_18_X, handler: 'index.main', code: lambda.Code.fromAsset(path.join(__dirname, '/../src/delete-todo')), }); // ๐ add route for DELETE /todos/{todoId} httpApi.addRoutes({ path: '/todos/{todoId}', methods: [HttpMethod.DELETE], integration: new HttpLambdaIntegration( 'delete-todo-integration', deleteTodoLambda, ), }); // ๐ add an Output with the API Url new cdk.CfnOutput(this, 'apiUrl', { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion value: httpApi.url!, }); } }
Let's go over what we did in the code sample.
We created a Lambda function, which we'll integrate for HTTP DELETE at
/todos/{todoId}
We added another route to our HTTP API. The route is for DELETE requests to
/todos/{todoId}
, i.e. /todos/todo-123
. The requests to this route will
get forwarded to our delete todo Lambda function
We added an Output
with the HTTP API URL, which we'll write to a file on
the local file system
json
output file.Let's add the code for the delete-todo lambda function at
src/delete-todo/index.js
:
async function main(event) { console.log('event is ๐', JSON.stringify(event, null, 2)); return { body: JSON.stringify([ {todoId: event.pathParameters.todoId, text: 'Buy groceries'}, ]), statusCode: 200, }; } module.exports = {main};
The function does pretty much the same as our get-todos
function - it returns
a JSON response.
Let's issue the deploy command to test our HTTP API. We'll write the API URL to a file on the local file system:
npx aws-cdk deploy \ --outputs-file ./cdk-outputs.json
After a successful deployment, we can look at the integrations for our HTTP API in the API Gateway management console:
Everything seems to be configured as expected. We have:
/todos
route with Lambda function integration/todos/{todoId}
route with Lambda function integrationLet's test our GET /todos
route first. You can grab the API URL from the
management console or from the output in the cdk-outputs.json
file.
curl --location --request GET 'YOUR_API_URL/todos'
The response shows that our Lambda integration for the GET /todos
route works
as expected:
Finally, let's test our DELETE /todos/{todoId}
route:
curl --location --request DELETE 'YOUR_API_URL/todos/todo-1234'
Our Lambda integration for the DELETE /todos/{todoId}
route also works:
At this point, we have a working HTTP API with Lambda integrations for 2 routes.
To delete the resources we have provisioned, run the destroy
command:
npx aws-cdk destroy