Nestjs🐺⚡ | The framework of Nodejs (Part-2) | Modules, Circular Dependency, Guards
Tags: javascript, typescript, webdev, tutorial
Published: 2021-08-14 13:38:16

> If you haven't read the [part-1](https://dev.to/krtirtho/nestjs-the-framework-of-nodejs-part-1-gl7), please first read that else you'll feel this given information is out of context

In Part-2, I'll be discussing Nestjs Modules, Circular Dependency, Guards

### 1. Modules

In part-1, there was a smidge description of modules. Modules in Nestjs aren't global instead it has depth. But can be shared across any other modules too. Though it supports Global Module like Angular, it is more recommended to keep Services/Controllers in the module where they're mostly used in Nestjs

Most of the time modules will be generated through the NestCLI & providers/controllers generated in that module's context will get automatically added by the CLI. These are called *feature modules*

Here's a module example:

```tsx
////// hi.module.ts //////
import {Module} from "@nestjs/common"
import HiService from "./hi.service";
import HiController from "hi.controller";

@Module({
  providers: [HiService],
  controllers: [HiController],
  exports: [HiService]
})
export class HiModule{
}

////// hello.module.ts//////
import {Module} from "@nestjs/common"
import HelloService from "./hello.service";
import HelloController from "hello.controller";
import HiModule from "../hi/hi.module"

@Module({
	imports: [HiModule],
  providers: [HelloService],
  controllers: [HelloController],
  exports: [HelloService]
})
export class HelloModule{
}
```

The `@Module` decorator's `controllers` array-property is used for all the *controllers* that the module uses or all the classes decorated with the `@Controller` decorator. The `providers` property is used for `service` or classes that are decorated with an `@Injectable` decorator. Remember, anything *Injectable* is a provider & you've to put it in `providers` field to be able to inject/use it.

The `exports` property is used to export/expose the providers that can be shared with other modules. Put any providers that you want to inject/use in other modules

The `imports` property is the exact opposite of `exports`. To be able to use/inject any external providers in a provider/controller of another module, you've to add that exported provider's module in the `imports` field of another module

### 2. Circular Dependency

Often times you want to use a provider in another module's provider & another modules' provider in that provider/controller. In this case, it creates a circular dependency. Circular dependencies can arise in Nest between modules and between providers. One should always try best to avoid Circular Dependency in Nestjs but sometimes it's not possible. In this case, `forwardRef`  & `@Inject` parameter decorator comes handy for providers which are within the same module context

Example of using `forwardRef` accross providers from same module to resolve circular dependency:

```tsx
///// bye.service.ts /////
import { forwardRef, Inject, Injectable } from '@nestjs/common';
import { HelloService } from './hello.service';

@Injectable()
export class ByeService {
  constructor(
		// injecting HelloService
    @Inject(forwardRef(() => HelloService))
    private helloService: HelloService,
  ) {}

  getBye(arg: string) {
    return `bye bye, ${arg}`;
  }

	// it uses `helloService` & is within same module
  helloServiceUsingMethod() {
    return this.helloService.getHello('bye');
  }
}

///// hello.service.ts /////
import { forwardRef, Inject, Injectable } from '@nestjs/common';
import { ByeService } from './bye.service';

@Injectable()
export class HelloService {
	// ...other stuff

  constructor(
		// injecting ByeService
    @Inject(forwardRef(() => ByeService))
    private byeService: ByeService,
  ) {}

  getHello(arg: string) {
    return `hello for ${arg}`;
  }

  byeServiceUsingMethod() {
    return this.byeService.getBye('hello');
  }

	// ....other stuff
}
```

Let's add newly created `ByeService` in */hello* module or `HelloModule`'s `providers` field

```tsx
////// hello.module.ts //////
// import stuff
import {ByeService} from "./bye.service"

@Module({
  providers: [HelloService, ByeService], // new bye-service added
  controllers: [HelloController],
  exports: [HelloService]
})
export class HelloModule{
}
```

Now, what about providers that are from the external modules? No worries, just do like above for the providers & just use `forwardRef` in the `imports` field of both modules to import each other's providers in their context

Example of forwarding ref of external providers across modules:

```tsx
////// hi.module.ts //////
import { forwardRef, Module } from '@nestjs/common';
import HiService from "./hi.service";
import HiController from "hi.controller";
import HelloModule from "../hello/hello.module";

@Module({
  imports: [forwardRef(() => HelloModule)], // importing HelloMoule using forwardRef
  providers: [HiService],
  controllers: [HiController],
  exports: [HiService] // exporting hi-service for using in hello-service
})
export class HiModule{
}

////// hello.module.ts//////
import {Module, forwardRef} from "@nestjs/common"
import HelloService from "./hello.service";
import HelloController from "hello.controller";
import HiModule from "../hi/hi.module";
import ByeService from "./bye.service";

@Module({
	imports: [forwardRef(() => HiModule)],
  providers: [HelloService, ByeService],
  controllers: [HelloController],
  exports: [HelloService] // exporting hello-service for using in hi-service
})
export class HelloModule{
}
```

Now that both module's providers are available in each other's scope, let's use `forwardRef` in their providers `HelloService` & `HiService` to resolve their circular dependence:

```tsx
///// hello.service.ts //////
import {Injectable, Inject, forwardRef} from "@nestjs/common"
import HiService from "../hi/hi.service"

@Injectable()
export class HelloService{
  // .... other properties/methods

	constructor(
		// just like provider-scoped circular dependency
		@Inject(forwardRef(()=>HiService))
		private hiService: HiService
	 ){
	}

	getHello(arg: string){
		return `hello for ${arg}`
	}

	// a method that uses `hiService`
  hiServiceUsingMethod(){
		return this.hiService.getHi("hello");
  }
  // .... other properties/methods
}

///// hi.service.ts /////
import {Injectable, Inject, forwardRef} from "@nestjs/common"
import HelloService from "../hello/hello.service"

@Injectable()
export class HelloService{
  // .... other properties/methods

	constructor(
		@Inject(forwardRef(()=>HelloService)) private helloService: HelloService
	 ){
	}

	getHi(arg: string){
		return `hi for ${arg}`
	}

	// a method that uses `helloService`
  helloServiceUsingMethod(){
		return this.helloService.getHello("hi");
  }
  // .... other properties/methods
}
```

> Make sure your code does not depend on which constructor is called first as the order of instantiation of these provider classes are indeterminate

> There's an advanced alternative to `forwardRef`. The `ModuleRef` class is provided from `@nestjs/core` for dynamically instantiating both static and scoped providers. It can be mainly used to navigate the internal list of providers and obtain a reference to any provider using its injection token as a lookup key. `ModuleRef` can be injected into a class in the normal way. Learn more about `[ModuleRef](https://docs.nestjs.com/fundamentals/module-ref)`

### 3. Guards

According to Nestjs docs, Guards have a *single responsibility.* It's their job to determine if a request will be handled by the controller or not depending on certain conditions (Specifically user-defined logic). It's useful for authentication/authorization & is the recommended way to handle authentication/authorization in Nestjs. Though authentication/permissions etc.. can be done with `middleware` & is done in express or other HTTP servers as these don't have connected strong context & need no reason to know about which method will be used to handle the request. Middlewares only have the `next` function, nothing else thus it's kinda dumb for Nestjs. But Guards have access to the execution context. It's designed more like exception filters, pipes & interceptors.

> Guards are executed after each middleware but before any interceptor or pipe

Guards are a kind of provider as its class also needs to be annotated with `@Injectable` decorator but it has to implement interface `CanActivate` or provide the method `canActivate` in case of JS

> Most of the time authentication will be handled using `passport` or similar libraries. And Nestjs docs has an explanation of how to use `passport` to make a *Authentication flow* in Nestjs [here](https://docs.nestjs.com/security/authentication). Here, this `AuthGuard` is usable but not production safe. Just using it for demonstration purpose

Example of an `AuthGaurd`:

```tsx
////// auth.guard.ts /////

import { Injectable, CanActivate, ExecutionContext, Logger } from '@nestjs/common';
import { Observable } from 'rxjs';

function validateToken(token: string): boolean{
	return true
}

@Injectable()
export class AuthGuard implements CanActivate {
	logger: Logger = new Logger(AuthGuard.name)  

  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
		try{
		  // gives access to the express/fastify request object
	    const request = context.switchToHttp().getRequest();
			// jwt/any kind of token
	    const token = request?.hearders?.["Authorization"]?.split(" ")[1]
			if(!token)return false; // no token no entry

		  return validateToken(token)
		}
		catch(e){
			this.logger.error(e)
			return false
		}
  }
}
```

Just like exception-filter/pipes you can use Guards in *method-scope/controller-scope* using `@UseGaurds()` decorator. It can take any amount of Guards as its arguments

method-scoped Guard example:

```tsx
////// hello.controller.ts ///////
// ... import stuff
import {UseGuards} from "@nestjs/commmon"
import {AuthGuard} from "../../guards/auth.guard"

@Controller()
export class HelloController{
  // ..... other stuff
 
	@Get("/restricted-data")
	@UseGuards(AuthGuard)      // or pass it already being instantated as `new AuthGuard()`                             
	async getRestrictedData(){ // if it doesn't require dependency injection
		// ... logic
		return {};
	}

	// ..... other stuff
}
```

> BTW, you can assign new properties to the `request` object in the Guard & can access it through `@Req()` parameter-decorator in any Controller route handler such as `getRestrictedData` in `HelloController`

Just like pipes/exception-filters, you can use Guards globally with the app's `useGlobalGaurds` method. Then no need to use `@UseGaurds()` for each controller/handler that requires that Guard

Example of global guards:

```tsx
///// main.ts /////
// ...import stuff
import {AuthGuard} from "./guards/auth.guard"

async function bootstrap(){
	// ...other stuff

	app.useGlobalGuards(new AuthGuard())

	// ...other stuff
}

bootstrap()
```

But it'll throw an error if you're using/injecting other providers inside that Guard. But if you want to keep both dependency-injection & global scope then providing it through global `AppModule` &  then setting it as a global guard will work

DI capable Global Guard:

```tsx
///// app.module.ts //////
// ...import other stuff
import {AuthGuard} from "./guards/auth.guard"

// unique key/id for selecting the gaurd from within the NestFactory instance
export const AUTH_GUARD = "unqiue-auth-guard";

@Module({
  // ...other stuff

	providers: [
		AppService,
		{provide: AUTH_GUARD, useClass: AuthGuard}
	],

  // ...other stuff
})
export class AppModule{
}

///// main.ts /////
// ...import stuff
import {AUTH_GUARD} from "./app.module";

async function bootstrap(){
	// ...other stuff

	const authGuard = app.select(AppModule).get(AUTH_GUARD)

	app.useGlobalGuards(authGuard);

	// ...other stuff
}

bootstrap()
```

Now, there another problem arises. How will one make a route public/unrestricted from this Guard? This is where the `Reflector` comes in handy. It's a special class provided by `@nestjs/core` that can be accessed in any *module-scoped* providers/controllers or simply, in any controller/provider/guard/exception-filter/interceptor/pipe that isn't instantiated globally

With `Reflector`, `@SetMetadata()` decorator & *custom-decorator* we can simply handle this case

`@SetMetadata()` is a both method & class decorator provided by `@nestjs/common` & can be used to set special `key-value metadata` for a method/class & this can be accessed through the `Reflector` that is injected in every `@Injectable()` & `@Controller()` available in `AppModule`'s context

Custom Decorator example:

```tsx
///// public.decorator.ts /////

import { SetMetadata } from "@nestjs/common";

export const IS_PUBLIC_KEY = "THIS_ROUTE_IS_PUBLIC"

// decorators are functions inside function with access to extra metadata provided 
// by the JSVM (JavaScript Interpreter). So you can ovbiously call 
// a decorator in a function like normal functions but just remember to `return` it to
// let the decorator's inner function to access those metadata about the class/method/parameter/property
// its currently being applied to
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);

// the decorator flow-> `Public` is a function which returns & calls `SetMetadata`
// function which also returns & calls an inner function within it. Its called
// **function-currying**
// More on Wikipedia: https://en.wikipedia.org/wiki/Currying
```

Now in `AuthGuard`'s `canActivate` method lets get the metadata of currently active class/method in context:

```tsx
////// auth.guard.ts /////
// ...import stuff
import { Reflector } from "@nestjs/core";
import {IS_PUBLIC_KEY} from "./decorators/public.decorator"

@Injectable()
export class AuthGuard implements CanActivate {
		// ...other stuff

		// just add the Reflector as a type
	constructor(private readonly reflector: Reflector){}

  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
		try{
			// accessing the passed metadata with its unique key/id
			// within the current execution context
			const isPublic = this.reflector.getAllAndOverride<boolean>(
						IS_PUBLIC_KEY,
						[
              context.getHandler(),
              context.getClass(),
			      ]
					);
			if(isPublic) return true;

		  // ... other validation logic/stuff
		}
		catch(e){
			this.logger.error(e)
			return false
		}
  }
}
```

Now we only have the job to apply the custom `@Public()` method/class decorator in a route to make it *unrestricted.* If you've read **part-1** then you know that `HelloController` (created in part-1) has a GET /hello route that responds with hello on request. But for the `AuthGuard`, that route will be restricted. But what in the world should make someone not getting *a warm hello*?!. So let's make it open to everyone:

```tsx
////// hello.controller.ts ///////
// ... import stuff
import {Public} from "../decorators/public.decorator"

@Controller()
export class HelloController{
  // ..... other stuff
 
	@Get("hello")
  @Public() // now everyone gets a hello ;)
	async replyHello(){
		// ... logic
	}

	// ..... other stuff
}
```

Here's the complete application with today's update

{% codesandbox hello-world-forked-7xkln %}

After update, All the routes except `/hello` will return

```json
{"statusCode": 403,"message": "Forbidden resource", "error": "Forbidden"}
```

Providing any jwt-token in this `Bearer <token>` format with request-header's  `Authorization` field will make the protected routes work for now