【前端】嘿,Nest.js實(shí)戰(zhàn)開發(fā)系列之 Nest.js初體驗(yàn)
寫在前面前面從小白視角學(xué)習(xí)了Typescript,并學(xué)習(xí)總結(jié)了ts的系列文章,希望能夠?qū)τ谧x者有所幫助。至于學(xué)習(xí)了TS基礎(chǔ)后,如何進(jìn)行開發(fā)實(shí)踐,本系列將結(jié)合Nest.js的Node服務(wù)器框架進(jìn)行娓娓道來(lái)。
- Nest (NestJS) 是一個(gè)用于構(gòu)建高效、可擴(kuò)展的Node.js服務(wù)器端應(yīng)用程序的框架。它使用漸進(jìn)式 JavaScript,使用TypeScript構(gòu)建并完全支持(但仍然允許開發(fā)人員使用純 JavaScript 進(jìn)行編碼)并結(jié)合了 OOP(面向?qū)ο缶幊?、FP(函數(shù)式編程)和 FRP(函數(shù)式響應(yīng)式編程)的元素。
Nest使用了功能強(qiáng)大的HTTP Server框架,默認(rèn)支持Express框架,其是簡(jiǎn)單易上手的。Nest是在Express上進(jìn)行抽象而成的,結(jié)合TS強(qiáng)大的語(yǔ)言體系實(shí)現(xiàn)高效快捷開發(fā)。
Nest是筆者繼接觸Express框架后感興趣的Node框架,對(duì)此還是比較熟悉的,選擇Nest也就簡(jiǎn)單易行。截止到筆者發(fā)布文章的時(shí)候,Github上Nest擁有37.7K個(gè)Stat,足以證明其受青睞程度。
Nest 提供開箱即用的應(yīng)用程序架構(gòu),允許開發(fā)人員和團(tuán)隊(duì)創(chuàng)建高度可測(cè)試、可擴(kuò)展、松散耦合且易于維護(hù)的應(yīng)用程序。該架構(gòu)深受 Angular 的啟發(fā)。
項(xiàng)目創(chuàng)建
開發(fā)環(huán)境
在項(xiàng)目開展前,先行介紹下開發(fā)環(huán)境:
- node.js:14.15.1
- typescript:3.8.3
- nest.js:7.6.15
先決條件請(qǐng)確保您的操作系統(tǒng)上安裝了Node.js(>= 10.13.0,v13 除外)。
創(chuàng)建項(xiàng)目
要使用 Nest cli創(chuàng)建項(xiàng)目,先得安裝相關(guān)腳手架,運(yùn)行下列命令創(chuàng)建第一個(gè)Nest項(xiàng)目。
- $ npm i -g @nestjs/cli
- $ nest new project-name
當(dāng)然也可以使用yarn命令進(jìn)行創(chuàng)建:
- $ yarn add @nest/cli
- $ nest new project-name
在輸入完上述命令后,得到以下內(nèi)容:
- G:\Code>nest new nest-test
- ⚡ We will scaffold your app in a few seconds..
- CREATE nest-test/.eslintrc.js (631 bytes)
- CREATE nest-test/.prettierrc (51 bytes)
- CREATE nest-test/nest-cli.json (64 bytes)
- CREATE nest-test/package.json (1971 bytes)
- CREATE nest-test/README.md (3339 bytes)
- CREATE nest-test/tsconfig.build.json (97 bytes)
- CREATE nest-test/tsconfig.json (339 bytes)
- CREATE nest-test/src/app.controller.spec.ts (617 bytes)
- CREATE nest-test/src/app.controller.ts (274 bytes)
- CREATE nest-test/src/app.module.ts (249 bytes)
- CREATE nest-test/src/app.service.ts (142 bytes)
- CREATE nest-test/src/main.ts (208 bytes)
- CREATE nest-test/test/app.e2e-spec.ts (630 bytes)
- CREATE nest-test/test/jest-e2e.json (183 bytes)
- ? Which package manager would you ❤️ to use? yarn
- ▹▹▹▸▹ Installation in progress... ☕
上述所示,會(huì)詢問(wèn)你選擇yarn還是npm進(jìn)行包管理,筆者此處選擇的是yarn。
- 🚀 Successfully created project nest-test
- 👉 Get started with the following commands:
- $ cd nest-test
- $ yarn run start
- Thanks for installing Nest 🙏
- Please consider donating to our open collective
- to help us maintain this package.
- 🍷 Donate: https://opencollective.com/nest
經(jīng)歷過(guò)歲月靜好,電腦后臺(tái)已經(jīng)為我們負(fù)重前行,最終創(chuàng)建成功。
根據(jù)上述提示,我們進(jìn)入項(xiàng)目進(jìn)行操作,項(xiàng)目目錄如下所示:
運(yùn)行yarn start或npm run start后執(zhí)行運(yùn)行項(xiàng)目,啟動(dòng)項(xiàng)目服務(wù)。
此時(shí),在瀏覽器地址欄輸入http://localhost:3000即可看到hello world。
詳情介紹
路由
當(dāng)打開src目錄下main.ts文件時(shí),看到@Controller()裝飾器中使用路由前綴可以更方便地進(jìn)行路由分組,最大程度減少代碼重復(fù)。
main.ts
- import { NestFactory } from '@nestjs/core';
- import { AppModule } from './app.module';
- async function bootstrap() {
- const app = await NestFactory.create(AppModule);//表示使用nest的工廠函數(shù)創(chuàng)建了AppModule
- await app.listen(3000);//表示項(xiàng)目監(jiān)聽的端口是3000
- }
- bootstrap();
控制器是控制傳入的請(qǐng)求返回到客戶端的顯示內(nèi)容,當(dāng)然也可以進(jìn)行添加指定的路由。我們可以在app.controller.ts文件中添加以下代碼:
- @Get("/home")
- getHome(): string {
- return "my home";
- }
運(yùn)行得到:
設(shè)置局部路由前綴
路由還可以設(shè)置局部和全局的前綴,使用前綴可以避免在所有路由共享通用前綴時(shí)出現(xiàn)沖突的情況。
在@Controller()寫入best,可以表示當(dāng)前文件中所有路由設(shè)置前綴best。如下所示:
- @Controller("best")
- export class AppController {
- constructor(private readonly appService: AppService) {}
- @Get()
- getHello(): string {
- return this.appService.getHello();
- }
- }
運(yùn)行結(jié)果:
設(shè)置全局路由前綴
可以在main.ts文件中添加app.setGlobalPrefix()設(shè)置全局路由前端:
- app.setGlobalPrefix('nest-test'); // 全局路由前綴
運(yùn)行結(jié)果:
controller控制器
控制器負(fù)責(zé)處理傳入的請(qǐng)求并將響應(yīng)返回給客戶端。控制器的目的是接收應(yīng)用程序的特定請(qǐng)求。在路由該控制器接收哪些請(qǐng)求機(jī)構(gòu)的控制。很多時(shí)候,每個(gè)控制器有多個(gè)路由,不同的路由可以執(zhí)行不同的動(dòng)作。

為創(chuàng)建一個(gè)基本的控制器,我們使用類和裝飾器。裝飾器將類與所需的元數(shù)據(jù)相關(guān)聯(lián),并使 Nest 能夠創(chuàng)建路由映射(將請(qǐng)求綁定到相應(yīng)的控制器)。
app.controller.ts
- 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();
- }
- }
同樣的,我們可以使用命令進(jìn)行創(chuàng)建新的控制器模塊,便于對(duì)項(xiàng)目的管理。
- $ nest g controller users
此時(shí)在src中生成了users目錄文件:
初始化的controller文件如下:
users.controller.ts
- import { Controller } from '@nestjs/common';
- @Controller('users')
- export class UsersController {}
Services業(yè)務(wù)
我們看到前面controller文件中,可以實(shí)現(xiàn)簡(jiǎn)單業(yè)務(wù)邏輯的處理,但是在實(shí)際開發(fā)中應(yīng)當(dāng)將控制器和業(yè)務(wù)進(jìn)行分開,對(duì)代碼進(jìn)行解耦。
- $ nest g service users
此時(shí)在src中的users目錄下生成了業(yè)務(wù)文件:
users.service.ts
- import { Injectable } from '@nestjs/common';
- @Injectable()
- export class UsersService {
- // 添加用戶的業(yè)務(wù)邏輯
- addUser(username: string, password: string): string{
- console.log(`create user:username--${username} password--${password}`);
- return "add user success";
- }
- }
users.controller.ts
- import { Body, Controller, Post } from '@nestjs/common';
- import { UsersService }from "./users.service";
- @Controller('users')
- export class UsersController {
- constructor(private readonly usersService: UsersService) {}//Nest 是圍繞通常稱為依賴注入的強(qiáng)大設(shè)計(jì)模式構(gòu)建的。Nest 將UsersService通過(guò)創(chuàng)建并返回一個(gè)實(shí)例usersService。
- @Post("add")
- addUser(@Body() body){
- return this.usersService.addUser(body.username,body.password);
- }
- }
使用postman進(jìn)行模擬用戶請(qǐng)求,運(yùn)行結(jié)果如下:
Module模塊
模塊是用@Module()裝飾器注釋的類,@Module()裝飾器提供元數(shù)據(jù)利用的組織應(yīng)用程序結(jié)構(gòu)。

每個(gè)應(yīng)用程序至少有一個(gè)模塊和一個(gè)根模塊。根模塊是 Nest 用于構(gòu)建應(yīng)用程序圖的起點(diǎn)- Nest 用于解析模塊和提供者關(guān)系和依賴關(guān)系的內(nèi)部數(shù)據(jù)結(jié)構(gòu)。雖然理論上非常小的應(yīng)用程序可能只有根模塊,但這不是典型情況。我們要強(qiáng)調(diào)的是,強(qiáng)烈推薦使用模塊作為組織組件的有效方式。因此,對(duì)于大多數(shù)應(yīng)用程序,最終的架構(gòu)將采用多個(gè)模塊,每個(gè)模塊封裝一組密切相關(guān)的功能。
所述@Module()裝飾采用單個(gè)對(duì)象,其屬性描述該模塊:
我們看到上面創(chuàng)建的Service和Controller是如何進(jìn)行訪問(wèn)運(yùn)行的呢?
打開app.modelu.ts 可以看到:
- import { Module } from '@nestjs/common';
- import { AppController } from './app.controller';
- import { AppService } from './app.service';
- import { UsersController } from './users/users.controller';
- import { UsersService } from './users/users.service';
- @Module({
- imports: [],
- controllers: [AppController, UsersController],
- providers: [AppService, UsersService],
- })
- export class AppModule {}
在我們創(chuàng)建了子模塊后,創(chuàng)建了UsersController和UsersService,即使不新建module文件也能通過(guò)路由訪問(wèn),因?yàn)橄到y(tǒng)會(huì)自動(dòng)添加到app.module.ts文件中。
當(dāng)然,我們也可以根據(jù)需求進(jìn)行創(chuàng)建子模塊的module文件,只需要執(zhí)行下列命令即可:
- $ nest g module users
此時(shí)看到生成了module子模塊文件:
初始化的文件如下所示:
- import { Module } from '@nestjs/common';
- @Module({})
- export class UsersModule {}
此時(shí)需要將users模塊的UsersController和UsersService組裝到module文件中。這樣,其他module模塊想要引入U(xiǎn)sers模塊時(shí),不需要同時(shí)Controller和Service了,方便對(duì)本模塊進(jìn)行管理。
- import { Module } from '@nestjs/common';
- import { UsersController } from './users.controller';
- import { UsersService } from './users.service';
- @Module({
- imports: [UsersModule],
- controllers: [UsersController],
- providers: [UsersService],
- })
- export class UsersModule {}
當(dāng)然,需要對(duì)app.module.ts文件進(jìn)行修改,因?yàn)樽幽K已經(jīng)引入了Controller和Service了。
- import { Module } from '@nestjs/common';
- import { AppController } from './app.controller';
- import { AppService } from './app.service';
- // import { UsersController } from './users/users.controller';
- // import { UsersService } from './users/users.service';
- import { UsersModule } from './users/users.module';
- @Module({
- imports: [UsersModule],
- controllers: [AppController],
- providers: [AppService],
- })
- export class AppModule {}
小結(jié)
本文主要介紹使用Nest創(chuàng)建的首個(gè)項(xiàng)目,簡(jiǎn)要講解了創(chuàng)建過(guò)程,以及使用到的模塊概念。對(duì)路由、控制器、業(yè)務(wù)、模塊進(jìn)行了闡述,后續(xù)概念會(huì)進(jìn)行詳細(xì)講解,更詳細(xì)的請(qǐng)見官方文檔。