NestJS draft

Last modified 4 months ago / Edit on Github
draft
This is a draft, the content is not complete and of poor quality!

This note depends heavily on my personal experience when I was working with Angular and NestJs for some specific projects and settings. You shouldn't consider it as a good reference.

👉 Official NestJS documentation.

Key concepts

👇 Copied (mostly) from this source.

  • Modules -- Modules encapsulate logic into reusable pieces of code (components).

    // app.module.ts
    @Module({
    imports: [], // Other modules
    controllers: [], // REST controllers
    providers: [], // Services, Pipes, Guards, etc
    })
    export class AppModule {}
  • Controllers -- Used to handle REST operations (HTTP methods).

    // Request to http://endpoint/users/<userId>/hi

    @Controller('users') // Decorator indicating that the following TypeScript class is a REST controller
    export class AppController {
    constructor(
    private readonly appService: AppService // Service available through Dependency Injection
    ) {}

    @Get('/:id/hi') // HTTP method handler
    sayHi(@Param('id') userId: string): string {
    return this.appService.sayHi(userId); // Calling a service method
    }
    }
  • Providers

    • Services -- Services are used to handle logic and functionality. Service methods are called from within a controller.

      // app.service.ts
      @Injectable() // Decorator that marks a TypeScript class a provider (service)
      export class AppService {
      constructor() {} // Other services, repositories, can use Dependency Injection
      sayHi(userId: string): string {
      return `Hello ${userId}`; // Plain functionality
      }
      }
    • Dependency injection -- borrow the idea from Angular.

Side notes

  • users.repository.ts: file will contain the code that interacts with your database.
  • users.factory.ts: used to create an instance of service (eg. users.service.ts). For example, we need the name and id of that user throughout the UsersService, we cannot input them for every methods inside this service. With the factory, we can input them once!

Controllers

Headers

👉 Official example.

A simple example
// FRONT (Angular)
import { HttpClient, HttpHeaders } from '@angular/common/http';
export class LexiconService {
constructor(private httpClient: HttpClient) {}
public getUserName(userId: string, credentials: any): Promise<string> {
const encodedPrivateKey = Buffer.from(credentials.private_key, 'ascii').toString('base64');
return this.httpClient
.get(`${endpointBack}/users/get-name/${userId}`, {
headers: new HttpHeaders({
'client-email': String(credentials.client_email),
'private-key': encodedPrivateKey
})
})
.toPromise();
}
}
// BACK
@Controller('users')
export class UsersController {
constructor() {}

@Get('get-name/:user-id')
getUserName(
@Headers('private-key') privateKey?: string,
@Headers('client-email') clientEmail?: string
): void {
const decodedPrivateKey = Buffer.from(privateKey, 'base64').toString('ascii');
const credentials: UserCredentials = new UserCredentials({
private_key: decodedPrivateKey,
client_email: clientEmail
});
}
}

Some remarks,

// Using lowercase
@Header('my-id') id: string // instead of `My-Id`
// Debug
import { Headers } from '@nestjs/common';
...
@Put('/')
public async put(@Headers() headers) {
console.log(headers);
}

Error handling

👉 Built-in HTTP exceptions | Nest Docs.
👉 HTTP response status codes | MDN Docs.
👉 Status codes and their use in gRPC | GRPC Core.
👉 Handling Errors (with gRPC Mapping) | Google Cloud Docs.

🎯 What we want (also an example): From the error of an external service (Dialogflow, for example) > Mapping to a HTTP Status > Send it back to the front > Handle it on the front.

Show snippets
import { HttpException } from '@nestjs/common';

// From some service
export class SomeService {
async simpleFunction(): Promise<any> {
return this.client.method(params)
.then(response => response)
.catch(err => Promise.reject(new HttpException(err)));
}
}
// In the controller
import { SomeService } from './some.service.ts';
import { Response } from 'express';

@Controller('endpoint')
export class SomeController {
constructor(private someService: SomeService) {}

@Get('/abc/xyz')
async someFunc(@Res() res: Response): Promise<void> {
...
this.someService.simpleFunction()
.then(response => res.status(200).json(response))
.catch(err => res.status(err.status || 500).json(err));
}
}
// On front (Angular)
getFunction(): Promise<any> {
return this.httpClient.get(`path/to/back/endpoint`, { headers, params })
.catch(err => Promise.reject(err));
}

Using Next of Express

👉 Error handling | ExpressJS

// Very simple of using .catch(next)
import { NextFunction, Response } from 'express';

@Controller('endpoint')
export class SomeController {
constructor(private someService: SomeService) {}

@Get('/abc/xyz')
async someFunc(@Res() res: Response, @Next() next: NextFunction): Promise<void> {
...
this.someService.simpleFunction()
.then(response => res.status(200).json(response))
.catch(next);
}
}
Support Thi Support Thi