NestJs – Framework backend cho Nodejs

NestJs – Framework backend cho Nodejs

Giới thiệu

Nest (NestJS) là một framework hỗ trợ người dùng xây dựng các ứng dụng node server-side một cách hiệu quả và dễ dàng mở rộng. Nest được hỗ trợ sử dụng với Typescript và cả Javascript thuần và có đầy đủ các tính chất của:

  1. OOP (Lập trình hướng đối tượng),
  2. FP (Lập trình chức năng), và
  3. FRP (Lập trình phản ứng chức năng).

Tại sao chọn NestJS trong số nhiều framework NodeJS khác ? Theo số liệu trên GitHub, tính đến tháng 7 năm 2020, Nest được khá cao số lượt yêu thích. Nhờ sự phát triển của JavaScript như một ngôn ngữ lập trình phát triển web, rất nhiều Javascript/Nodejs framework đã ra đời. Và Nest không phải là một ngoại lệ. Với rất nhiều tính năng tối ưu, NestJS có thể giúp các nhà phát triển tạo ra các ứng dụng phía backend, API RESTful một cách dễ dàng và hiệu quả.

*** Số liệu trên stateofjs.com năm 2019 về các Javascript framework được nhiều người sử dụng. Ngoài các framework được ưa chuộng nhất hiện nay như: Express, Next.js, Koa, Meteor, Sails, Feathers, Nuxt, Gatsby, Nest cũng là một trong những framework được sử dụng ngày càng nhiều, xếp trên nhiều framework khác.

Credit: stateofjs.com

 

Cài đặt và tạo ứng dụng NestJS mới.

Vui lòng đảm bảo rằng Node.js (> = 10.13.0) được cài đặt.

Thiết lập một dự án mới khá đơn giản với Nest CLI. Với npm được cài đặt, bạn có thể tạo một project Nest mới với các lệnh sau:

$ npm i -g @nestjs/cli

Cài đặt nestjs-cli

$ nest new project-name

Tạo dự án mới

Sau khi chạy lệnh trên thì thư mục project sẽ được tạo ra, các file mẫu và các file thư viện trong node modules cũng sẽ được cài đặt.

Để run chương trình hãy dùng lệnh sau:

npm start

Sau đó truy cập trình duyệt tại http://localhost:3000, để thấy được ứng dụng Nest vừa được tạo đang chạy.

Cấu hình và chuyển đổi giữa ExpressJS và Fastify

Có hai nền tảng HTTP mà NestJS có thể hỗ trợ: Express Fastify.

Express: rất phổ biến trong cộng đồng phát triển web Nodejs. Express là framework web tối giản nổi tiếng dành cho node.

Fastify: có hiệu suất tốt hơn. Đó là một framework có hiệu suất cao và chi phí thấp, tập trung vào việc cung cấp hiệu quả và tốc độ tối đa.

Bạn có thể chọn một để phù hợp nhất với nhu cầu của bạn.

Mặc định, Nest sử dụng Express framework.

import './LoadEnv';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
  try {
    const app = await NestFactory.create(AppModule);
    app.useGlobalPipes(new ValidationPipe());
    await app.listen(process.env.PORT || 3000);
  } catch (err) {
    console.log(err);
  }
}
bootstrap();

Để cấu hình NestJS sử dụng Fastify, trước tiên chúng ta cần cài đặt các package theo yêu cầu:

$ npm i --save @nestjs/platform-fastify

Bên trong hàm bootstrap trong main.ts, import package và cấu hình để sử dụng Fastify như sau:

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

Routing trong NestJS

Routing trong NestJS rất dễ để định nghĩa. Chúng ta sẽ sử dụng decorator @Controller(‘users’) để xác định các routing cơ bản cho users. Các routing cho Post, Get, Put, Delete, Param, và Body được đánh dấu bằng Nestjs annotation tương ứng.

GET /users

GET /users/id

POST /users

Sử dụng tiền tố đường dẫn ‘users’ trong decorator @Controller(‘users’) cho phép chúng ta gán các routing liên quan lại với nhau, và giảm thiểu code bị lặp lại.

@Controller('users')
export class UsersController {
  @Get()
  find() {
    return this.usersService.find();
  }
  @Get(':id')
  findById(@Param('id') id) {
    return this.usersService.findById(id);
  }
  @Post()
  add(@Body() createUserDto: CreateUserDto) {
    return this.usersService.add(createUserDto);
  }
  @Patch(':id')
  update(@Param('id') id, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.update(id, updateUserDto);
  }
}

Chúng ta có thể truy cập các request body bằng cách thêm decorator @Body () vào trong định nghĩa của hàm.

@Post()
 add(@Body() createUserDto: CreateUserDto) {
   return this.usersService.add(createUserDto);
}

Decorator @Param() được sử dụng để truy cập parameter của phương thức. Xem ví dụ bên dưới, để truy cập parameter id chỉ cần gọi @Param(‘id’).

@Get(':id')
  findById(@Param('id') id) {
    return this.usersService.findById(id);
}

Các khái niệm trong NestJS

Providers: là một khái niệm cơ bản trong Nest.Nhiều class Nest cơ bản có thể được dùng như là provider: services, repositories, factories, helpers, v.v. Mục đích của một provider là nó có thể inject dependencies; điều này có nghĩa là các đối tượng có thể tạo ra các mối quan hệ khác nhau với nhau; và việc tạo các instance của các object được thực hiện bởi Nest runtime. Một provider chỉ đơn giản là một lớp được liên kết với một decorator @Injectable().

Hãy bắt đầu tạo service đơn giản. UsersService – Service này sẽ đảm nhận lưu trữ và trả về dữ liệu, và được thiết kế để sử dụng bởi UsersController, vì vậy chúng ta nên tạo 1 provider để 2 class này có thể tạo quan hệ với nhau.

 

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private usersRepository: Repository<User>,
  ) {}
  async findOne(username: string): Promise<User | undefined> {
    return this.usersRepository.findOne({ name: username, deleted: 0 });
  }
  async find(option?: FindManyOptions<User>): Promise<User[]> {
    return this.usersRepository.find(option);
  }
  async findById(id: number): Promise<User> {
    return this.usersRepository.findOne(id);
  }
  async add(user: CreateUserDto): Promise<User> {
    return this.usersRepository.save(user);
  }
  async update(user: UpdateUserDto): Promise<User> {
    return this.usersRepository.save(user);
  }
}

HINT: Có thể tạo một service bằng cách sử dụng CLI: nest g service users @Injectable() sẽ giúp Nest biết rằng đây là 1 provider. Vì thế Nest sẽ tự động tạo 1 instance của lớp này và truyền vào UsersController:

Modules: Một module là một lớp được chú thích với một decorator @Module (). Decorator @Module() cung cấp metadata mà Nest sử dụng để tổ chức cấu trúc ứng dụng.

Mỗi ứng dụng có ít nhất một module, một module gốc.  Mỗi module cấu thành nên một tính năng cụ thể trong ứng dụng của bạn. Nest khuyến khích việc xây dựng sourcecode thông qua các module để sắp xếp các tính năng.. Cấu trúc source code của bạn có thể trông như thế này:

GraphQL

Như nhiều người được biết. GraphQL là một ngôn ngữ truy vấn mạnh mẽ cho API và giúp cho việc truy xuất dữ liệu, load data sẵn có. Nest cũng giúp ta tạo ra một server GraphQL ổn định.

Giả sử rằng bạn đã có hiểu biết cơ bản về GraphQL, bây giờ hãy tìm hiểu cách sử dụng GraphQL với Nest.

Bắt đầu bằng cách cài đặt các package cần thiết:

npm i --save @nestjs/graphql apollo-server-express graphql-tools graphql type-graphql

Tùy thuộc vào nền tảng cơ bản nào bạn sử dụng (Express hoặc Fastify), bạn cũng phải cài đặt cả apollo-server-express or apollo-server-fastify.

Dưới đây là danh sách các khái niệm chính bạn cần biết vềGraphQL:

  1. Schema
  2. Query
  3. Mutation
  4. Type
  5. Resolver

NestJS cung cấp cho chúng tôi hai cách khác nhau để xây dựng các ứng dụng GraphQL:

  1. Schema first
  2. Code first

Tổng quan

Với tất cả các tính năng đã được liệt kê ở trên, nó xác minh rằng NestJS có rất nhiều tính năng thú vị có thể giúp các nhà phát triển dễ dàng xây dựng một ứng dụng backend. Mặc dù nó vẫn có một số nhược điểm nhưng sức mạnh và tính hữu dụng của nó không thể phủ nhận. Dưới đây là tóm tắt về ưu và nhược điểm của Nest:

 

Ưu điểm:

Mã nguồn mở

Dễ sử dụng, là một framework mạnh, nhiều tiện ích.

Tài liệu dễ hiểu.

Thời gian phát triển ứng dụng nhanh.

Cú pháp theo kiểu Angular cho backend.

Theo hệ sinh thái NodeJS.

Có hỗ trợ Graphql.

Kiến trúc tốt.

Typescript giúp nó tích hợp tốt trong vscode.

 

Nhược điểm:

Cơ sở người dùng là nhỏ. Trợ giúp ít hơn về Stackoverflow.

Quá nhiều thay đổi trong một bản update.

Không ổn định.

Khó debug.

Tham khảo

https://expressjs.com/

https://www.fastify.io/

https://docs.nestjs.com/graphql/quick-start

https://docs.nestjs.com/techniques/performance

https://docs.nestjs.com/fundamentals/execution-context#reflection-and-metadata

https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841

https://www.apollographql.com/blog/graphql-vs-rest-5d425123e34b/