Nestjs🐺⚡ | The framework of Nodejs (Part-1) | Controllers, ExceptionFilters, Providers
Tags: javascript, typescript, webdev, tutorial
Published: 2021-08-08 07:36:51

Nestjs is a server-side framework often confused  with the term "Server-Side Angular"

Even though Nest follows the pattern & design principals of Google's Angular but its significantly different than Angular by design

> Nestjs is a abstraction layer over traditional nodejs server-side tools & packages

So please don't compare it with http-servers such as: express, koa, fastify, hapi etc.. Nestjs actually uses express & fastify as its platform for http server

Nestjs centralizes all the needed technologies/tools to build perfect, reliable & durable enterprise servers using Nodejs. Its in the league of Django, Spring Boot, Ruby on Rails etc.. server-side frameworks

It follows micro-services architecture but can be used for monolithic servers too

Features of Nestjs: (source: https://docs.nestjs.com)

- Extensible, Reliable, Versatile, Progressive framework
- Offers clean, straight forward & understandable architecture
- Offers out of the box:
    - Dependency Injection,
    - Routing with decorators using Controllers
    - Security with `helmet`, `cors` , `node-csrf`
    - Exception filters (unhandled exception layer)
    - Guards
    - Separation of logic from controllers using Providers
    - Robust Module system
    - Lifecycle events & many more
    - unit-testing & integration-testing support with `jest` & `super-test`
- It provides/supports (through packages):
    - http-server (express/fastify)
    - GraphQL server
    - websocket server (socket.io/ws)
    - database orm (sequelize/mongoose/typeorm/knex/prism)
    - request body validation using `class-validator`
    - caching using `cache-manager`
    - task-scheduling using `cron`
    - task queue using `bull` & many more other tools

> This is not a complete tutorial. If you want to learn Nestjs completely visit https://docs.nestjs.com. It contains complete details about Nestjs

All of the names & technical terms might feel over whelming but these are pretty easy to implement. Some of 'em take 5-10 lines of code only to implement. But each of them are equally important for a enterprise server or a server with smaller user-base. Nestjs covers the architecture & the dependencies for us

A fact, Nestjs actually helps & guides us as a new backend developer towards all important tools along being used as a tool

Nestjs also has a powerful cli, named `@nestjs/cli`. It helps manipulating files/modules. Its kinda like Angluar's CLI but only handles files & modules. It helps you organizing your project more efficiently

> I'll be doing a 3 parts of Nestjs tutorial.  In part-1 or this part, I'll cover about only `Controllers`, `ExceptionFilters` & `Providers`

But first lets create the project using:

```bash
$ npm install -g @nestjs/cli
$ nest new hello-world && cd hello-world
$ npm run start:dev
```

This will create a directory structure of following:

```
hello-world/
├── src/
│   ├── app.controller.ts
│   ├── app.controller.spec.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   ├── app.service.spec.ts
│   └── main.ts
├── test/
│   ├── app.e2e-spec.ts
│   └── jest.e2e.json
├── .gitignore
├── .eslintrc.js
├── .prettierrc
├── README.md
├── nest-cli.json
├── package.json
├── package-lock.json
├── tsconfig.build.json
└── tsconfig.json
```

Now lets create a directory `hello` inside `src` & inside `hello` create 4 files for this tutorial

- `hello.controller.ts`
- `hello.module.ts`
- `hello.service.ts`
- `hello-body.dto.ts`

### 1. Controllers

Controllers are Nest's building block. These are where one will handle incoming request. You can define the route path with http method modifiers (Get, Post, Put, Delete etc..) decorators

Controller example:

```tsx
// hello.controller.ts

import {Controller, Logger, Get, NotFoundException, Param} from "@nestjs/common"

@Controller()
export class HelloController{
		/* a logger from nestjs for logging error/other info */
    logger: Logger = new Logger(HelloController.name)
    db: {id: string, message: string}[] = []; // temporary database

    @Get("hello")
    async replyHello() {
        try {
            return "Hello";
        } catch (error) {
            this.logger.error(error?.message ?? "");
            throw error;
        }
    }

    @Get("hello/:helloId") // dyanmic parameter just like express, koa-router etc...
		async replyExactHello(
           /*pass the same dynamic parameter from "hello/:helloId" in 
             @Param decorator's first to let nestjs find the parameter
             correctly
            */
           @Param("helloId") id: string
        ) {
        try {
            /*returning the correct temp hello message*/
            const message = this.db.find(hello=>hello.id===id)?.message
            if(!message) throw new NotFoundException("desired `hello` not found") //404 error
            return message;
        } catch (error) {
            /* will log the error & autmatically send the error as response with all required data */
            this.logger.error(error?.message ?? "");
            throw error;
        }
    }
}
```

Nestjs uses decorator pattern & its primarily written in *Typescript* but *it supports JavaScript too.*  You can also perform validation on request-body using `class-validator`

```tsx
////// main.ts //////
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./hello.module";
import { ValidationPipe } from "@nestjs/common";

async function bootstrap() {
    /* Creates a nest application for monolithic servers */
    const app = await NestFactory.create(AppModule, { logger: false });

    // validation is done through Nestjs pipes. 
    // Nestjs Pipes run before a specified request (kinda like middlewre)
    /* Enabling Validation pipe globally.
       Thoough it can be done in module level too
		*/
    app.useGlobalPipes(new ValidationPipe());
    await app.listen(PORT);
}
bootstrap()

```

Here I'm just creating a Nestjs server instance & adding `ValidatonPipe` globally. Pipes are just methods that run before Controllers. Pipes can be used at method/argument level also using `@UsePipes` decorator. You can even create your own custom Pipes. Also you might've noticed `AppModule` . It's the main point of Nestjs for making all the things work. You'l find more about `AppModule` after Exception Filters section

 Now lets create a body validation Schema with `class-validator` & decorators

```tsx
////// hello-body.dto.ts //////
import {IsDefined, IsNotEmpty} from "class-validator"

export class HelloBodyDTO{
  @IsDefined()
  @IsNotEmpty({message: "A custom error message if you want to"})
	message!: string;
}
```

`@IsDefined` & `@IsNotEmpty` will validate a string which is defined & at least has a length of 1 or in other words the string shouldn't be just `""` . Now lets use this one in a `@Post` request controller:

```tsx
////// hello.controller.ts //////
import {Controller, Logger, Get, NotFoundException, Post, Body} from "@nestjs/common"
import {HelloBodyDTO} from "./hello-body.dto"
import {v4 as uuid} from "uuid"

@Controller()
export class HelloController{
  // ... previously written stuff from the `Controller` part

  // decorator name is similar to http verbs e.g. POST -> @Post
  @Post("hello")
	saveHello(
		/*Just pass the class as a type & the validation will be done automatically*/
		@Body() body: HelloBodyDTO
	){
		try{
      const id = uuid()
			const hello = {id, message: body.message}
			this.db.push(hello) // saving in the temp db
			return hello;
		}
		catch (error){
				this.logger.error(error?.message ?? "");
        throw error;
		}
	}
}

```

### 2. Exception Filters

> **Exception filters** are error handlers that runs when a Controller throws error. It handles that error automatically & sends appropriate, user-friendly error response

If you've followed the code you might've got a hint that Nestjs uses a `HttpExceptionFilter` by default (globally) . The package `@nestjs/common` provides many `HttpException`  inherited Exceptions e.g. `NotFoundException` , `BadRequestException`, `NotAcceptableException` , `UnauthorizedException` and many more. You can even create your very own custom `ExceptionFilter`

[Learn how to create a custom ExceptionFilter](https://docs.nestjs.com/exception-filters#exception-filters-1)

If you want to use a custom exception filter in a route handler, you've to use `@UseFilter` decorator

```tsx
// ... other stuff
import {ForbiddenException} from "@nestjs/common"
import {CustomHttpExceptionFilter} from "./custom-filter"

// a simple handler method inside a Controller
@Post("throw-error")
@UseFilters(new CustomHttpExceptionFilter())
errorThrowingHandler(){
	throw new ForbiddenException("its forbidden");
}
// ... other stuff
```

Using this long code  `@UseFilters(new HttpExceptionFilter())` before every handler/controller can't be hard but if your application has a usecase for using it globally then you just have to use `useGlobalFilters` of Nestjs server instance & pass all the global filters as parameters

```tsx
///// main.ts /////

// ...other stuff
import {CustomHttpExceptionFilter} from "./custom-filter"

app.useGlobalFilters(new CustomHttpExceptionFilter())
// ...other stuff
```

### 3. Providers

Providers are another essential part of Nestjs. By far, I was using a temporary variable to store data. That's why such simple thing can be done through Controller handlers. But for bigger, complex logic, it'd be hard to do code separation & reuse. That's where providers comes to play....

You can declare/create a provider using the `@Injectable` decorator on top of a class. Then Dependency injection/Logging etc can be done through providers

Here's a provider example. I'm using a custom variable as a database for ease of understanding. But most of the time `create`, `find`, `findById`, `delete`, `deleteById` etc are provided by the database ORM. So in real-world scenarios these methods aren't needed to be implemented in Providers. Providers should be used for handling more complex logic. But for demonstration lets think these methods as complex logic

```tsx
////// hello.service.ts ///////

import { Injectable } from "@nestjs/common"
import {v4 as uuid} from "uuid"

@Injectable()
export class HelloService{
  db: {id: string, message: string}[] = []

  async findById(id: string){
		return this.db.find(hello=>hello.id===id)
  }

  async create(message: string){
		const id = uuid()
		const hello = {id, message}
		this.db.push(hello)
		return hello;
  }

  async deleteById(id: string){
		this.db = this.db.filter(hello=>hello.id!==id)
    return `DELETED node ${id} from db`
  }
}
```

Now, lets convert the `HelloController` for using `HelloService` through Dependency Injection. But before we've to put `HelloService` inside the `HelloModule`

> A module is a class annotated with a `@Module()` decorator. The `@Module()` decorator provides metadata that Nest makes use of to organize the application structure. Each application has at least one module, **a root module**. The root module is the starting point Nest uses to build the application graph - the internal data structure Nest uses to resolve module and provider relationships and dependencies

That module is the main thing that helps Nest making the dependency graph for Dependency Injection. Example of an `app.module.ts` :

```tsx
////// app.module.ts //////
import { Module } from '@nestjs/common';
/*This is the base '/' controller */
import { AppController } from './app.controller';
/* basic provider for AppController */
import { AppService } from './app.service';

@Module({
  /*this where descendent modules get added
			we've to do this if we were importing another inside
			an other module to be able to use its providers
     */
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```

We've to add every providers (`Injectable`)/controllers that we use inside our controller/provider in a module. Lets put `HelloService` & `HelloController` in `HelloModule`:

```tsx
////// hello.module.ts //////
import {Module} from "@nestjs/common"
import {HelloService} from "./hello.service"
import {HelloController} from "./hello.controller"

@Module({
  /* put all providers that is under this module graph to help Nest to
		 inject those in the controllers
  */
	providers: [HelloService],
  /* put controllers here for letting Nest recognize all the route/path &
     their handlers
	*/
  controllers: [HelloController],
  /*put those providers which you wanna use outside of this module
    In an outside module when HelloModule gets imported
  */
  exports: []
})
export class HelloModule{}
```

To let Nest recognize `HelloModule`  as module, lets add `HelloModule` inside the `imports` array of `AppModule`:

```tsx
///// app.module.ts //////
// ... previously imported stuff
import {HelloModule} from "./hello/hello.module"

@Module({
    imports: [HelloModule],
    // ... other properties previously added
})
export class AppModule {}
```

> And this `AppModule` is used as the entrypoint of `NestFactory` instance in `main.ts`

Now we can easily use `HelloService`  inside `HelloController` or in other Module's controllers/providers

```tsx
////// hello.controller.ts //////
// ... previously imported stuff
import {HelloService} from "./hello.service"

@Controller()
export class HelloController{

    logger: Logger = new Logger(HelloController.name)

    /* just create a contructor arg and set the type as the provider
			 & that's gonna do the work
		 */
    constructor(private readonly helloService: HelloService){}

    @Get("hello")
    async replyHello() {
        try {
            return "Hello";
        } catch (error) {
            this.logger.error(error?.message ?? "");
            throw error;
        }
    }

    @Get("hello/:helloId")
		async replyExactHello(@Param("helloId") id: string) {
        try {
            /*using provider's methods*/
            const message = await this.helloService.find(id)?.message;
						if(!message) throw new NotFoundException("desired `hello` not found") //404 error
            return message;
        } catch (error) {
            this.logger.error(error?.message ?? "");
            throw error;
        }
    }
  

	  @Post("hello")
		saveHello(@Body() body: HelloBodyDTO){
			try{
        /* creating `hello` using the provider HelloService */
				return await this.helloService.create(body.message)
			}
			catch (error){
				this.logger.error(error?.message ?? "");
        throw error;
			}
		}
}
```

Don't be afraid of Nestjs's Module system. Its hard for the first time but once you get the idea, it all makes sense & this module system is required for Nestjs to do all those cool Dependecy Injection.

BTW, you don't have to add providers/controllers manually in the Module. If you create modules/providers/controller using the **nest-cli,** it'll be done automatically. Above mentioned Module managing steps can be done automatically just by using these 3 commands

create a **module**:

```bash
$ nest g module hello
```

create a **controller**:

```bash
$ nest g controller hello
```

create a **provider**:

```bash
$ nest g provider hello
```

Please don't hurt me😶. I know, I should've shown this easier way earlier😁. But that idea of how module works in Nestjs often troubles people to not use Nestjs. So its important to getting the deep insight of it. You can take deep insight of Nestjs Module system [here](https://docs.nestjs.com/modules)

Here's the complete application

{% codesandbox hello-world-rj3u4 %}