DEV Community

Cover image for Deploy a Serverless API with AWS CDK and AWS Lambda

Posted on • Originally published at

Deploy a Serverless API with AWS CDK and AWS Lambda

In this tutorial, we will implement a Serverless API using AWS Lambda and we will deploy it using AWS CDK. We will use Typescript as the CDK language. It will be a page view counter where we will keep the state in Redis.

Check the github repo for the source code.

What is AWS CDK?

AWS CDK is an interesting project which allows you to provision and deploy AWS infrastructure with code. Currently TypeScript, JavaScript, Python, Java, C#/.Net are supported. You can compare AWS CDK with following technologies:

  • AWS CloudFormation
  • Serverless Framework

The above projects allows you to set up the infrastructure with configuration files (yaml, json) while with AWS CDK, you set up the resources with code. For more information about CDK see the related AWS Docs.

Project Setup

Install cdk with: npm install -g aws-cdk

Create a directory for your project. Inside the directory init cdk:

mkdir api-with-cdk

cd api-with-cdk

cdk init --language typescript
Enter fullscreen mode Exit fullscreen mode

Counter Function Code

Create a directory for your API function

mkdir api

Inside the API folder, init and npm project and install ioredis.

cd api
npm init
npm install ioredis
Enter fullscreen mode Exit fullscreen mode

In the api folder, create a file: counter.js

var Redis = require("ioredis");
    if (typeof client === 'undefined') {
        var client = new Redis(process.env.REDIS_URL);

exports.main = async function (event, context) {
    try {
        const count = await client.incr('counter')
        return {
        statusCode: 200,
        headers: {},
        body: "View count:" + count
    } catch (error) {
        var body = error.stack || JSON.stringify(error, null, 2);
        return {
        statusCode: 400,
        headers: {},
        body: JSON.stringify(body)
Enter fullscreen mode Exit fullscreen mode

Counter Service

Go back to the top directory, install lambda and api-gateway libraries:

cd ..
npm install @aws-cdk/aws-apigateway @aws-cdk/aws-lambda
Enter fullscreen mode Exit fullscreen mode

Inside the lib directory, create counter_service.ts:

import * as core from "@aws-cdk/core";
import * as apigateway from "@aws-cdk/aws-apigateway";
import * as lambda from "@aws-cdk/aws-lambda";

export class CounterService extends core.Construct {
constructor(scope: core.Construct, id: string) {
super(scope, id);

       const handler = new lambda.Function(this, "AppHandler", {
           runtime: lambda.Runtime.NODEJS_10_X,
           code: lambda.Code.fromAsset("api"),
           handler: "counter.main",
           environment: {
               REDIS_URL: "REPLACE_HERE"

       const api = new apigateway.RestApi(this, "counter-api", {
           restApiName: "Serverless Counter API",
           description: "This is a basic API."

       const apiIntegration = new apigateway.LambdaIntegration(handler, {
           requestTemplates: { "application/json": '{ "statusCode": "200" }' }

       api.root.addMethod("GET", apiIntegration);
Enter fullscreen mode Exit fullscreen mode

You need to replace REPLACE_HERE with a proper Redis URL (ioredis format). You can create a Serverless Redis database in the Upstash for free. Copy the ioredis URL from Upstash console.

Update the Stack

Update lib/api-with-cdk-stack.ts:

import * as cdk from '@aws-cdk/core';
import * as counter_service from '../lib/counter_service';

export class ApiWithCdkStack extends cdk.Stack {
    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);
        new counter_service.CounterService(this, 'CounterApi');
Enter fullscreen mode Exit fullscreen mode


In the top folder:

cdk synth
cdk bootstrap
cdk deploy
Enter fullscreen mode Exit fullscreen mode

Now you should see the command outputs the endpoint url. Click to the url, you should see the page counter.

Success 🎉

Top comments (1)

nomada2 profile image

// 20211004185027

"message": "Internal server error"