1. 程式人生 > 實用技巧 >Getting Started with NestJS(譯)

Getting Started with NestJS(譯)

原文地址:Getting Started with NestJS

介紹

如果您使用的是Node.js應用程式,則可能已經注意到,隨著時間的推移,它變得越來越難以維護。 您嚮應用程式新增新功能的次數越多,程式碼庫就越大。

Nest.js是用於構建高效,可靠和可擴充套件的應用程式的服務端Node.js框架。 它為後端應用程式提供了一種模組化結構,用於將程式碼組織到單獨的模組中。 它旨在消除程式碼庫的混亂。

Angular的啟發,Nest.js使用TypeScript構建,並使用了Express.js,使其與大多數Express中介軟體相容。

在本文中,您將建立一個小的RESTful API,使使用者能夠在書店中獲取,建立和刪除圖書。

前提

要完成本教程,您將需要:

瞭解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工具之外,您還可以通過使用GitGitHub克隆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上