# NestJS

## Introduction

* It is a framework for building efficient, scalable [Node.js](https://nodejs.org/) server-side applications.
* It provides the ecosystem of library, such as mongoose, ...
* It provides an out-of-the-box application architecture which allows developers and teams to create highly testable, scalable, loosely coupled, and easily maintainable applications. The architecture is heavily inspired by Angular. It effectively solve the main problem of - **Architecture**.
* It is built around the strong design pattern commonly known as **Dependency injection**.
* The dependencies injected can be used within the module
* Applied AOP design pattern into it, which is similar with spring boot

```typescript
constructor(private catsService: CatsService) {}
```

* Nest is able to work with any Node HTTP framework once an adapter is created. There are two HTTP platforms supported out-of-the-box: [express](https://expressjs.com/) and [fastify](https://www.fastify.io/).
* Whichever platform is used, it exposes its own application interface. These are seen respectively as `NestExpressApplication` and `NestFastifyApplication`.

  When you pass a type to the `NestFactory.create()` method, as in the example below, the `app` object will have methods available exclusively for that specific platform.&#x20;

```typescript
//express
const app = await NestFactory.create<NestExpressApplication>(AppModule);

// express - override version
const server = express();

server.set('query parser', (queryString) => {
  const qs = require('qs');
  return qs.parse(queryString, { 
    depth: 10,  // Increase depth limit from default 5
    arrayLimit: 100,  // Optional: increase array items limit
    parameterLimit: 2000  // Optional: increase parameter count limit
  });
});
const app = await NestFactory.create(
  AppModule, 
  new ExpressAdapter(server),
  { bufferLogs: true }
);

// fastify
const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter()
  );
```

## Module

### App Module

![](/files/4jaXFiK9ugs3LngJqVQR)

* Each application has at least one module, a app **module**.&#x20;
* The `AppModule` is the entry point for the application. When the NestJS application starts, it looks for the `AppModule` to initialize and configure the application. Nest uses to build the **application graph**
* For the module having controller should be imported into app module to ensures that the controllers are registered with the NestJS application and that their routes are accessible.

{% code title="main.ts" %}

```typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

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

{% endcode %}

{% code title="app.module.ts" %}

```typescript
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule {}
```

{% endcode %}

* It can be used to provide global guard, filter, interceptor

{% code title="app.module.ts" %}

```typescript
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core';
@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter,
    },
    {
      provide: APP_GUARD,
      useClass: StaartAuthGuard,
    },
    {
      provide: APP_INTERCEPTOR,
      useClass: AuditLogger,
    },
  ]
})
```

{% endcode %}

* There are 2 methods to define intercepter, guard globally&#x20;
* one is to apply in `main.ts` directly , the guard , intercepter class cannot inject other dependencies into it , since it is registered outside of any module

{% code title="main.ts" %}

```typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { RolesGuard } from './guards/roles.guard';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalGuards(new RolesGuard()); // Apply the guard globally
  await app.listen(3000);
}
bootstrap();
```

{% endcode %}

### Controller

![](/files/0u1s592QV92aNPE5tZYM)

* To handle and receive incoming HTTP requests and send responses to the client.
* Using this built-in method, when a request handler returns a JavaScript object or array, it will **automatically** be serialized to JSON. When it returns a JavaScript primitive type (e.g., `string`, `number`, `boolean`), however, Nest will send just the value without attempting to serialize it. This makes response handling simple: just return the value, and Nest takes care of the rest.
* We can use the library-specific (e.g., Express) [response object](https://expressjs.com/en/api.html#res), which can be injected using the `@Res()` decorator in the method handler signature (e.g., `findAll(@Res() response)`). With this approach, you have the ability to use the native response handling methods exposed by that object. For example, with Express, you can construct responses using code like `response.status(200).send()`.

### Provider

## ![](/files/iKzS6JExO33h1W48VuAO)

* Many of the basic Nest classes may be treated as a provider – services, repositories, factories, helpers, and so on. The main idea of a provider is that the class that can be **injected** as a dependency
* If A service want to get B Service from provider, and B service is also have the relationship with C Service,  C must be injected to A Service

```javascript
@Module({
  imports: [],
  controllers: [DogController],
  providers: [DogService, MouseService],
  exports: [DogService],
})
export class DogModule {}
```

```javascript
@Module({
   // choice 1
   // imports: [DogModule], // correct
  controllers: [CatController],
  // providers: [CatService, DogService], // incorrect
  // providers: [CatService, DogService, MouseService] // correct
  exports: [CatService],
})
export class CatModule {}
```

* For each time the class is injected by provider, the class will be instantiated for each time

### Import & Export

* Import is the list of imported modules that export the providers which are required in this module
* Export can the subset of provider or import of this module, so that other module can inject of the exported class after importing

```typescript
@Module({
  imports: [MouseModule, DragonModule],
  controllers: [DogController],
  providers: [DogService, TreeService],
  exports: [DogService, MouseMoudle],
})
export class DogModule {}
```

```typescript
@Module({
  imports: [DogModule],
  controllers: [CatController],
  providers: [CatService],
})
export class CatModule {}
```

* In the above example. the class included in dragon module and dog service can be injected into cat controller class, as dog module exported part included it and be imported
* However, the circular dependencies relationship should be prohibited, here is an example:&#x20;

```typescript
@Module({
  imports: [CatModule],
  controllers: [DogController],
  providers: [DogService],
  exports: [DogService],
})
export class DogModule {}
```

```typescript
@Module({
  imports: [DogModule],
  controllers: [CatController],
  providers: [CatService],
  exports: [CatService]
})
export class CatModule {}
```

* The service class injected from import, the class will only be instantiate for one time only in global level

## Middleware

### ![](/files/uk82gOlg9YK9WP4TkCa2)

Middleware is a function which is called **before** the route handler. Middleware functions have access to the [request](https://expressjs.com/en/4x/api.html#req) and [response](https://expressjs.com/en/4x/api.html#res) objects, and the `next()` middleware function in the application’s request-response cycle. The **next** middleware function is commonly denoted by a variable named `next`.

```typescript
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log('Request...');
    next();
  }
}
```

```typescript
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('cats');
  }
}
```

## Exception Filter

* Nest comes with a built-in exceptions layer which is responsible for processing all unhandled exceptions across an application. When an exception is not handled by your application code,
* It can help to customize the error response depend on the kind of exception thrown

```typescript
import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  BadRequestException,
} from '@nestjs/common';
import { Request, Response } from 'express';

@Catch(BadRequestException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
    });
  }
}
```

```typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './exceptionHandler/http-exception.filter';

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

## Pipe

* **transformation**: transform input data to the desired form (e.g., from string to integer)
* **validation**: evaluate input data and if valid, simply pass it through unchanged; otherwise, throw an exception

```typescript
@Controller('cat')
export class CatController {
  constructor(
  ) {}

  @Get(':id')
  pipeTest(@Param('id', OptionalIntPipe) id: any) {
    return id;
  }
}
```

```typescript
export class OptionalIntPipe implements PipeTransform {
  transform(value: string, metadata: ArgumentMetadata): number | undefined {
    if (!value) return undefined;
    const num = Number(value);
    if (isNaN(num))
      throw new BadRequestException(
        OPTIONAL_INT_PIPE_NUMBER.replace('$key', metadata.data),
      );
    return num;
  }
}
```

## Guard

* Guards have a single responsibility. They determine whether a given request will be handled by the route handler or not, depending on certain conditions (like permissions, roles, ACLs, etc.) present at run-time. This is often referred to as authorization
* Every guard must implement a `canActivate()` function. This function should return a boolean, indicating whether the current request is allowed or not.&#x20;
* The `canActivate()` function takes a single argument, the `ExecutionContext` instance. The `ExecutionContext` inherits from `ArgumentsHost. ArgumentsHost` simply acts as an abstraction over a handler's arguments. For example, for HTTP server applications (when `@nestjs/platform-express` is being used), the `host` object encapsulates Express's `[request, response, next]` array
* Guards have access to the ExecutionContext instance, and thus know exactly what's going to be executed next.
* Can be combined with decorator for authentication

```typescript
import { SetMetadata } from '@nestjs/common';

export const Scopes = (...scopes: string[]) => SetMetadata('scopes', scopes);
```

```typescript
@Injectable()
export class ScopesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const scopes = this.reflector.get<string[]>('scopes', context.getHandler());
    const request = context.switchToHttp().getRequest<UserRequest>();
    if (!scopes) return true;
    const user: AccessTokenParsed = request.user;
    let authorized = false;
    if (!user) return false;
    for (const userScope of user.scopes) {
      for (let scope of scopes) {
        for (const key in request.params)
          scope = scope.replace(`{${key}}`, request.params[key]);
        authorized = authorized || minimatch(scope, userScope);
        if (authorized) return true;
      }
    }
    return authorized;
  }
}
```

```typescript
@Module({
  providers: [{ provide: APP_GUARD, useClass: TestGuard }],
  imports: [CatModule, DogModule],
})
export class AppModule {}
```

## Interceptor

![](/files/W2BLLrKcIS1CLsPv9mAx)

* bind extra logic before / after method execution
* transform the result returned from a function
* transform the exception thrown from a function
* extend the basic function behavior

```typescript
import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';

@Injectable()
export class TestInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    console.log('Before...');

    const now = Date.now();
    return next
      .handle()
      .pipe(tap(() => console.log(`After... ${Date.now() - now}ms`)))
      .pipe(map((data) => ({ data })));
  }
}
```

```typescript
@Get(':id')
@UseInterceptors(TestInterceptor)
pipeTest(@Param('id', ParseIntPipe) id: any) {
  return id;
}
```

## Decorator

* A decorator is an expression which returns a function and can take a target, name and property descriptor as arguments.
* It can be mainly used for return data in a easier way

```javascript
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const User = createParamDecorator(
  (data: string, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    const user = request.user;

    return data ? user?.[data] : user;
  },
);
```

```javascript
@Get()
async findOne(@User('firstName') firstName: string) {
  console.log(`Hello ${firstName}`);
}
```

* It can be used to grouped different decorator together&#x20;

```javascript
import { applyDecorators } from '@nestjs/common';

export function Auth(...roles: Role[]) {
  return applyDecorators(
    SetMetadata('roles', roles),
    UseGuards(AuthGuard, RolesGuard),
    ApiBearerAuth(),
    ApiUnauthorizedResponse({ description: 'Unauthorized' }),
  );
}
```

## Sequence

* Incoming request&#x20;
* Globally bound middleware&#x20;
* Module bound middleware&#x20;
* Global guards&#x20;
* Controller guards&#x20;
* Route guards&#x20;
* Global interceptors (pre-controller)&#x20;
* Controller interceptors (pre-controller)&#x20;
* Route interceptors (pre-controller)&#x20;
* Global pipes&#x20;
* Controller pipes&#x20;
* Route pipes&#x20;
* Route parameter pipes&#x20;
* Controller (method handler)&#x20;
* Service (if exists)&#x20;
* Route interceptor (post-request)&#x20;
* Controller interceptor (post-request)&#x20;
* Global interceptor (post-request)&#x20;
* Exception filters (route, then controller, then global)&#x20;
* Server response

## Unit Test

```typescript
import { Injectable } from '@nestjs/common';
import { CatService } from 'src/cat/cat.service';
import { MouseService } from 'src/mouse/mouse.service';
import { PrismaService } from 'src/prisma/prisma.service';


@Injectable()
export class DogService {
  mouseService: MouseService;
  prismaService: PrismaService;
  catService: CatService;
  constructor(
    mouseService: MouseService,
    prismaService: PrismaService,
    catService: CatService,
  ) {
    this.mouseService = mouseService;
    this.prismaService = prismaService;
    this.catService = catService;
    console.log('init dog');
  }
  getCat(): string {
    return 'Cat';
  }
  getDog(): string {
    return 'dog';
  }
  getMouse(): string {
    return this.mouseService.getMouse();
  }
  async test(input: number) {
    return await this.mouseService.getNumber(input);
  }
  async prismaTest(input: number) {
    return await this.prismaService.user.delete({ where: { id: input } });
  }
}
```

```typescript
import { Test } from '@nestjs/testing';
import { ModuleMocker, MockFunctionMetadata } from 'jest-mock';
import { DogService } from './dog.service';
import { mockDeep, DeepMockProxy, any } from 'jest-mock-extended';
import { MouseService } from 'src/mouse/mouse.service';
import { PrismaService } from 'src/prisma/prisma.service';
import { User } from '@prisma/client';

const moduleMocker = new ModuleMocker(global);
let dogService: DogService;

describe('DogService', () => {
  let mouseService: DeepMockProxy<MouseService>;
  let prismaService: DeepMockProxy<PrismaService>;
  beforeEach(async () => {
    mouseService = mockDeep<MouseService>();
    prismaService = mockDeep<PrismaService>();
    const moduleRef = await Test.createTestingModule({
      providers: [
        DogService,
        { provide: MouseService, useValue: mouseService },
        { provide: PrismaService, useValue: prismaService },
      ],
    })
      .useMocker((token) => {
        if (typeof token === 'function') {
          const mockMetadata = moduleMocker.getMetadata(
            token,
          ) as MockFunctionMetadata<any, any>;
          const Mock = moduleMocker.generateFromMetadata(mockMetadata);
          return new Mock();
        }
      })
      .compile();

    dogService = moduleRef.get(DogService);
  });
  describe('test', () => {
    it('/test', () => {
      mouseService.getNumber.calledWith(1).mockResolvedValue(1);
      expect(dogService.test(1)).resolves.toBe(1);
    });
  });

  describe('prismaTest', () => {
    it('/test', () => {
      const deletedUser = { id: 1 };
      prismaService.user.delete
        .calledWith(any())
        .mockResolvedValue(deletedUser as User);
      expect(prismaService.user.delete({ where: { id: 1 } })).resolves.toEqual(
        deletedUser,
      );
      expect(dogService.prismaTest(1)).resolves.toBe(deletedUser);
    });
  });
});
```

* The `Test` class is useful for providing an application execution context that essentially mocks the full Nest runtime, but gives you hooks that make it easy to manage class instances, including mocking and overriding.&#x20;
* Nest also allows you to define a mock factory to apply to all of your missing dependencies. This is useful for cases where you have a large number of dependencies in a class and mocking all of them will take a long time and a lot of setup. To make use of this feature, the `createTestingModule()` will need to be chained up with the `useMocker()` method, passing a factory for your dependency mocks.
* Jest-mock-extended provides complete Typescript type safety for interfaces, argument types and return types. If your class has objects returns from methods that you would also like to mock, you can use `mockDeep` in replacement for mock.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://petercheng7788.gitbook.io/developer-note/backend/nodejs/nestjs.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
