Getting Started with NestJS(譯)
原文地址:Getting Started with NestJS
介紹
如果您使用的是Node.js應用程式,則可能已經注意到,隨著時間的推移,它變得越來越難以維護。 您嚮應用程式新增新功能的次數越多,程式碼庫就越大。
Nest.js是用於構建高效,可靠和可擴充套件的應用程式的服務端Node.js框架。 它為後端應用程式提供了一種模組化結構,用於將程式碼組織到單獨的模組中。 它旨在消除程式碼庫的混亂。
受Angular的啟發,Nest.js使用TypeScript構建,並使用了Express.js,使其與大多數Express中介軟體相容。
在本文中,您將建立一個小的RESTful API,使使用者能夠在書店中獲取,建立和刪除圖書。
前提
要完成本教程,您將需要:
- Node.js的本地開發環境。移步如何安裝Node.js和建立本地開發環境
瞭解Nest.js的組成結構
以下是構建Nest.js應用程式時使用的組成部分
- Controllers
- Providers
- Modules
我們將從檢視controllers開始。 與大多數Web框架一樣,Nest.js中的controllers負責處理所有傳入請求,並將響應返回給應用程式的客戶端。 例如,如果您對特定端點(例如/home)進行API呼叫,則controllers將接收到該請求,並基於可用資源,它將返回適當的響應。
Nest.js的構建方式使路由機制能夠控制哪個控制器將負責處理特定請求。
要在Nest.js中定義一個controller,請建立一個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處理應用程式中的任何/ users GET請求並返回指定的適當響應。 控制器處理的其他HTTP請求包括POST,PUT,DELETE,我們將在本教程的後面部分看到。
建立controller後,需要將其新增到Module定義中,Nest.js才能輕鬆識別它。 這可以是根ApplicationModule或在應用程式內建立的任何其他模組。 有關更多資訊,請參見本文的Modules部分。
現在讓我們看一下providers。
如前所述,Nest.js受Angular的啟發很大,類似於Angular應用程式,您可以建立一個提供程式並將其注入到controllers或其他providers中。 這些providers也稱為服務,它們旨在抽象化任何形式的複雜性和邏輯。
Nest.js中的服務提供者是一個JavaScript類,其頂部帶有一個特殊的@Injectable()裝飾器。 例如,您可以建立一個服務來獲取使用者:
// 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;
}
}
上面建立的提供程式是帶有兩個方法create()和findAll()的類,可分別用於建立和返回所有使用者。為了方便進行型別檢查,使用了一個介面來指定方法應接收的元素的型別。
最後,讓我們看一下Modules。Modules使您可以對相關檔案進行分組。它們是用@Module裝飾器裝飾的Typescript檔案。該附加的裝飾器提供了Nest用來組織應用程式結構的元資料。
每個Nest.js應用程式必須至少具有一個模組,通常稱為根模組。這個根模組是頂層模組,通常對於一個小型應用程式就足夠了。建議將大型應用程式分為多個模組,因為這有助於維護應用程式的結構。
如果您有一個管理有關使用者的大量資料或功能的應用程式,則可以將controller,services和其他相關檔案分組到一個模組中,例如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 {}
在此示例中,我們匯出了一個包含UsersController和UsersService的UsersModule。 設定好此位置之後,我們可以繼續在應用程式的根模組中匯入和使用UsersModule,如以下程式碼片段所示:
...
import { UsersModule } from './users/users.module';
@Module({
...
})
export class AppModule { }
Nest.js中還有一些其他重要概念:
- DTO:資料傳輸物件是定義如何通過網路傳送資料的物件。
- 介面:TypeScript介面用於型別檢查和定義可以傳遞給控制器或Nest服務的資料型別。
- 依賴注入:依賴注入是一種用於提高應用程式效率和模組化的設計模式。 最大的框架經常使用它來保持程式碼的清潔和易於使用。 Nest.js也利用它來基本建立耦合元件。
通過這種模式,管理諸如控制器,提供程式和模組之類的構建塊之間的依賴性非常容易。 唯一需要做的就是在控制器的建構函式中定義依賴項,例如,UsersService(),如下所示:
...
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService){}
...
}
在簡要介紹了其中一些概念之後,您現在可以進入下一節,在這裡您將把到目前為止所獲得的所有知識投入使用,同時您還將學習如何使用Nest.js無縫構建RESTful API。
如本文前面所述,您將建立一個示例應用程式,以幫助您更好地瞭解Nest.js的一些核心概念。
該應用程式將專門用於書店。 在文章的結尾,您將建立一個微服務,該服務將使使用者能夠建立新書並向其現有書單新增很少的描述。 這可能來自資料庫,但是為了確保本文的簡潔性,我們還沒有真正將應用程式連線到資料庫。 但是,相反,我們將利用書籍的模擬資料,一旦建立了新書籍,我們將其推送並新增到列表中。
第1步 - 安裝Nest.js
為了搭建一個新的Nest.js應用程式,您將需要全域性安裝Nest CLI應用程式。 這是一個命令列工具,專門用於製作新的Nest.js應用並提供對多個命令的訪問許可權,以生成不同的檔案並生成結構良好的應用。
除了使用CLI工具之外,您還可以通過使用Git從GitHub克隆starter project安裝新的Nest.js應用程式。但出於本教程的目的,請執行以下命令來安裝Nest CLI:
npm install -g @nestjs/cli
這將使您可以訪問nest命令以進行專案安裝以及其他專案特定的命令。
接下來,執行以下命令以在開發目錄中安裝一個名為bookstore-nest的新專案:
nest new bookstore-nest
在安裝過程中,系統將詢問您一些問題,只需按照提示進行操作,然後做出相應的響應即可。 接下來,安裝完成後,將工作目錄切換到新建立的專案中:
cd bookstore-nest
啟動應用程式:
npm run start
您也可以執行以下命令來在專案中使用Nodemon:
// start the application using nodemon
npm run start:dev
在瀏覽器中導航到http://localhost:3000,您將看到Hello World!,如下圖所示:
第2步 - 在專案啟動後,讓我們建立根模組。
讓我們為書店生成一個模組。 為此,您將利用Nest CLI的檔案生成器。 執行以下命令為應用程式搭建新模組:
nest generate module books
這將在src資料夾中建立一個名為books的新資料夾。 在books資料夾中,您將找到一個books.module.ts檔案:
// src/books/books/module.ts
import { Module } from '@nestjs/common';
@Module({})
export class BooksModule {}
這是由命令生成的,該模組也已新增到app.module.ts中,該碰巧是應用程式的根模組。
接下來,您將為端點建立路由
第3步 - 建立路由和控制器
正如之前提到的那樣,路由存在於控制器中,因此你需要建立控制器用於處理各個端點。再次使用Nest CLI生成你的控制器,執行以下命令:
nest generate controller books
這將在books資料夾中建立一個控制器。
由於我們暫時不會連線到資料庫,因此請為書店建立一個簡單的模擬資料。 在src資料夾下,建立一個名為mocks的子資料夾,並在新建立的資料夾內,建立一個名為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' },
];
接下來,您將建立一個服務來儲存書店的所有邏輯。
第4步 – 搭建一個服務
執行以下命令以生成服務:
nest generate service books
此命令將在./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;
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匯入了需要用到的模組,還從先前建立的模擬資料中匯入了BOOKS。
接下來,建立了兩個名為getBooks()和getBook()的不同方法,以從模擬資料中檢索書籍列表,並使用bookID作為引數僅獲取一本書。
接下來,在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);
});
}
}
上面的方法將會用於新增一本新書到現存的列表中
最後,新增最後一個方法,使用bookID作為引數刪除特定的書:
// 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步 - 將服務注入控制器
在這裡,您將通過建構函式的方式使用依賴項注入設計模式將BooksService傳遞到BooksController中。 開啟先前建立的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匯入的,您還分別匯入了BooksService和CreateBookDTO。 CreateBookDTO是一個數據傳輸物件,它是一個TypeScript類,用於型別檢查並定義物件在建立新書時的外觀結構。我們將稍後建立此DTO。
接下來,您使用建構函式將BooksService注入到控制器中,並建立了四個不同的方法:
-
getBooks():用於獲取所有書籍的列表。它具有@Get()裝飾器。這有助於將傳送到 /books 的任何GET請求對映到此控制器。
-
getBook():用於通過將bookID作為引數來檢索特定書籍的詳細資訊。
-
addBook():用於建立新書並將其釋出到現有書單中。並且由於我們沒有持久化到資料庫中,因此新新增的書將僅儲存在記憶體中。
-
deleteBook():用於通過傳遞bookID作為查詢引數來刪除一本書。
每個方法都附加有一個特殊的裝飾器,這使得將每個HTTP請求路由到控制器內的特定方法非常容易。
第6步 - 定義DTO
在上一部分中,您使用了一個稱為CreateBookDTO的資料傳輸物件。 要建立它,請導航到./src/books資料夾並建立一個新的子資料夾名稱dto。 接下來,在新建立的資料夾中,建立另一個檔案,並將其命名為create-book.dto.ts並將以下內容貼上到其中:
// src/books/dto/create-book.dto.ts
export class CreateBookDTO {
readonly id: number;
readonly title: string;
readonly description: string;
readonly author: string;
}
您幾乎已經完成了該應用程式。 導航回到先前建立的./src/books/books.module.ts檔案,並使用以下程式碼對其進行更新:
// 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 {}
如果當前沒有執行該應用程式,請再次啟動:
npm run start
然後使用postman來測試API
建立一些新書:
使用ID獲取一本書:
刪除一本書:
總結
在本教程中,您快速瞭解了Nest.js的基礎知識和基本構建塊,然後構建了RESTful API。
您會找到本教程的完整原始碼在GitHub上。