Getting Started with NestJS(譯)

原文地址: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)建和刪除圖書盾似。

前提

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

了解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工具之外野来,您還可以通過使用GitGitHub克隆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狗超!,如下圖所示:

image

第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

image

創(chuàng)建一些新書:

image

使用ID獲取一本書:

image

刪除一本書:

image

總結(jié)

在本教程中揭糕,您快速了解了Nest.js的基礎(chǔ)知識和基本構(gòu)建塊,然后構(gòu)建了RESTful API锻霎。

您會找到本教程的完整源代碼在GitHub上著角。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市旋恼,隨后出現(xiàn)的幾起案子雇寇,更是在濱河造成了極大的恐慌,老刑警劉巖蚌铜,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锨侯,死亡現(xiàn)場離奇詭異,居然都是意外死亡冬殃,警方通過查閱死者的電腦和手機(jī)囚痴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來审葬,“玉大人深滚,你說我怎么就攤上這事』辆酰” “怎么了痴荐?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長官册。 經(jīng)常有香客問我生兆,道長,這世上最難降的妖魔是什么膝宁? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任鸦难,我火速辦了婚禮根吁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘合蔽。我一直安慰自己击敌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布拴事。 她就那樣靜靜地躺著沃斤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪刃宵。 梳的紋絲不亂的頭發(fā)上轰枝,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機(jī)與錄音组去,去河邊找鬼鞍陨。 笑死,一個胖子當(dāng)著我的面吹牛从隆,可吹牛的內(nèi)容都是我干的诚撵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼键闺,長吁一口氣:“原來是場噩夢啊……” “哼寿烟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起辛燥,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤筛武,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后挎塌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徘六,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年榴都,在試婚紗的時候發(fā)現(xiàn)自己被綠了待锈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡嘴高,死狀恐怖竿音,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拴驮,我是刑警寧澤春瞬,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站套啤,受9級特大地震影響宽气,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一抹竹、第九天 我趴在偏房一處隱蔽的房頂上張望线罕。 院中可真熱鬧止潮,春花似錦窃判、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至燃乍,卻和暖如春唆樊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背刻蟹。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工逗旁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人舆瘪。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓片效,卻偏偏與公主長得像,于是被迫代替她去往敵國和親英古。 傳聞我的和親對象是個殘疾皇子淀衣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評論 2 355