Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Hướng dẫn về Nest.js – Xây dựng API REST với Nest và Node

Với tư cách là nhà phát triển phụ trợ Node.js, bạn sẽ đồng ý rằng theo mặc định, Node.js rất đơn giản và không đưa ra giả định nào về những gì bạn cần khi xây dựng một ứng dụng. Do đó, bạn chịu trách nhiệm thiết lập mọi thứ bạn muốn sử dụng trên một ứng dụng, bao gồm xử lý định tuyến, thực hiện lệnh gọi API, thiết lập TypeScript hoặc Web Sockets hoặc thậm chí những thứ cơ bản như tổ chức mã, cấu trúc tệp và quy ước đặt tên .

Quản lý một ứng dụng quy mô lớn có thể là một nhiệm vụ khó khăn, đặc biệt nếu nó không được thiết kế với cấu trúc rõ ràng và các nguyên tắc tổ chức mã nghiêm ngặt.

Nest.js cố gắng giải quyết một số vấn đề này bằng cách tạo ra sự trừu tượng hóa xung quanh Node.js để bạn, với tư cách là nhà phát triển, có thể tập trung vào vấn đề ứng dụng thay vì các chi tiết triển khai nhỏ khác.

Trong hướng dẫn này, bạn sẽ tìm hiểu các nguyên tắc cơ bản cốt lõi của Nest.js từ trên xuống dưới, nhằm giúp bạn tăng tốc để có thể xây dựng các ứng dụng Node.js cấp doanh nghiệp với sự trợ giúp của Nest.js một cách nhanh chóng.

Mọi thứ chúng ta học qua hướng dẫn này sẽ được tăng dần; bao gồm rất nhiều nền tảng về các khái niệm giới thiệu. Để tận dụng tối đa hướng dẫn này, việc viết mã sẽ rất hữu ích.

Hãy để chúng tôi đi sâu vào ngay, các bạn!

Mã nguồn: Như thường lệ, bạn có thể phân nhánh và sửa đổi mã nguồn được lưu trữ trên GitHub.

Lưu ý: Chúng tôi sẽ sử dụng Postman để kiểm tra API trong bản trình diễn của chúng tôi. Bạn có thể tải xuống trên Trang tải xuống người đưa thư. Ngoài ra, bạn chỉ cần sử dụng trình duyệt, dòng lệnh curl công cụ hoặc bất kỳ công cụ nào khác mà bạn có thể quen thuộc.

Nest.js là gì

Hãy coi Nest.js như một tập hợp siêu Node.js giúp tóm tắt các nhiệm vụ, công cụ và mã soạn sẵn khó khăn, đồng thời bổ sung bộ công cụ đầy đủ để phát triển ứng dụng của bạn bằng cách sử dụng JavaScript và TypeScript hiện đại.

Nest.js cung cấp kiến ​​trúc ứng dụng có thể dùng ngay cho phép các nhà phát triển và nhóm tạo ra khả năng mở rộng cao, có thể kiểm thử, kết hợp lỏng lẻo và dễ bảo trì bằng cách tận dụng các tùy chọn và mô-đun nổi bật và sẵn có trong cộng đồng, giống như các tùy chọn và mô-đun có sẵn trong Các ứng dụng Express.js. Bạn thậm chí có thể hoán đổi Express (mà nó sử dụng theo mặc định) cho Fastify, nhưng làm như vậy có nghĩa là bạn có thể cần sử dụng các thư viện tương thích Fastify khác nhau trong ứng dụng của mình.

Nó kết hợp các tính năng của Lập trình chức năng, Lập trình hướng đối tượng và Lập trình phản ứng chức năng và với hơn 52.4k sao và 6.2k forks trên GitHub và số lượt tải xuống hàng tuần lên tới 1,784,004, khung Node.js lũy tiến là một lựa chọn phổ biến để tạo các ứng dụng phía máy chủ cấp doanh nghiệp, có khả năng mở rộng và hiệu quả.

Các tính năng của Nest.js

Sau đây là những lý do khiến Nest.js phát triển để trở thành một framework Node.js phổ biến như vậy:

  1. Nest.js được tạo ra để giúp các nhà phát triển xây dựng cả ứng dụng nguyên khối và dịch vụ vi mô.
  2. Mặc dù mạnh mẽ nhưng nó cũng thân thiện với nhà phát triển khi làm việc cùng; dễ sử dụng, học nhanh và dễ áp ​​dụng.
  3. Nó tận dụng TypeScript (một bộ siêu JavaScript) ngay lập tức và tạo chỗ cho các nhà phát triển viết mã có thể bảo trì mà không gặp phải lỗi thời gian chạy.
  4. Nó sở hữu Giao diện dòng lệnh giúp tăng năng suất của các nhà phát triển và dễ dàng phát triển.
  5. Khi xây dựng bằng Nest.js, các quy trình phát triển được nâng cao và tiết kiệm thời gian cho dù bạn đang khởi động Sản phẩm khả thi tối thiểu hay đang làm việc trên một ứng dụng vì Nest có cấu trúc thư mục dự án tuyệt vời theo mặc định.
  6. Nó hỗ trợ nhiều mô-đun dành riêng cho Nest giúp tích hợp các khái niệm và công nghệ phổ biến bao gồm TypeORM, GraphQL, ghi nhật ký, xác thực, Mongoose, WebSockets, bộ nhớ đệm, v.v.
  7. Nest.js có thể tự hào về việc nắm giữ một số tài liệu tốt nhất cho bất kỳ framework nào hiện có. Tài liệu của nó rất kỹ lưỡng, dễ hiểu và hữu ích trong việc tiết kiệm thời gian gỡ lỗi vì nó được thực hiện dễ dàng khi cần giải pháp cho một vấn đề.
  8. Nest.js tích hợp với Jest, giúp việc viết bài kiểm tra đơn vị trên ứng dụng của bạn trở nên đơn giản.
  9. Nó được xây dựng cho cả ứng dụng doanh nghiệp quy mô nhỏ và quy mô lớn.

Tạo dự án Nest.js

Để bắt đầu với Nest.js trên máy cục bộ của bạn, trước tiên bạn phải cài đặt Giao diện dòng lệnh Nest (CLI), giao diện này sẽ giúp tạo một thư mục dự án Nest.js mới và điền vào thư mục đó các tệp và mô-đun cốt lõi cần thiết cho một Ứng dụng Nest.js.

Chạy lệnh sau để cài đặt Giao diện dòng lệnh Nest.js:

$ npm i -g @nestjs/cli
// Or
$ yarn global add @nestjs/cli
// Or
$ pnpm add -g @nestjs/cli

Sau khi cài đặt thành công Nest.js CLI trên toàn cầu trên máy cục bộ của mình, bạn có thể chạy nest trên dòng lệnh để xem các lệnh khác nhau mà chúng ta có thể nhấn vào:

$ nest

Kết quả trong:

Usage: nest  [options]

Options:
  -v, --version                                   Output the current version.
  -h, --help                                      Output usage information.

Commands:
  new|n [options] [name]                          Generate Nest application.
  build [options] [app]                           Build Nest application.
  start [options] [app]                           Run Nest application.
  info|i                                          Display Nest project details.
  add [options]                          Adds support for an external library to your project.
  generate|g [options]  [name] [path]  Generate a Nest element.
    Schematics available on @nestjs/schematics collection:
      ┌───────────────┬─────────────┬──────────────────────────────────────────────┐
      │ name          │ alias       │ description                                  │
      │ application   │ application │ Generate a new application workspace         │
      │ class         │ cl          │ Generate a new class                         │
      │ configuration │ config      │ Generate a CLI configuration file            │
      │ controller    │ co          │ Generate a controller declaration            │
      │ decorator     │ d           │ Generate a custom decorator                  │
      │ filter        │ f           │ Generate a filter declaration                │
      │ gateway       │ ga          │ Generate a gateway declaration               │
      │ guard         │ gu          │ Generate a guard declaration                 │
      │ interceptor   │ itc         │ Generate an interceptor declaration          │
      │ interface     │ itf         │ Generate an interface                        │
      │ middleware    │ mi          │ Generate a middleware declaration            │
      │ module        │ mo          │ Generate a module declaration                │
      │ pipe          │ pi          │ Generate a pipe declaration                  │
      │ provider      │ pr          │ Generate a provider declaration              │
      │ resolver      │ r           │ Generate a GraphQL resolver declaration      │
      │ service       │ s           │ Generate a service declaration               │
      │ library       │ lib         │ Generate a new library within a monorepo     │
      │ sub-app       │ app         │ Generate a new application within a monorepo │
      │ resource      │ res         │ Generate a new CRUD resource                 │
      └───────────────┴─────────────┴──────────────────────────────────────────────┘

Tại đây, bạn được hướng dẫn cách sử dụng các lệnh và bây giờ có thể chạm vào new|n [options] [name] lệnh để tạo dự án Nest.js đầu tiên của bạn:

$ nest new getting-started-with-nestjs
// Or
$ nest n getting-started-with-nestjs

Tiếp theo, bạn sẽ được hỏi bạn muốn sử dụng trình quản lý gói nào:

? Which package manager would you ❤️ to use? (Use arrow keys)
  npm
  yarn
> pnpm

Hãy thoải mái chọn trình quản lý gói mà bạn chọn, tôi sẽ chọn pnpm. Điều này là do nó hiệu quả và nhanh hơn khoảng ba lần so với NPM và với hệ thống bộ nhớ đệm tốc độ cao, PNPM cũng nhanh hơn Yarn.

Sau khi chọn trình quản lý gói, quá trình cài đặt sẽ tiếp tục, sau đó ứng dụng Nest.js sẽ được tạo.

Bây giờ bạn có thể cd vào dự án mới tạo và mở nó bằng trình chỉnh sửa bạn chọn:

$ cd getting-started-with-nestjs

Với dự án hiện đã được tạo, chúng ta có thể chạy nó bằng một trong các lệnh sau:

$ npm run start
// Or
$ yarn start
// Or
$ pnpm run start

Nếu bạn nhìn vào package.json tập tin, bạn sẽ nhận thấy trong đoạn script, giá trị cho pnpm run start is nest start:


    
"start": "nest start",

Điều này có nghĩa là bạn cũng có thể chạy ứng dụng Nest.js bằng cách chạy:

$ nest start

Nhìn vào cấu trúc dự án Nest.js

Chúng ta hãy xem xét kỹ hơn cách cấu trúc của ứng dụng Nest:

/package.json

Sản phẩm package.json file là trái tim của Node.js và theo phần mở rộng, dự án Nest.js. Nó chứa tất cả siêu dữ liệu về dự án và xác định các thuộc tính chức năng khác nhau của dự án cần thiết để cài đặt các phần phụ thuộc của ứng dụng hoặc chạy tập lệnh dự án.

Chúng ta đã thấy khả năng của start kịch bản.

Sản phẩm start:dev profile giúp bạn có thể theo dõi các thay đổi trong ứng dụng và tự động tải lại ứng dụng mà không cần phải dừng ứng dụng và khởi động lại - và nó được thiết kế để phát triển. Các start:prod tập lệnh rất hữu ích khi bạn muốn kiểm tra xem ứng dụng của mình đã sẵn sàng sản xuất hay chưa cũng như khi bạn triển khai nó vào sản xuất, cùng với các tập lệnh khác để kiểm tra ứng dụng Nest.js.

@nestjs/platform-express định nghĩa express là máy chủ HTTP mặc định trong ứng dụng Nest.

/tsconfig.json

Sản phẩm tsconfig.json file là một tệp được viết bằng JSON (Ký hiệu đối tượng JavaScript) xác định các tùy chọn liên quan đến TypeScript cần có để biên dịch ứng dụng Nest.

/nest-cli.json

Phần này chứa siêu dữ liệu cần thiết để xây dựng, tổ chức hoặc triển khai các ứng dụng Nest.

/test

Thư mục này chứa tất cả các tệp cần thiết để chạy thử nghiệm Nest. Nest sử dụng Jest framework để thử nghiệm cấu hình Jest trong jest-e2e.json tập tin.

/src

Sản phẩm src thư mục là thư mục mẹ cho cốt lõi của dự án Nest. Nó giữ main.ts file là tệp nơi ứng dụng Nest khởi động. Công việc của main.ts tập tin sẽ được tải AppModule được nhập khẩu từ /src/app.module.ts.

Ở phần sau của hướng dẫn này, chúng ta sẽ tìm hiểu về Mô-đun; một trong những thành phần chính của ứng dụng Nest.js.

Sản phẩm AppModule là một lớp được tạo dưới dạng một mô-đun, sử dụng @Module người trang trí. bên trong app.module.ts tập tin, AppService từ ./app.serviceAppController từ ./app.controller cũng được nhập khẩu.

Sản phẩm AppController cũng là một lớp được tạo bằng cách sử dụng @Controller người trang trí, trong khi AppService là một lớp được tạo bằng cách sử dụng @Injectable chú thích.

Điều thú vị về Nest là nó có rất ít trình trang trí bên trong có thể thêm siêu dữ liệu vào bất kỳ lớp nào và siêu dữ liệu đó xác định mục đích của lớp đó, chẳng hạn như:

  • @Controller()biến một lớp thành một bộ điều khiển.
  • @Module() chuyển đổi một lớp thành một mô-đun.
  • @Injectable() biến một lớp thành một nhà cung cấp.

Cũng trong src thư mục là app.controller.spec.ts tệp, đây là tệp thử nghiệm cho Bộ điều khiển.

Chúng ta có thể chạy ứng dụng bằng cách sử dụng nest start.

Ứng dụng được bắt đầu lúc http://localhost:3000 trên trình duyệt của bạn:

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Chúng ta có thể thay đổi nội dung hiển thị tại http://localhost:3000, bằng cách đi tới app.service.ts tệp, trong đó nhà cung cấp cho tuyến chỉ mục đã được xác định.

Các khối xây dựng của ứng dụng Nest.js

Có ba thành phần chính của ứng dụng Nest.js:

  1. Modules
  2. Bộ điều khiển
  3. Nhà cung cấp

Khi tìm hiểu về các khối xây dựng của ứng dụng Nest, trước tiên chúng ta hãy dọn dẹp dự án Nest bằng cách xóa app.controller.spec.ts, ./app.service, app.module.ts./app.controller các tập tin; chỉ rời đi main.ts, để mô phỏng vòng đời phát triển từ đầu.

Tại thời điểm này, khi chúng tôi xóa phần đã nhập AppModule tập tin từ main.ts, chúng tôi được nhắc rằng Đối số cho 'mô-đun' không được cung cấp.

Để trình diễn các khối xây dựng của ứng dụng Nest, chúng ta sẽ xem xét cách triển khai Hồ sơ người dùng đơn giản bằng cách xây dựng API REST để xử lý các hoạt động CRUD trên một đối tượng.

Modules

Trong tạp chí src thư mục tạo mới app.module.ts tập tin, sau đó tạo một AppModule lớp mà chúng tôi xuất khẩu.

Tiếp theo, nhập AppModule lớp vào main.ts, và chạy nest start.

Hướng đến http://localhost:3000 trong trình duyệt của bạn và bạn sẽ gặp lỗi 404:

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Điều này là do chúng tôi chưa xác định tuyến đường cho URL cơ sở của ứng dụng Nest.

Quay trở lại app.module.ts, chúng ta có AppModule lớp mà chúng tôi có chưa phải là mô-đun Nest. Để biến nó thành mô-đun Nest, chúng tôi thêm @Module() trang trí được nhập khẩu từ @nestjs/commonsau đó chúng ta chuyển một đối tượng trống.



import { Module } from '@nestjs/common';
@Module({})

export class AppModule {}

Bây giờ, chúng ta có mô-đun Nest.js!

Lưu ý: Mô-đun là một lớp được chú thích bằng @Module() người trang trí.

Mỗi ứng dụng Nest đều có một mô-đun gốc, đóng vai trò là điểm truy cập để giải quyết cấu trúc và các mối quan hệ của ứng dụng Nest.

Bạn nên sử dụng nhiều mô-đun để sắp xếp các thành phần ứng dụng của mình.

Sản phẩm @Module() công cụ trang trí cho phép các nhà phát triển xác định siêu dữ liệu về một lớp trong ứng dụng Nest.

Trong trường hợp có nhiều mô-đun, chẳng hạn như mô-đun người dùng, mô-đun đặt hàng, mô-đun trò chuyện, v.v., app.module.ts nên được sử dụng để đăng ký tất cả các mô-đun khác của ứng dụng Nest.

Tạo tuyến đường; Bộ điều khiển

Cần có bộ điều khiển để tạo tuyến đường trong ứng dụng Nest. Mục đích của bộ điều khiển là nhận các yêu cầu cụ thể cho ứng dụng Nest; kiểm soát chu trình yêu cầu và phản hồi cho các tuyến khác nhau trong ứng dụng.

Khi một yêu cầu HTTP được thực hiện từ máy khách đến ứng dụng Nest, tuyến phù hợp với tuyến trong đó yêu cầu đang được thực hiện sẽ xử lý yêu cầu đó và trả về phản hồi thích hợp.

Để tạo bộ điều khiển trong ứng dụng Nest, chúng ta phải sử dụng @Controller() người trang trí.

Trong tạp chí src thư mục, tạo một tập tin mới app.contoller.tsvà trong đó, chúng ta có thể định nghĩa bộ điều khiển Nest:

import { Controller } from '@nestjs/common';

@Controller({})

export class AppController {}

Đó là nó! Chúng tôi có một bộ điều khiển rất đẹp, nhưng để tạo một tuyến đường mới, trước tiên chúng tôi cần cho ứng dụng Nest biết về bộ điều khiển đã tạo.

Để đạt được điều này, chúng tôi đảm bảo nhập AppController trong app.module.ts và xác định thông tin về bộ điều khiển trong @Module() trang trí - như một mảng của bộ điều khiển:



import { Module } from '@nestjs/common';
import { AppController } from './app.controller';

@Module({
  controllers: [AppController],
})

export class AppModule {}

Xử lý các yêu cầu GET

Sau đó chúng ta định nghĩa một cách đơn giản getUser() tuyến đường (với @Get() trang trí được sử dụng để xử lý các yêu cầu HTTP GET tới một đường dẫn được chỉ định) để làm tuyến cơ sở, chúng ta có thể truy cập tương tự trên trình duyệt tại https://localhost:3000:



import { Controller, Get } from '@nestjs/common';

@Controller({})

export class AppController {
  @Get()
  getUser() {
    return 'I am a great person';
  }
}

Kết quả này trong:

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Hmm, ở đây chúng ta chỉ trả về một chuỗi, nhưng nếu chúng ta muốn trả về một đối tượng thì sao? Thay vì một chuỗi, chúng ta có thể định nghĩa một đối tượng:



import { Controller, Get } from '@nestjs/common';

@Controller({})

export class AppController {
  @Get()
  getUser() {
    return { name: 'Uchechukwu Azubuko', country: 'Nigeria' };
  }
}

Hướng đến http://localhost:3000 trong trình duyệt của bạn và bạn sẽ thấy đối tượng:

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Rời khỏi tuyến đường cơ sở, hãy tạo một tuyến đường tương tự như http://localhost:3000/user để tìm nạp tất cả người dùng?

Chúng ta có thể tạo bộ điều khiển để xử lý tuyến đường như vậy theo một số cách.

Một cách là định nghĩa một phương thức mới, sử dụng @Get() người trang trí/xử lý.

import { Controller, Get } from '@nestjs/common';

@Controller({})

export class AppController {
  @Get()
  getUser() {
    return { name: 'Uchechukwu Azubuko', country: 'Nigeria' };
  }
}

Nest.js cung cấp trình trang trí hoặc trình xử lý cho tất cả các phương thức HTTP khác nhau, bao gồm @Get(), @Post(), @Put(), @Delete(), @Patch(), @Options()@Head().

Sản phẩm @All() trang trí xác định một điểm cuối xử lý tất cả các phương thức khác nhau.

Xử lý các yêu cầu POST

Chúng ta cũng có thể định nghĩa các yêu cầu POST để lưu trữ dữ liệu trong cơ sở dữ liệu bằng cách sử dụng @Post() người trang trí:

import { Controller, Post } from '@nestjs/common';

@Controller({})
export class AppController {
  @Post()
  store() {
    return 'Post request successful';
  }
}

Sau đó, chúng tôi kiểm tra yêu cầu POST bằng Postman và nhận thấy rằng chuỗi được trả về thành công như được xác định.

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Bạn có thể hỏi, nếu tôi cũng muốn làm nhiều việc hơn là trả lại dữ liệu thì sao? Có lẽ, để gửi dữ liệu.

Để làm được điều đó, bạn cần đưa dữ liệu vào bên trong phương thức định tuyến, như được hiển thị:

import { Controller, Post, Req } from '@nestjs/common';
import { Request } from 'express';

@Controller({})
export class AppController {
  @Post()
  store(@Req() req: Request) {
    return req.body;
  }
}

Bây giờ, khi chúng tôi kiểm tra yêu cầu POST bằng Postman, chúng tôi có thể xem dữ liệu đang được gửi. Trong trường hợp này, nó chỉ là một đối tượng trống:

Xem hướng dẫn thực hành, thực tế của chúng tôi để học Git, với các phương pháp hay nhất, các tiêu chuẩn được ngành công nghiệp chấp nhận và bảng lừa đảo đi kèm. Dừng lệnh Googling Git và thực sự học nó!

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Định tuyến động với các tham số tuyến đường

Giả sử bạn muốn chấp nhận dữ liệu động như một phần của yêu cầu. Trước tiên, chúng ta cần xác định mã thông báo trong đường dẫn của tuyến đường, để ghi chú vị trí động trên tuyến đường/URL, sau đó sử dụng @Param() trang trí, tham số tuyến đường có thể được truy cập như sau:

import { Controller, Get, Param } from '@nestjs/common';

@Controller({})
export class AppController {
  @Get('/:userId')
  getUser(@Param() userId: number) {
    return userId;
  }
}

Sản phẩm userId được trả về thành công:

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Xử lý các yêu cầu không đồng bộ

Nest.js có thể xử lý các yêu cầu không đồng bộ trả lại lời hứa bằng nhiều cách tiếp cận khác nhau:

import { Controller, Get} from '@nestjs/common';

@Controller({})
export class AppController {
  @Get()
  async findAll(): Promise {
    return [];
  }
}

Trong cách tiếp cận trên, tính không đồng bộ được xử lý bằng cách sử dụng async từ khóa. Một cách tiếp cận khác là trả về các luồng có thể quan sát được RxJS:

import { Controller, Get} from '@nestjs/common';

@Controller({})
export class AppController {
  @Get()
  findAll(): Observable {
    return of([]);
  }
}

Tại đây, Nest.js sẽ đăng ký nguồn dưới mui xe và khi luồng hoàn thành, nó sẽ tự động nhận giá trị được phát ra cuối cùng.

Xử lý chuyển hướng trong Nest

Sản phẩm @Redirect() trang trí được sử dụng để chuyển hướng phản hồi đến một URL khác. Các @Redirect() trình trang trí chấp nhận hai đối số – URL để chuyển hướng đến và mã trạng thái khi chuyển hướng, cả hai đều là tùy chọn:

import { Controller, Get} from '@nestjs/common';

@Controller({})
export class AppController {
  @Get()
  @Redirect('https://www.ucheazubuko.com', 302)
  getSite() {
    return { url: 'https://stackabuse.com' };
  }
}

Trả lại mã trạng thái

Để trả về mã trạng thái cho mọi yêu cầu được xử lý trên máy chủ Nest.js, @HttpCode(…) dễ dàng đi qua.

Trong Nest, mã trạng thái mặc định cho yêu cầu GET là 200, yêu cầu POST là 201, yêu cầu lỗi là 304

Mã trạng thái cho một yêu cầu máy chủ có thể được xác định như dưới đây:

import { Controller, Post, HttpCode } from '@nestjs/common';

@Controller({})
export class AppController {
  @Post()
  @HttpCode(204)
  create() {
    return 'This action adds a new user to the app.';
  }
}

Xử lý các yêu cầu XÓA

Tương tự như việc thực hiện một yêu cầu POST, một yêu cầu xóa có thể được xử lý như sau:

import { Controller, Delete, Param } from '@nestjs/common';

@Controller({})
export class AppController {
  @Delete('/:userId')
  delete(@Param() params: { userId: number }) {
    return params;
  }
}

Xử lý các yêu cầu CẬP NHẬT

Yêu cầu cập nhật dữ liệu cụ thể trên máy chủ có thể được xử lý bằng cách sử dụng @Patch() người trang trí:

import { Controller, Patch, Req} from '@nestjs/common';
import { Request } from 'express';

@Controller({})
export class AppController {
  @Patch('/:userId')
  update(@Req() req: Request) {
    return req.body;
  }
}

Bây giờ chúng ta đã thấy nhiều cách khác nhau để xác định các bộ điều khiển điển hình mà chúng ta thường có trên một máy chủ mạnh mẽ, điều quan trọng cần lưu ý là bộ điều khiển phải gọn gàng, sạch sẽ và được xác định cho mỗi trường hợp sử dụng, sao cho nếu có một bộ điều khiển khác để xác định user các tuyến đường, thì một thư mục riêng sẽ được tạo và dành riêng cho việc xử lý tương tự - cách xa AppController.

Sau đó trong user.controller.ts, chúng ta có thể định cấu hình tất cả các trình xử lý tuyến đường trong đó có tiền tố là /user/ bằng cách viết mã như hiển thị bên dưới:



import { Controller, Get } from '@nestjs/common';

@Controller('/user')
export class UserController {
  @Get()
  getUser() {
    return 'I am from the user controller';
  }
}

Tiếp theo, đăng ký UserController trong mảng của bộ điều khiển trong app.modules.ts:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { UserController } from './controllers/user/user.controller';

@Module({
  controllers: [AppController, UserController],
})

export class AppModule {}

Khi chúng tôi điều hướng đến https:localhost:3000/user, nó trả về thành công:

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Để giữ cho thư mục dự án gọn gàng hơn hiện tại, chúng ta có thể định nghĩa một user.module.ts tập tin nơi chúng tôi sẽ xác định UserController:

import { Module } from '@nestjs/common';
import { UserController } from './user.controller';

@Module({
  controllers: [UserController],
})

export class UserModule {}

Sau đó, nhập UserModule trong app.module.ts:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { UserModule } from './user/user.module';

@Module({
  controllers: [AppController],
  imports: [UserModule],
})

export class AppModule {}

Với điều này, chúng ta sẽ có thể có được hiệu ứng tương tự như trước đây.

Lưu ý: Nest giúp bạn dễ dàng (g)tạo (mo)dules và (co)người điều khiển bằng cách sử dụng nest g monest g co lệnh. Các mô-đun cụ thể, chẳng hạn như user mô-đun và bộ điều khiển cũng có thể được tạo nhanh chóng bằng Nest CLI bằng cách chạy các lệnh: nest g mo user – để tạo một mô-đun người dùng và nest g co user – để tạo bộ điều khiển người dùng.

Nhà cung cấp

Tất cả việc tìm nạp dữ liệu từ cơ sở dữ liệu phải được nhà cung cấp xử lý thay vì bộ điều khiển, để tạo một lớp trừu tượng giữa mã mà người dùng phải đối mặt và mã tương tác với dữ liệu có khả năng nhạy cảm. Giữa các lớp này – xác thực có thể được thiết lập để đảm bảo xử lý cơ sở dữ liệu thích hợp. Với Nest CLI, chúng ta có thể tạo nhà cung cấp bằng cách tạo các dịch vụ:

$ nest g s user

Điều này tạo ra một UserService trong đó chúng tôi sẽ xác định tất cả logic kinh doanh cho UserController, Do đó UserController chỉ xử lý các yêu cầu và phản hồi. TRONG user.service.ts, chúng tôi thấy rằng @Injectable() trang trí được sử dụng để xác định lớp. Trong Nest, việc sử dụng @Injectable() người trang trí là chuyển đổi các dịch vụ, kho lưu trữ hoặc lớp người trợ giúp thành nhà cung cấp.

Các nhà cung cấp được đưa vào một lớp thông qua hàm tạo của nó. Chúng ta hãy xem xét kỹ một ví dụ.

Trước đó, trong user.controller.ts, chúng ta đã xác định logic nghiệp vụ để lấy đối tượng người dùng, nhưng bây giờ, chúng ta nên định nghĩa tương tự trong UserService:



import { Controller, Injectable } from '@nestjs/common';

@Controller({})

export class AppController {
  @Injectable()
  get() {
    return { name: 'Uchechukwu Azubuko', country: 'Nigeria'; };
  }
}

Tiếp theo, trong user.controller.ts tập tin, chúng ta hãy xác định một hàm tạo trong UserController lớp học. Trong hàm tạo này, chúng tôi cung cấp một giá trị riêng userService, đó là một loại UserService lớp học. Với quyền riêng tư này, chúng tôi có thể khai thác logic nghiệp vụ mà chúng tôi đã xác định trước đó để tìm nạp người dùng:



import { Controller, Get } from '@nestjs/common';
import { UserService } from './user.service';

@Controller('/user')
export class UserController {
  constructor(private userService: UserService) {}
  @Get()
  getUser() {
    return this.userService.get();
  }
}

Như vậy, UserController lớp, bây giờ phụ thuộc vào UserService lớp trong một khái niệm được gọi là
tiêm phụ thuộc.

Theo cùng một cách, logic trong cả hai user.controller.tsuser.service.ts các tập tin được cập nhật tương ứng:



import {
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
  Req,
} from '@nestjs/common';
import { Request } from 'express';
import { UserService } from './user.service';

@Controller('user')
export class UserController {
  constructor(private userService: UserService) {}
  @Get()
  getUsers() {
    return this.userService.get();
  }
  @Get('/:userId')
  getUser(@Param() param: { userId: number }) {
    return this.userService.getUser(param);
  }
  @Post()
  store(@Req() req: Request) {
    return this.userService.create(req);
  }
  @Patch('/:userId')
  update(@Req() req: Request, @Param() param: { userId: number }) {
    return this.userService.update(req, param);
  }
  @Delete()
  delete(@Param() param: { userId: number }) {
    return this.userService.delete(param);
  }
}


import { Injectable } from '@nestjs/common';
import { Request } from 'express';

@Injectable()
export class UserService {
  get() {
    return { name: 'Uchechukwu Azubuko', country: 'Nigeria' };
  }
  getUser(param: { userId: number }) {
    return param;
  }
  create(req: Request) {
    return req.body;
  }
  update(req: Request, param: { userId: number }) {
    return { body: req.body, param };
  }
  delete(param: { userId: number }) {
    return param;
  }
}

Bây giờ, hãy để chúng tôi xác minh rằng các điểm cuối hoạt động như bình thường bằng cách sử dụng Postman.

Làm sáng tỏ nội dung phụ thuộc trong Nest.js

Khi xây dựng các thành phần nhỏ hơn của một ứng dụng, chẳng hạn như một lớp hoặc mô-đun, lớp của bạn có thể phụ thuộc vào chức năng của lớp hoặc mô-đun khác, chẳng hạn như nhu cầu khai thác dịch vụ HTTP do một lớp khác cung cấp để thực hiện lệnh gọi API hoặc các lớp dịch vụ tương tác với lớp kiên trì.

Sự phụ thuộc có thể được cung cấp trong bộ điều khiển thông qua tiêm phụ thuộc.

Tính năng chèn phụ thuộc là một khái niệm và mẫu lập trình thể hiện cách các phần của ứng dụng được phân phối đến các phần khác của ứng dụng yêu cầu chúng, theo cách mang lại sự gắn kết cao nhưng khả năng ghép nối lỏng lẻo.

Nest hỗ trợ tính năng chèn phần phụ thuộc và bạn có thể sử dụng tính năng này trong các ứng dụng Nest để nâng cao tính mô-đun của dự án.

Một minh họa thực tế được mô tả như sau:

Giả sử lớp A sử dụng một số chức năng của lớp B. Khi đó người ta nói rằng lớp A phụ thuộc vào lớp B. Vì vậy, để sử dụng lớp B trong lớp A, trước tiên chúng ta cần tạo một thể hiện của lớp B (nghĩa là tạo một Đối tượng loại B): const b = new B ().
Việc chuyển nhiệm vụ tạo một phiên bản của một lớp sang một lớp khác và trực tiếp sử dụng phần phụ thuộc trong lớp được cung cấp (thành phần bộ tiêm) được gọi là nội xạ phụ thuộc.

Khuyên bảo: Tính năng chèn phụ thuộc, hay DI, là một trong những khái niệm cơ bản trong các framework như Spring Boot, Nest.js và Angular.js. Nếu bạn muốn đọc thêm về nó, bạn có thể kiểm tra Tài liệu góc chính thức.

Thông thường, một lớp chỉ nên tập trung vào việc hoàn thành các chức năng của nó thay vì được sử dụng để tạo ra các đối tượng khác nhau mà nó có thể yêu cầu hoặc không.

Lợi ích của việc tiêm phụ thuộc.

  1. Nó giúp kiểm tra đơn vị.
  2. Với tính năng chèn phần phụ thuộc, mã soạn sẵn sẽ giảm bớt do việc khởi tạo các phần phụ thuộc được thực hiện bởi thành phần bộ tiêm.
  3. Quá trình mở rộng một ứng dụng trở nên dễ dàng hơn.
  4. Tính năng chèn phụ thuộc giúp cho phép khớp nối lỏng lẻo.

Khám phá tải trọng yêu cầu

Hãy nhớ rằng trên các trình xử lý yêu cầu khác nhau như POST và PATCH, chúng ta có thể chạm vào yêu cầu được máy chủ gửi bằng cách sử dụng @Req() người trang trí. Tuy nhiên, còn nhiều điều hơn thế nữa.

Thay vì truy xuất toàn bộ đối tượng yêu cầu, chúng ta chỉ cần chạm vào các phần cụ thể của đối tượng yêu cầu mà chúng ta cần.
Do đó, Nest cung cấp nhiều trình trang trí khác nhau có thể được sử dụng với trình xử lý tuyến HTTP để truy cập các đối tượng Express of Fastify:

Người trang trí tổ yến Đối tượng Fastify hoặc Express được truy cập
`@Request(), @Req()` `yêu cầu`
`@Response(), @Res()` `lại`
`@Tiếp theo()` `tiếp theo`
`@Phiên()` `req.session`
`@Param(param?: string)` `req.params` / `req.params[param]`
`@Body(param?: string)` `req.body` / `req.body[param]`
`@Query(param?: string)` `req.query` / `req.query[param]`
`@Headers(param?: string)` `req.headers` / `req.headers[param]`
`@Ip()` `req.ip`
`@HostParam()` `req.hosts`

Một ví dụ điển hình sẽ là thay thế @Req() trang trí mà chúng ta đã sử dụng trước đây để truy cập vào phần nội dung của kết quả, với @Body() có thể cung cấp cho chúng tôi quyền truy cập trực tiếp vào nội dung của yêu cầu mà không cần khoan:



@Post()
store(@Body() body: any) {
  return this.userService.create(body);
}

@Patch('/:userId')
update(@Body() body: any, @Param() param: { userId: number }) {
  return this.userService.update(body, param);
}


create(body: any) {
  return body;
}

update(body: any, param: { userId: number }) {
  return { body: body, param };
}

Trong một số trường hợp, bạn có thể chỉ muốn truy xuất các thuộc tính cụ thể của tải trọng yêu cầu. Trong trường hợp đó, bạn sẽ phải xác định lược đồ Đối tượng truyền dữ liệu (DTO). Lược đồ truyền dữ liệu là một đối tượng xác định bản sao của đối tượng đang được truy xuất, nhưng được sử dụng chủ yếu để truyền dữ liệu giữa đối tượng được cho là được lưu hoặc truy xuất và lớp lưu giữ. Thông thường, vì quá trình này dễ bị tấn công hơn nên DTO không chứa nhiều điểm dữ liệu nhạy cảm. Đặc điểm này cũng cho phép bạn chỉ truy xuất một số trường nhất định của một đối tượng.

Trong Nest, bạn nên sử dụng các lớp để xác định Đối tượng truyền dữ liệu vì giá trị của các lớp được giữ nguyên trong quá trình biên dịch.

Giả sử phần thân của yêu cầu có mã thông báo và bạn không muốn truy xuất hoặc cập nhật dữ liệu đó thì DTO có thể được xác định như hiển thị bên dưới:



@Patch('/:userId')
update(
  @Body() updateUserDto: { name: string; email: string },
  @Param() param: { userId: number },
) {
  return this.userService.update(updateUserDto, param);
}


update(
  updateUserDto: { name: string; email: string },
  param: { userId: number },
) {
  return { body: updateUserDto, param };
}

Tuy nhiên, bạn sẽ nhận thấy rằng chúng tôi đã xác định loại cho updateUserDto hai lần; TRONG user.service.ts và trong user.controller.ts, nhưng chúng ta cần giữ mã của mình KHÔ (Đừng lặp lại chính mình) để không lặp lại trong cơ sở mã.

Đối với điều này, trong một thư mục mới /user/dto trong /user thư mục, chúng ta cần tạo một tập tin /update-user.dto.ts với .dto.ts tiện ích mở rộng nơi chúng tôi xác định và xuất UpdateUserDto lớp để sử dụng trong user.service.tsuser.controller.ts các tập tin:



export class UpdateUserDto {
  name: string;
  email: string;
}

...
import { UpdateUserDto } from './dto/update-user.dto';

@Patch('/:userId')
update(
  @Body() updateUserDto: UpdateUserDto,
  @Param() param: { userId: number },
) {
  return this.userService.update(updateUserDto, param);
}

...
import { UpdateUserDto } from './dto/update-user.dto';

update(updateUserDto: UpdateUserDto, param: { userId: number }) {
  return { body: updateUserDto, param };
}

Đường ống và xác nhận

Giả sử có nhu cầu xác thực dữ liệu nhận được khi yêu cầu được thực hiện qua máy chủ.

Trong Nest, chúng tôi có thể kiểm tra tính chính xác của bất kỳ dữ liệu nào vào hoặc ra khỏi ứng dụng bằng cách sử dụng các đường ống cài đặt hai phần phụ thuộc – class-validatorclass-transformer.

Một đường ống là một lớp được định nghĩa bằng @Injectable() công cụ trang trí (do đó, pipe là nhà cung cấp), thực hiện PipeTransform giao diện. Họ chuyển đổi dữ liệu sang định dạng mong muốn và đánh giá dữ liệu sao cho nếu dữ liệu được cho là hợp lệ thì nó sẽ không thay đổi, nếu không thì sẽ đưa ra một ngoại lệ. Để sử dụng một đường ống, bạn cần liên kết một thể hiện của lớp đường ống cụ thể với ngữ cảnh thích hợp.

Sản phẩm class-validator gói cho phép xác thực các phần trang trí và không trang trí bằng cách sử dụng trình xác thực.js nội bộ. Trong khi class-transformer gói cho phép chuyển đổi các đối tượng thành thể hiện của một lớp, chuyển đổi lớp thành đối tượng và tuần tự hóa hoặc giải tuần tự hóa các đối tượng dựa trên các tiêu chí nhất định.

Tám ống do Nest cung cấp là:

  • ValidationPipe
  • ParseArrayPipe
  • ParseIntPipe
  • ParseUUIDPipe
  • ParseBoolPipe
  • DefaultValuePipe
  • ParseEnumPipe
  • ParseFloatPipe

Để chứng minh tính xác thực trong Nest trong hướng dẫn này, chúng tôi sẽ sử dụng công cụ tích hợp sẵn ValidationPipe điều đó giúp có thể thực thi xác thực theo tải trọng yêu cầu và kết hợp tốt với class-validator bưu kiện; các quy tắc cụ thể được khai báo bằng các chú thích đơn giản trong phần khai báo Đối tượng truyền dữ liệu/lớp cục bộ trong mỗi mô-đun.

Để bắt đầu sử dụng tính năng tích hợp sẵn ValidationPipe được xuất khẩu từ @nestjs/common, chúng ta hãy cài đặt class-validatorclass-transformer gói:

$ npm i --save class-validator class-transformer
# Or
$ yarn add class-validator class-transformer
# Or
$ pnpm install class-validator class-transformer

Tiếp theo, điều hướng đến main.ts nơi chúng ta sẽ ràng buộc ValidationPipe ở cấp độ gốc của ứng dụng để đảm bảo rằng tất cả các điểm cuối trong ứng dụng của chúng tôi đều được bảo vệ khỏi việc truy xuất dữ liệu không hợp lệ:



import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3000);
}

bootstrap();

Tiếp theo, trong phần khai báo Đối tượng truyền dữ liệu của mỗi mô-đun, chúng tôi thêm một số quy tắc xác thực bằng cách khai báo các hoạt động kiểm tra dữ liệu thích hợp cho từng dữ liệu riêng lẻ. Trong trường hợp của chúng tôi, chúng tôi sẽ khai báo các quy tắc xác thực thích hợp cho nameemail in UpdateUserDto:



import { IsEmail, IsString } from 'class-validator';

export class UpdateUserDto {
  @IsString()
  name: string;

  @IsEmail()
  email: string;
}

Sản phẩm @IsString() trình trang trí kiểm tra xem dữ liệu đã cho có phải là một chuỗi thực hay không và @IsEmail() trình xác thực sẽ kiểm tra xem dữ liệu đã cho có phải là email hay không, nếu không nó sẽ trả về sai và đưa ra một ngoại lệ.

Bây giờ, nếu chúng ta cố gắng tạo ra một PATCH yêu cầu hồ sơ người dùng và nhập số thay vì email hợp lệ, ví dụ: một ngoại lệ sẽ được đưa ra:

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Với những điều này, chúng tôi có một quá trình xác thực rất tốt trong ứng dụng Nest của mình.

Trong khi xác nhận với ValidationPipe, cũng có thể lọc các thuộc tính mà chúng tôi không muốn trình xử lý phương thức của mình nhận. Ví dụ: nếu trình xử lý của chúng tôi chỉ mong đợi nameemail thuộc tính, nhưng một yêu cầu cũng bao gồm một country tài sản, chúng ta có thể loại bỏ country thuộc tính từ đối tượng kết quả bằng cách thiết lập whitelist đến true khi chúng tôi khởi tạo ValidationPipe:



import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
    }),
  );
  await app.listen(3000);
}

bootstrap();

Ống liên kết ở cấp thông số phương pháp

Ống cũng có thể được xác định trên params, cũng. Đối với điều này, chúng tôi sẽ liên kết đường ống ở cấp độ thông số của phương thức.

Trước đây, mặc dù chúng ta đã xác định userId là một số, bạn sẽ nhận thấy rằng nếu chúng tôi đưa ra yêu cầu với userId dưới dạng một chuỗi, nó thành công bất kể:

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Để đảm bảo rằng giá trị của userId phải luôn là một số, chúng ta sẽ khai báo nó ràng buộc getUser() trình xử lý phương thức với kiểm tra xác thực để đảm bảo giống nhau:


...
import { ParseIntPipe } from '@nestjs/common';

@Get('/:userId')
getUser(@Param('userId', ParseIntPipe) userId: number) {
  return this.userService.getUser(userId);
}


getUser(userId: number) {
  return { userId };
}

Sản phẩm ParseIntPipe xác định Ống ParseInt tích hợp và đảm bảo rằng dữ liệu mà nó chạy phải là số nguyên.

Bây giờ, khi chúng ta thực hiện một GET yêu cầu không hợp lệ userId của chuỗi “ab”, việc xác thực không thành công và một ngoại lệ được đưa ra với một 400 mã trạng thái:

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Nhưng với một giá trị số, quá trình xác thực đã thành công:

Hướng dẫn về Nest.js - Xây dựng API REST với Nest và Node PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Chúng tôi cũng có thể cập nhật các trình xử lý phương thức khác cho phù hợp để đảm bảo xác thực hợp lệ:



import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  ParseIntPipe,
  Patch,
  Post,
  Req,
} from '@nestjs/common';
import { Request } from 'express';
import { UserService } from './user.service';

@Controller('user')
export class UserController {
  constructor(private userService: UserService) {}
  @Get()
  getUsers() {
    return this.userService.get();
  }
  @Get('/:userId')
  getUser(@Param('userId', ParseIntPipe) userId: number) {
    return this.userService.getUser(userId);
  }
  @Post()
  store(@Req() req: Request) {
    return this.userService.create(req);
  }
  @Patch('/:userId')
  update(
    @Body() updateUserDto: { name: string; email: string },
    @Param('userId', ParseIntPipe) userId: number,
  ) {
    return this.userService.update(updateUserDto, userId);
  }
  @Delete()
  delete(@Param('userId', ParseIntPipe) userId: number) {
    return this.userService.delete(userId);
  }
}


import { Injectable } from '@nestjs/common';
import { Request } from 'express';
import { UpdateUserDto } from './dto/user-update.dto';

@Injectable()
export class UserService {
  get() {
    return { name: 'Uchechukwu Azubuko', country: 'Nigeria' };
  }
  getUser(userId: number) {
    return { userId };
  }
  create(req: Request) {
    return req.body;
  }
  update(updateUserDto: UpdateUserDto, userId: number) {
    return { body: updateUserDto, userId };
  }
  delete(userId: number) {
    return { userId };
  }
}

Giờ đây, chúng tôi đã đảm bảo kỹ thuật thực hành tốt nhất để xác thực dữ liệu được đưa vào ứng dụng của chúng tôi, có thể từ nguồn bên ngoài, tại bất kỳ thời điểm nào.

Kết luận

Trong hướng dẫn này, bạn có thể tìm hiểu về phiên bản mới nhất của khối Node.js; Nest.js và tất cả những gì cần thiết để giúp bạn bắt đầu nếu bạn muốn xây dựng một ứng dụng bằng nó. Bạn đã tìm hiểu Nest là gì, các tính năng của Nest, cách tạo dự án Nest, cách xử lý dữ liệu đến vào ứng dụng Nest và cách xác thực dữ liệu đến. Nói chung, bạn đã tìm hiểu về các khối xây dựng của bất kỳ ứng dụng Nest nào và giá trị mà mỗi thành phần mang lại cho ứng dụng Nest.js.

Từ thời điểm này, vẫn còn rất nhiều điều cần tìm hiểu liên quan đến việc xây dựng một ứng dụng cấp doanh nghiệp với Nest, nhưng bạn đã có thể nắm bắt thành công các khái niệm cơ bản có thể giúp bạn bắt đầu và thực hiện tất cả những điều phía trước.

Hãy chú ý theo dõi hướng dẫn mới trong tương lai, nơi chúng ta tìm hiểu cách xây dựng API an toàn với Nest và MySQL.

Nhờ đọc!

Tài Nguyên Bổ Sung

Tài liệu Nest.js
Tài liệu góc

Dấu thời gian:

Thêm từ xếp chồng lên nhau