Http API Example in AWS CDK [API Gateway V2]

avatar
Borislav Hadzhiev

Last updated: Jan 26, 2024
4 min

banner

# Creating an HTTP API in AWS CDK

We're going to create an HTTP API with 2 routes:

  • GET /todos - with a Lambda function integration.
  • DELETE /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 response

In order to create an HTTP API in CDK, we have to instantiate and configure the HttpApi class.

The code for this article is available on GitHub

Let's start by creating an HTTP API, a lambda function and an API route at GET /todos:

lib/cdk-starter-stack.ts
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, ), }); } }
If you still use CDK version 1, switch to the cdk-v1 branch in the GitHub repository.

Let's go over what we did in the code sample.

  1. 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

  2. We created a Lambda function, which we will integrate with our HTTP API at GET /todos

  3. We added a route to our API, specifying that all GET requests made to the /todos path should get routed to our lambda function

The code for this article is available on GitHub

Let's add the code for our lambda function at src/get-todos/index.js:

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.

The code for this article is available on GitHub

Before we deploy and test our API, let's also add a route with a path parameter at DELETE /todos/{todoId}.

lib/cdk-starter-stack.ts
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.

  1. We created a Lambda function, which we'll integrate for HTTP DELETE at /todos/{todoId}

  2. 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

  3. We added an Output with the HTTP API URL, which we'll write to a file on the local file system

Writing the API URL to a file is very convenient for keeping the value in sync between your frontend and backend code. On your frontend, you can just import the value from the json output file.

Let's add the code for the delete-todo lambda function at src/delete-todo/index.js:

The code for this article is available on GitHub
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:

shell
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:

http api integrations

Everything seems to be configured as expected. We have:

  • GET /todos route with Lambda function integration
  • DELETE /todos/{todoId} route with Lambda function integration

Let'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.

shell
curl --location --request GET 'YOUR_API_URL/todos'

The response shows that our Lambda integration for the GET /todos route works as expected:

http api get route

Finally, let's test our DELETE /todos/{todoId} route:

shell
curl --location --request DELETE 'YOUR_API_URL/todos/todo-1234'

Our Lambda integration for the DELETE /todos/{todoId} route also works:

http api delete route

At this point, we have a working HTTP API with Lambda integrations for 2 routes.

# Clean up

To delete the resources we have provisioned, run the destroy command:

shell
npx aws-cdk destroy

# Further Reading

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.

Copyright ยฉ 2024 Borislav Hadzhiev