本系列文已出版成書「NestJS 基礎必學實務指南:使用強大且易擴展的 Node.js 框架打造網頁應用程式」,感謝 iT 邦幫忙與博碩文化的協助。如果對 NestJS 有興趣、覺得這個系列文對你有幫助的話,歡迎前往購書,你的支持是我最大的寫作動力!
Nest 採用模組化設計,將各個不同的功能區塊打包成 模組 (Module),而 Module 必定有 一個以上,並且是以 樹狀結構 發散出去,最頂部的 Module 稱為 根模組 (Root Module),其概念如下:
而一個 有路由機制 的 Module 會帶有 控制器 (Controller) 與 服務 (Service),它們之間的關係如下:
從圖中可以看出 Controller 與 Service 透過 Module 建立關係後,即可將 Service 注入 (Inject) 到 Controller 中使用,這樣的好處是可以職責分離,把處理請求的操作交給 Controller,把處理邏輯的部分交給 Service,這樣說明有點太抽象了,那來點實際流程吧:
用現實生活中的例子來說明 Nest 整體概念的話,Nest App 就像一間有多國料理的餐廳,該餐廳規劃每種國家的料理即一個區塊,每個區塊都有負責的外場服務生,而這個區塊即為 Module,Controller 就是外場服務生,而 Service 則是內場人員,當客人走進餐廳時,先依照想吃的異國料理來安排座位,外場服務生協助客人點餐並將訂單送至內場,內場人員開始針對客人的訂單做料理,當餐點做好了之後,再請外場服務生送到客人面前:
現在對於 Nest 應該有些概念了,那就來看怎麼建置第一個 Nest App 吧!
Nest 官方設計了一套 CLI 來幫助各位開發者們加速開發,可以透過 NestCLI 自動產生程式碼骨架,這樣一來便可以大幅降低「相同操作重複做」的次數,非常貼心。那要如何安裝呢?只需要透過 npm
進行全域安裝即可,在終端機輸入下方指令:
$ npm install -g @nestjs/cli
安裝完以後就可以透過終端機使用 NestCLI 了,查看有哪些指令可以使用:
$ nest --help
透過 NestCLI 的 new
指令來快速建立 App:
提醒:注意終端機當前位於資料夾何處,建議透過 cd 指令移動到想要的位置。
$ nest new <APP_NAME>
此時會建立一些 App 的骨架,並詢問要使用哪種套件管理程式:
提醒:這裡可以根據個人喜好選擇,筆者這邊選 npm。
等程序跑完後,就來執行看看吧:
$ cd <APP_NAME>
$ npm start
Nest 預設是在 3000 port,從瀏覽器網址列輸入 http://localhost:3000 來看架設結果:
透過 NestCLI 建置的專案資料夾結構如下:
.
├─ dist
├─ node_modules
├─ src
| ├─ app.controller.ts
| ├─ app.controller.spec.ts
| ├─ app.module.ts
| ├─ app.service.ts
| └─ main.ts
├─ test
| ├─ app.e2e-spec.ts
| └─ jest-e2e.json
├─ .eslintrc.js
├─ .gitignore
├─ .prettierrc
├─ nest-cli.json
├─ package.json
├─ package-lock.json
├─ tsconfig.json
├─ tsconfig.build.json
└─ README.md
npm install <PACKAGE>
所安裝的檔案。tsconfig.json
的延伸。注意:這邊會簡單帶過,後續會再針對各功能做詳細的說明。
在 src
資料夾中,撇除測試用的 app.controller.spec.ts
外,會看到 main.ts
、app.module.ts
、app.controller.ts
以及app.service.ts
。
main.ts
為載入點,程式碼如下:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
以非同步的 bootstrap
函式做為載入函式,透過 NestFactory.create(AppModule)
產生一個 Nest App 的實例 (Instance),並透過呼叫該實例的 listen(PORT)
將其架設起來。
提醒:PORT 即為要使用的 port,預設為 3000。
app.module.ts
為根模組,程式碼如下:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
在 Nest 中,大部分的元件都是使用 裝飾器 (Decorator) 的方式來提供 元數據 (Metadata),可以看到定義了一個名為 AppModule
的 class
,透過裝飾器將其變成 Nest 的 Module,並在這裡定義該模組的 Controller 與 Service。
app.controller.ts
是註冊於根模組底下的 Controller, 不是必要項目。程式碼如下:
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
可以看到也是使用帶有裝飾器的 class
,比較特別的是裡面的方法 (Method) 也使用了裝飾器,來定義該方法是使用哪種方式進行觸發等。另外,可以在 constructor
中看見 appService
的參數,這是使用 依賴注入(Dependency Injection) 的方式將 AppService
注入到 AppController
中。
app.service.ts
是註冊於根模組底下的 Service,不是必要項目。程式碼如下:
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
與 Module、Controller 有些不同,Service 所使用的裝飾器為 Injectable
,原因是 Service 屬於 抽象 的概念,在 Nest 中有許多抽象概念可以使用 Injectable
來實作,他們統一歸類為 Provider。
Nest 提供高度的模組化設計,只要把 Controller 與 Service 定義好並放入對應的 Module 裡,再像拼拼圖一樣把相關模組各自關聯起來,就可以建立起易維護、低耦合、易擴展的 Node.js 後端應用,如果再使用官方設計的 NestCLI,將大幅加速開發時間!