原文地址:Getting Started with NestJS
介紹
如果您使用的是Node.js應(yīng)用程序佑女,則可能已經(jīng)注意到虫给,隨著時間的推移,它變得越來越難以維護(hù)。 您向應(yīng)用程序添加新功能的次數(shù)越多晓褪,代碼庫就越大盛龄。
Nest.js是用于構(gòu)建高效,可靠和可擴(kuò)展的應(yīng)用程序的服務(wù)端Node.js框架商架。 它為后端應(yīng)用程序提供了一種模塊化結(jié)構(gòu),用于將代碼組織到單獨(dú)的模塊中芥玉。 它旨在消除代碼庫的混亂蛇摸。
受Angular的啟發(fā),Nest.js使用TypeScript構(gòu)建灿巧,并使用了Express.js赶袄,使其與大多數(shù)Express中間件兼容。
在本文中抠藕,您將創(chuàng)建一個小的RESTful API饿肺,使用戶能夠在書店中獲取,創(chuàng)建和刪除圖書盾似。
前提
要完成本教程敬辣,您將需要:
- Node.js的本地開發(fā)環(huán)境。移步如何安裝Node.js和創(chuàng)建本地開發(fā)環(huán)境
了解Nest.js的組成結(jié)構(gòu)
以下是構(gòu)建Nest.js應(yīng)用程序時使用的組成部分
- Controllers
- Providers
- Modules
我們將從查看controllers開始。 與大多數(shù)Web框架一樣溉跃,Nest.js中的controllers負(fù)責(zé)處理所有傳入請求村刨,并將響應(yīng)返回給應(yīng)用程序的客戶端。 例如撰茎,如果您對特定端點(diǎn)(例如/home)進(jìn)行API調(diào)用嵌牺,則controllers將接收到該請求,并基于可用資源乾吻,它將返回適當(dāng)?shù)捻憫?yīng)髓梅。
Nest.js的構(gòu)建方式使路由機(jī)制能夠控制哪個控制器將負(fù)責(zé)處理特定請求。
要在Nest.js中定義一個controller绎签,請創(chuàng)建一個TypeScript文件并包括一個裝飾器@Controller()枯饿,如以下代碼片段所示:
// users.controller.ts
import { Controller, Get } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll() {
return 'This will return all the users';
}
}
Controller裝飾器中用戶的前綴將指示UsersController處理應(yīng)用程序中的任何/ users GET請求并返回指定的適當(dāng)響應(yīng)。 控制器處理的其他HTTP請求包括POST诡必,PUT奢方,DELETE,我們將在本教程的后面部分看到爸舒。
創(chuàng)建controller后蟋字,需要將其添加到Module定義中,Nest.js才能輕松識別它扭勉。 這可以是根ApplicationModule或在應(yīng)用程序內(nèi)創(chuàng)建的任何其他模塊鹊奖。 有關(guān)更多信息,請參見本文的Modules部分涂炎。
現(xiàn)在讓我們看一下providers忠聚。
如前所述,Nest.js受Angular的啟發(fā)很大唱捣,類似于Angular應(yīng)用程序两蟀,您可以創(chuàng)建一個提供程序并將其注入到controllers或其他providers中。 這些providers也稱為服務(wù)震缭,它們旨在抽象化任何形式的復(fù)雜性和邏輯赂毯。
Nest.js中的服務(wù)提供者是一個JavaScript類,其頂部帶有一個特殊的@Injectable()裝飾器拣宰。 例如党涕,您可以創(chuàng)建一個服務(wù)來獲取用戶:
// users.service.ts
import { Injectable } from '@nestjs/common';
import { User } from './interfaces/user.interface';
@Injectable()
export class UsersService {
private readonly users: User[] = [];
create(user: User) {
this.users.push(user); }
findAll(): User[] {
return this.users;
}
}
上面創(chuàng)建的提供程序是帶有兩個方法create()和findAll()的類,可分別用于創(chuàng)建和返回所有用戶巡社。為了方便進(jìn)行類型檢查膛堤,使用了一個接口來指定方法應(yīng)接收的元素的類型。
最后重贺,讓我們看一下Modules骑祟。Modules使您可以對相關(guān)文件進(jìn)行分組回懦。它們是用@Module裝飾器裝飾的Typescript文件。該附加的裝飾器提供了Nest用來組織應(yīng)用程序結(jié)構(gòu)的元數(shù)據(jù)次企。
每個Nest.js應(yīng)用程序必須至少具有一個模塊怯晕,通常稱為根模塊。這個根模塊是頂層模塊缸棵,通常對于一個小型應(yīng)用程序就足夠了舟茶。建議將大型應(yīng)用程序分為多個模塊,因?yàn)檫@有助于維護(hù)應(yīng)用程序的結(jié)構(gòu)堵第。
如果您有一個管理有關(guān)用戶的大量數(shù)據(jù)或功能的應(yīng)用程序吧凉,則可以將controller,services和其他相關(guān)文件分組到一個模塊中踏志,例如UsersModule:
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller.ts';
import { UsersService } from './users.service.ts';
@Module({
controllers: [UsersController],
providers: [UsersService]
})
export class UsersModule {}
在此示例中阀捅,我們導(dǎo)出了一個包含UsersController和UsersService的UsersModule。 設(shè)置好此位置之后针余,我們可以繼續(xù)在應(yīng)用程序的根模塊中導(dǎo)入和使用UsersModule饲鄙,如以下代碼片段所示:
...
import { UsersModule } from './users/users.module';
@Module({
...
})
export class AppModule { }
Nest.js中還有一些其他重要概念:
- DTO:數(shù)據(jù)傳輸對象是定義如何通過網(wǎng)絡(luò)發(fā)送數(shù)據(jù)的對象。
- 接口:TypeScript接口用于類型檢查和定義可以傳遞給控制器或Nest服務(wù)的數(shù)據(jù)類型圆雁。
- 依賴注入:依賴注入是一種用于提高應(yīng)用程序效率和模塊化的設(shè)計(jì)模式忍级。 最大的框架經(jīng)常使用它來保持代碼的清潔和易于使用。 Nest.js也利用它來基本創(chuàng)建耦合組件伪朽。
通過這種模式轴咱,管理諸如控制器,提供程序和模塊之類的構(gòu)建塊之間的依賴性非常容易烈涮。 唯一需要做的就是在控制器的構(gòu)造函數(shù)中定義依賴項(xiàng)朴肺,例如,UsersService()跃脊,如下所示:
...
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService){}
...
}
在簡要介紹了其中一些概念之后宇挫,您現(xiàn)在可以進(jìn)入下一節(jié)苛吱,在這里您將把到目前為止所獲得的所有知識投入使用酪术,同時您還將學(xué)習(xí)如何使用Nest.js無縫構(gòu)建RESTful API。
如本文前面所述翠储,您將創(chuàng)建一個示例應(yīng)用程序绘雁,以幫助您更好地了解Nest.js的一些核心概念。
該應(yīng)用程序?qū)iT用于書店援所。 在文章的結(jié)尾庐舟,您將創(chuàng)建一個微服務(wù),該服務(wù)將使用戶能夠創(chuàng)建新書并向其現(xiàn)有書單添加很少的描述住拭。 這可能來自數(shù)據(jù)庫挪略,但是為了確保本文的簡潔性历帚,我們還沒有真正將應(yīng)用程序連接到數(shù)據(jù)庫。 但是杠娱,相反挽牢,我們將利用書籍的模擬數(shù)據(jù),一旦創(chuàng)建了新書籍摊求,我們將其推送并添加到列表中禽拔。
第1步 - 安裝Nest.js
為了搭建一個新的Nest.js應(yīng)用程序,您將需要全局安裝Nest CLI應(yīng)用程序室叉。 這是一個命令行工具睹栖,專門用于制作新的Nest.js應(yīng)用并提供對多個命令的訪問權(quán)限,以生成不同的文件并生成結(jié)構(gòu)良好的應(yīng)用茧痕。
除了使用CLI工具之外野来,您還可以通過使用Git從GitHub克隆starter project安裝新的Nest.js應(yīng)用程序。但出于本教程的目的踪旷,請運(yùn)行以下命令來安裝Nest CLI:
npm install -g @nestjs/cli
這將使您可以訪問nest命令以進(jìn)行項(xiàng)目安裝以及其他項(xiàng)目特定的命令梁只。
接下來,運(yùn)行以下命令以在開發(fā)目錄中安裝一個名為bookstore-nest的新項(xiàng)目:
nest new bookstore-nest
在安裝過程中埃脏,系統(tǒng)將詢問您一些問題搪锣,只需按照提示進(jìn)行操作,然后做出相應(yīng)的響應(yīng)即可彩掐。 接下來构舟,安裝完成后,將工作目錄切換到新創(chuàng)建的項(xiàng)目中:
cd bookstore-nest
啟動應(yīng)用程序:
npm run start
您也可以運(yùn)行以下命令來在項(xiàng)目中使用Nodemon:
// start the application using nodemon
npm run start:dev
在瀏覽器中導(dǎo)航到http://localhost:3000堵幽,您將看到Hello World狗超!,如下圖所示:
第2步 - 在項(xiàng)目啟動后朴下,讓我們創(chuàng)建根模塊努咐。
讓我們?yōu)闀晟梢粋€模塊。 為此殴胧,您將利用Nest CLI的文件生成器渗稍。 運(yùn)行以下命令為應(yīng)用程序搭建新模塊:
nest generate module books
這將在src文件夾中創(chuàng)建一個名為books的新文件夾。 在books文件夾中团滥,您將找到一個books.module.ts文件:
// src/books/books/module.ts
import { Module } from '@nestjs/common';
@Module({})
export class BooksModule {}
這是由命令生成的竿屹,該模塊也已添加到app.module.ts中,該碰巧是應(yīng)用程序的根模塊灸姊。
接下來拱燃,您將為端點(diǎn)創(chuàng)建路由
第3步 - 創(chuàng)建路由和控制器
正如之前提到的那樣,路由存在于控制器中力惯,因此你需要創(chuàng)建控制器用于處理各個端點(diǎn)碗誉。再次使用Nest CLI生成你的控制器召嘶,運(yùn)行以下命令:
nest generate controller books
這將在books文件夾中創(chuàng)建一個控制器。
由于我們暫時不會連接到數(shù)據(jù)庫哮缺,因此請為書店創(chuàng)建一個簡單的模擬數(shù)據(jù)苍蔬。 在src文件夾下,創(chuàng)建一個名為mocks的子文件夾蝴蜓,并在新創(chuàng)建的文件夾內(nèi)碟绑,創(chuàng)建一個名為books.mock.ts的新TypeScript文件,并在其中添加以下代碼:
// src/mocks/books.mock.ts
export const BOOKS = [
{ id: 1, title: 'First book', description: "This is the description for the first book", author: 'Olususi Oluyemi' },
{ id: 2, title: 'Second book', description: "This is the description for the second book", author: 'John Barry' },
{ id: 3, title: 'Third book', description: "This is the description for the third book", author: 'Clement Wilfred' },
{ id: 4, title: 'Fourth book', description: "This is the description for the fourth book", author: 'Christian nwamba' },
{ id: 5, title: 'Fifth book', description: "This is the description for the fifth book", author: 'Chris anderson' },
{ id: 6, title: 'Sixth book', description: "This is the description for the sixth book", author: 'Olususi Oluyemi' },
];
接下來茎匠,您將創(chuàng)建一個服務(wù)來保存書店的所有邏輯格仲。
第4步 – 搭建一個服務(wù)
運(yùn)行以下命令以生成服務(wù):
nest generate service books
此命令將在./src/books文件夾中創(chuàng)建一個名為books.service.ts的新文件。
接下來诵冒,打開新創(chuàng)建的文件并粘貼以下內(nèi)容:
// /src/books/books.service.ts
import { Injectable, HttpException } from '@nestjs/common';
import { BOOKS } from '../mocks/books.mock';
@Injectable()
export class BooksService {
books = BOOKS;
getBooks(): Promise<any> {
return new Promise(resolve => {
resolve(this.books);
});
}
getBook(bookID): Promise<any> {
let id = Number(bookID);
return new Promise(resolve => {
const book = this.books.find(book => book.id === id);
if (!book) {
throw new HttpException('Book does not exist!', 404);
}
resolve(book);
});
}
}
首先凯肋,您從Nest.js導(dǎo)入了需要用到的模塊,還從先前創(chuàng)建的模擬數(shù)據(jù)中導(dǎo)入了BOOKS汽馋。
接下來侮东,創(chuàng)建了兩個名為getBooks()和getBook()的不同方法,以從模擬數(shù)據(jù)中檢索書籍列表豹芯,并使用bookID作為參數(shù)僅獲取一本書悄雅。
接下來,在getBook()方法之后立即將以下方法添加到/src/books/books.service.ts中:
// src/books/books.service.ts
import { Injectable, HttpException } from '@nestjs/common';
import { BOOKS } from '../mocks/books.mock';
@Injectable()
export class BooksService {
books = BOOKS;
...
addBook(book): Promise<any> {
return new Promise(resolve => {
this.books.push(book);
resolve(this.books);
});
}
}
上面的方法將會用于添加一本新書到現(xiàn)存的列表中
最后铁蹈,添加最后一個方法宽闲,使用bookID作為參數(shù)刪除特定的書:
// src/books/books.service.ts
import { Injectable, HttpException } from '@nestjs/common';
import { BOOKS } from '../mocks/books.mock';
@Injectable()
export class BooksService {
books = BOOKS;
...
deleteBook(bookID): Promise<any> {
let id = Number(bookID);
return new Promise(resolve => {
let index = this.books.findIndex(book => book.id === id);
if (index === -1) {
throw new HttpException('Book does not exist!', 404);
}
this.books.splice(1, index);
resolve(this.books);
});
}
}
第5步 - 將服務(wù)注入控制器
在這里,您將通過構(gòu)造函數(shù)的方式使用依賴項(xiàng)注入設(shè)計(jì)模式將BooksService傳遞到BooksController中握牧。 打開先前創(chuàng)建的BooksController容诬,并將以下代碼粘貼到其中:
// src/books/books.controller.ts
import { Controller, Get, Param, Post, Body, Query, Delete } from '@nestjs/common';
import { BooksService } from './books.service';
import { CreateBookDTO } from './dto/create-book.dto';
@Controller('books')
export class BooksController {
constructor(private booksService: BooksService) { }
@Get()
async getBooks() {
const books = await this.booksService.getBooks();
return books;
}
@Get(':bookID')
async getBook(@Param('bookID') bookID) {
const book = await this.booksService.getBook(bookID);
return book;
}
@Post()
async addBook(@Body() createBookDTO: CreateBookDTO) {
const book = await this.booksService.addBook(createBookDTO);
return book;
}
@Delete()
async deleteBook(@Query() query) {
const books = await this.booksService.deleteBook(query.bookID);
return books;
}
}
首先,重要模塊是從@nestjs/common導(dǎo)入的沿腰,您還分別導(dǎo)入了BooksService和CreateBookDTO览徒。 CreateBookDTO是一個數(shù)據(jù)傳輸對象,它是一個TypeScript類颂龙,用于類型檢查并定義對象在創(chuàng)建新書時的外觀結(jié)構(gòu)习蓬。我們將稍后創(chuàng)建此DTO。
接下來厘托,您使用構(gòu)造函數(shù)將BooksService注入到控制器中友雳,并創(chuàng)建了四個不同的方法:
getBooks():用于獲取所有書籍的列表稿湿。它具有@Get()裝飾器铅匹。這有助于將發(fā)送到 /books 的任何GET請求映射到此控制器。
getBook():用于通過將bookID作為參數(shù)來檢索特定書籍的詳細(xì)信息饺藤。
addBook():用于創(chuàng)建新書并將其發(fā)布到現(xiàn)有書單中包斑。并且由于我們沒有持久化到數(shù)據(jù)庫中流礁,因此新添加的書將僅保存在內(nèi)存中。
deleteBook():用于通過傳遞bookID作為查詢參數(shù)來刪除一本書罗丰。
每個方法都附加有一個特殊的裝飾器神帅,這使得將每個HTTP請求路由到控制器內(nèi)的特定方法非常容易。
第6步 - 定義DTO
在上一部分中萌抵,您使用了一個稱為CreateBookDTO的數(shù)據(jù)傳輸對象找御。 要創(chuàng)建它,請導(dǎo)航到./src/books文件夾并創(chuàng)建一個新的子文件夾名稱dto绍填。 接下來霎桅,在新創(chuàng)建的文件夾中,創(chuàng)建另一個文件讨永,并將其命名為create-book.dto.ts并將以下內(nèi)容粘貼到其中:
// src/books/dto/create-book.dto.ts
export class CreateBookDTO {
readonly id: number;
readonly title: string;
readonly description: string;
readonly author: string;
}
您幾乎已經(jīng)完成了該應(yīng)用程序滔驶。 導(dǎo)航回到先前創(chuàng)建的./src/books/books.module.ts文件,并使用以下代碼對其進(jìn)行更新:
// src/books/books.module.ts
import { Module } from '@nestjs/common';
import { BooksController } from './books.controller';
import { BooksService } from './books.service';
@Module({
controllers: [BooksController],
providers: [BooksService]
})
export class BooksModule {}
如果當(dāng)前沒有運(yùn)行該應(yīng)用程序卿闹,請?jiān)俅螁樱?/p>
npm run start
然后使用postman來測試API
創(chuàng)建一些新書:
使用ID獲取一本書:
刪除一本書:
總結(jié)
在本教程中揭糕,您快速了解了Nest.js的基礎(chǔ)知識和基本構(gòu)建塊,然后構(gòu)建了RESTful API锻霎。
您會找到本教程的完整源代碼在GitHub上著角。