前言
今天嘗試寫了個 Nest.js 的 Demo,但是發現好像一堆東西看不懂,拿 AI 問了下才知道具體是什麼,把 AI 說的總結了一下放著自己看。(所以這篇文章帶了 AI 輔助生成的標籤)
概念
Nest.js 是一個基於 Node.js 構建的進階框架,它使用 TypeScript 編寫,具備模組化、依賴注入等特性,幫助開發者快速構建高效能和可擴充套件的服務端應用。Nest.js 是圍繞著 物件導向程式設計(OOP) 和 依賴注入(DI) 的設計理念開發的。
模組化結構
概念
在 Nest.js 中,應用是由多個模組(Module)組成的,模組包含控制器(Controller)、服務(Service)、提供者(Provider)等。每個模組可以將業務邏輯分離成獨立的單元,使程式碼易於維護和擴充套件。
案例
以 AppModule 為例。
import { Module } from '@nestjs/common';
import { TodoController } from './todo/todo.controller';
import { TodoService } from './todo/todo.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Todo } from './todo/todo.entity';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'sqlite',
database: 'todo.db',
entities: [Todo],
synchronize: true,
}),
TypeOrmModule.forFeature([Todo]),
],
controllers: [TodoController],
providers: [TodoService],
})
export class AppModule {}
@Module()
:標記為一個模組,它包含了控制器和服務。透過imports
引入 TypeORM 配置來連線資料庫。controllers
:定義了哪些控制器處理 HTTP 請求。providers
:註冊服務(例如TodoService
),這些服務可以在整個模組中被使用。
控制器(Controller)
概念
控制器用於處理 HTTP 請求(如 GET、POST、PUT、DELETE 等),它負責接受客戶端的請求並將其轉發給服務層處理。Nest.js 中的控制器是透過 @Controller()
裝飾器定義的。
案例
以TodoController 為例。
import { Controller, Get, Post, Delete, Param, Body } from '@nestjs/common';
import { TodoService } from './todo.service';
import { Todo } from './todo.entity';
@Controller('todos')
export class TodoController {
constructor(private readonly todoService: TodoService) {}
@Get()
getAllTodos(): Promise<Todo[]> {
return this.todoService.findAll();
}
@Post()
createTodo(@Body('title') title: string): Promise<Todo> {
return this.todoService.create(title);
}
@Delete(':id')
deleteTodo(@Param('id') id: number): Promise<void> {
return this.todoService.remove(id);
}
}
解釋
@Controller('todos')
:將控制器定義為/todos
路徑下的所有請求處理器。constructor(private readonly todoService: TodoService)
:透過依賴注入將TodoService
注入到控制器中。@Get()
:處理 GET 請求,呼叫todoService
獲取所有任務。@Post()
:處理 POST 請求,建立新的任務。@Delete(':id')
:處理 DELETE 請求,刪除指定 ID 的任務。
服務(Service)
概念
服務是用來處理業務邏輯的類。服務通常透過依賴注入的方式被控制器呼叫,並負責與資料庫或其他外部資源互動。
案例:
以 TodoService 為例。
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Todo } from './todo.entity';
@Injectable()
export class TodoService {
constructor(
@InjectRepository(Todo)
private readonly todoRepository: Repository<Todo>,
) {}
async create(title: string): Promise<Todo> {
const newTodo = this.todoRepository.create({ title, completed: false });
return this.todoRepository.save(newTodo);
}
async findAll(): Promise<Todo[]> {
return this.todoRepository.find();
}
async remove(id: number): Promise<void> {
await this.todoRepository.delete(id);
}
}
解釋
@Injectable()
:標記TodoService
類為可被注入的服務,Nest.js 會自動建立並管理它的例項。@InjectRepository(Todo)
:注入Todo
實體的倉庫,用於與資料庫表互動。create()
:建立新任務,並儲存到資料庫。findAll()
:從資料庫中獲取所有任務。remove()
:根據任務 ID 刪除任務。
依賴注入(Dependency Injection,DI)
概念
依賴注入是 Nest.js 的核心概念之一。透過 DI,類的依賴物件(如服務)可以在類的建構函式中被自動注入,避免類自己管理依賴的建立過程。DI 使得程式碼更易測試和維護。
案例:控制器中的依賴注入
constructor(private readonly todoService: TodoService) {}
解釋
todoService
是透過依賴注入注入到控制器中的。在AppModule
中註冊的TodoService
會自動被注入。
實體(Entity)與 TypeORM
概念
實體(Entity)表示資料庫中的表結構,TypeORM 允許開發者使用物件導向的方式與資料庫互動。每個實體類都對應資料庫中的一張表。
案例
以 Todo 實體為例。
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Todo {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column({ default: false })
completed: boolean;
}
解釋
@Entity()
:將Todo
類標記為資料庫表。@PrimaryGeneratedColumn()
:定義了一個自增的主鍵id
列。@Column()
:定義了表的普通列,如title
(任務標題)和completed
(任務是否完成)。
非同步
因為資料庫操作通常是非同步的,Nest.js 透過 Promise
來處理這些非同步操作。Promise<T>
表示這個操作最終會返回一個 T
型別的值(例如 Todo
)。
async create(title: string): Promise<Todo> {
const newTodo = this.todoRepository.create({ title, completed: false });
return this.todoRepository.save(newTodo);
}
Promise<Todo>
:表示這個非同步操作最終會返回一個Todo
實體。async
和await
:允許我們以同步的方式編寫非同步程式碼。
總結
- Nest.js 是模組化和依賴注入驅動的框架:每個應用由模組、控制器和服務組成,模組管理控制器和服務,服務處理業務邏輯並透過依賴注入與控制器協作。
- TypeORM 提供資料庫互動能力:透過實體類與資料庫表進行對映,
Repository
提供對資料庫的增刪查改操作。 - 依賴注入減少了類與類之間的耦合:Nest.js 自動管理類的依賴,提升了程式碼的靈活性和可維護性。