Nest JS for Building Serverless lambda Interface
Published: 2022-06-20 06:20:56


### Nest JS with serverless Lambda deployment 

Github : https://github.com/tkssharma/blogs/tree/master/nest-js-aws-cdk-lamda-deployment

Hi Guys, 

In this Blog We are going to talk about serverless deployment of Nest JS APIs 
I remember when i first wrote my lambda in Node JS and that time i upload my code zip and executed lambda, I was never a big fan of lambda as my approach of developing lambda was not the correct one 

what i was doing wrong 

- building a single lambda for single REST APIs and map that lambda to api gateway 
- managing a lambda which is serving simple one api for my service so if i am shaving 10 end points i was having 10 lambda mapped to api gateway
- Another issues is managing mapping at api gateway for all these REST end points and managing versions

Recently i started doing more serverless and the reason is now i don't need to struggle with all above problems 

- I can build whole microservice as a single lambda 
- i don't need to worry about api gateway mapping as we have single proxy to node js server
- we are using using AWS CDK so its easy to deploy on AWS (other options are also good like serverless but i like AWS CDK )

So now as my previous problem are over we can use nestjs microservice to deploy on AWS 

### Build a simple Nest JS service 

Install the CLI globally using the npm install -g command (see the Note above for details about global installs).

```sh
$ npm install -g @nestjs/cli
```

Basic workflow#
Once installed, you can invoke CLI commands directly from your OS command line through the nest executable. See the available nest commands by entering the following:

```sh
$ nest --help
```

Get help on an individual command using the following construct. Substitute any command, like new, add, etc., where you see generate in the example below to get detailed help on that command:

```sh
$ nest generate --help
```

To create, build and run a new basic Nest project in development mode, go to the folder that should be the parent of your new project, and run the following commands:

```sh
$ nest new my-nest-project
$ cd my-nest-project
$ npm run start:dev
```

In your browser, open http://localhost:3000 to see the new application running. The app will automatically recompile and reload when you change any of the source files.


### Setup AWS account
If you do not have it already, signup for an AWS account.

Once an account is active, create a user with the AWS IAM service and get its access key and secret access key. When that information is available create a hidden folder called ‘.aws’ in your working directory with a file name ‘credentials’ and paste the below content. Save the file once done.

```sh
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_ACCESS_KEY
# In VS Code terminal of a Mac machine, the commands would be:
mkdir .aws
cd .aws
touch credentials
open .
```

We will use AWS CDK to deploy lambda 

With this configuration, Serverless will create the Lambda function main that will serve all the routes and methods of the API. so its like one service with different apis and one single Lambda

- The next step is to install a few dependencies:

`aws-serverless-express` : `This library enables you to utilize` AWS Lambda and Amazon API Gateway to respond to web and API requests using your existing Node.js
aws-lambda: AWS Lambda lets you run code without provisioning or managing servers.
serverless-plugin-typescript: Serverless plugin for Typescript support that works out of the box without the need to install any other compiler or plugins.
serverless-plugin-optimize: Plugin to transpile and minify your code
serverless-offline plugin: Plugin to be able to test your app offline.

```sh
npm install --save aws-serverless-express
npm install --save aws-lambda
npm install --save-dev serverless-plugin-typescript
npm install --save-dev serverless-plugin-optimize
npm install --save-dev serverless-offline plugin
```

Nest JS application is a simple Hello world app, you can add more REST APIs and can plan to deploy this to AWS using CDK 

now we need to modify nestjs service Code as we don't need http server it will be just a function 

```javascript
import { NestFactory } from "@nestjs/core";
import { ExpressAdapter } from "@nestjs/platform-express";
import { INestApplication } from "@nestjs/common";
import { AppModule } from "./app.module";
import { Express } from "express";

export async function createApp(
  expressApp: Express
): Promise<INestApplication> {
  const app = await NestFactory.create(
    AppModule,
    new ExpressAdapter(expressApp)
  );

  return app;
}

// async function bootstrap() {
//   const app = await NestFactory.create(AppModule);
//   await app.listen(3000);
// }
// bootstrap();

```

we have commented server lines here 
```javascript

// async function bootstrap() {
//   const app = await NestFactory.create(AppModule);
//   await app.listen(3000);
// }
// bootstrap();
```

We can create lambda.ts file and get app instance from main.ts

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vkmz0tgj3z81w1p9tpu8.png)

```javascript
import { Server } from "http";
import { Context } from "aws-lambda";
import { createServer, proxy, Response } from "aws-serverless-express";
import * as express from "express";
import { createApp } from "./src/main";

let cachedServer: Server;

async function bootstrap(): Promise<Server> {
  const expressApp = express();

  const app = await createApp(expressApp);
  await app.init();

  return createServer(expressApp);
}

export async function handler(event: any, context: Context): Promise<Response> {
  if (!cachedServer) {
    const server = await bootstrap();
    cachedServer = server;
  }

  return proxy(cachedServer, event, context, "PROMISE").promise;
}
```

Important part here is how we are adding lambda handler function and what handler function will do 
```javascript
export async function handler(event: any, context: Context): Promise<Response> {
  if (!cachedServer) {
    const server = await bootstrap();
    cachedServer = server;
  }

  return proxy(cachedServer, event, context, "PROMISE").promise;
}
```

Serverless need an entry point to compile the NestJS app to a lambda function. This entry point will be a handler object exported in the file lambda.ts. Create the lambda.ts file in the src folder of your application as shown below.

Remaining all code will be same 

```javascript
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wu0tymj7mvnr9o1tp5ru.png)
})
export class AppModule {}

```

### Deploying Lambda to AWS using CDK 

Now we just to deploy this lambda to AWS after setting up CDK 
AWS CDK code configuration can live is same code base, We have bin and lib folder 



we have created lambda Stack with construct
```javascript
// import { resolve } from "path";

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

export class CdkNestStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const lambdaLayer = new lambda.LayerVersion(this, "BackendLayer", {
      code: lambda.Code.fromAsset("lambda/api/node_modules"),
      compatibleRuntimes: [
        lambda.Runtime.NODEJS_12_X,
        lambda.Runtime.NODEJS_10_X,
      ],
    });

    const backendLambda = new lambda.Function(this, "BackendHandler", {
      runtime: lambda.Runtime.NODEJS_12_X,
      code: lambda.Code.fromAsset("lambda/api/dist"),
      handler: "index.handler",
      layers: [lambdaLayer],
      environment: {
        NODE_PATH: "$NODE_PATH:/opt",
      },
    });
    new gateway.LambdaRestApi(this, "BackendEndpoint", {
      handler: backendLambda,
    });
  }
}

```
Lets import our stack and create a stack for lambda

```javascript
#!/usr/bin/env node
import * as cdk from '@aws-cdk/core';
import { CdkNestStack } from '../lib/cdk-nest-stack';

const app = new cdk.App();
new CdkNestStack(app, 'CdkNestStack');

```
Now we can trigger basic CDK commands

```sh
cdk init
cdk synth 
cdk bootstrap 
cdk deploy
cdk destroy
```

cdk bootstrap : we must run this command before deploy, this is one time command to initialize platform before deployment
cdk deploy with provide user friendly interface and will expose all resources its creating
aws destroy - it will destroy resources created

### References 

- https://docs.nestjs.com/
- https://cdkworkshop.com/