NestJS 是一個卓越的 Node.js 框架,最近獲得了開發者的廣泛喜愛和關注。本文將教您如何使用 NestJS、Prisma、PostgreSQL 和 Swagger 構建後端 REST API。
目錄
- 簡介
- 先決條件
- 生成 NestJS 專案
- 建立 PostgreSQL 例項
- 設定 Prisma
- 設定 Swagger
- 為
Article模型實現 CRUD 操作 - 更新 Swagger 響應型別
- 總結與最終說明
簡介
在本教程中,您將學習如何為一個名為“Median”(一個簡單的 Medium 克隆)的部落格應用構建後端 REST API。您將從建立一個新的 NestJS 專案開始。然後啟動您自己的 PostgreSQL 伺服器,並使用 Prisma 連線到它。最後,您將構建 REST API 並使用 Swagger 對其進行文件化。

您將使用的技術
您將使用以下工具來構建此應用程式
- NestJS 作為後端框架
- Prisma 作為物件關係對映器 (ORM)
- PostgreSQL 作為資料庫
- Swagger 作為 API 文件工具
- TypeScript 作為程式語言
先決條件
假定知識
這是一個對初學者友好的教程。但是,本教程假定您具有以下知識:
- JavaScript 或 TypeScript 的基本知識(首選)
- NestJS 的基本知識
注意:如果您不熟悉 NestJS,可以透過遵循概述部分在 NestJS 文件中快速學習基礎知識。
開發環境
要遵循本教程,您需要:
- ... 安裝 Node.js。
- ... 安裝 Docker 或 PostgreSQL。
- ... 安裝 Prisma VSCode 擴充套件。(可選)
- ... 能夠訪問 Unix shell(如 Linux 和 macOS 中的終端/shell)以執行本系列中提供的命令。(可選)
注意 1:可選的 Prisma VSCode 擴充套件為 Prisma 提供了非常出色的智慧感知和語法高亮。
注意 2:如果您沒有 Unix shell(例如,您在 Windows 機器上),您仍然可以遵循本教程,但 shell 命令可能需要根據您的機器進行修改。
生成 NestJS 專案
您首先需要安裝 NestJS CLI。NestJS CLI 在處理 NestJS 專案時非常方便。它內建了實用工具,可幫助您初始化、開發和維護 NestJS 應用程式。
您可以使用 NestJS CLI 建立一個空專案。首先,在您希望專案所在的目錄中執行以下命令:
CLI 將提示您為專案選擇一個包管理器——請選擇 npm。之後,您應該在當前目錄中擁有一個新的 NestJS 專案。
在您首選的程式碼編輯器中開啟專案(我們推薦 VSCode)。您應該看到以下檔案:
您大部分的程式碼都將位於 src 目錄中。NestJS CLI 已經為您建立了一些檔案。其中一些值得注意的檔案是:
src/app.module.ts:應用程式的根模組。src/app.controller.ts:一個基本的控制器,包含一個路由:/。此路由將返回一個簡單的'Hello World!'訊息。src/main.ts:應用程式的入口點。它將啟動 NestJS 應用程式。
您可以使用以下命令啟動您的專案:
此命令將監視您的檔案,並在您進行更改時自動重新編譯和重新載入伺服器。要驗證伺服器是否正在執行,請訪問 URL https://:3000/。您應該會看到一個空白頁面,上面顯示著訊息 'Hello World!'。
注意:在您學習本教程時,應保持伺服器在後臺執行。
建立 PostgreSQL 例項
您將使用 PostgreSQL 作為 NestJS 應用程式的資料庫。本教程將向您展示如何透過 Docker 容器在您的機器上安裝和執行 PostgreSQL。
注意:如果您不想使用 Docker,您可以原生設定 PostgreSQL 例項或在Heroku 上獲取託管的 PostgreSQL 資料庫。
首先,在專案主資料夾中建立一個 docker-compose.yml 檔案:
這個 docker-compose.yml 檔案是一個配置檔案,它將包含執行一個內建 PostgreSQL 的 Docker 容器的規範。在檔案中建立以下配置:
關於此配置,有幾點需要理解:
- The
image選項定義要使用的 Docker 映象。這裡,您正在使用postgres映象版本 13.5。 - The
environment選項指定在初始化期間傳遞給容器的環境變數。您可以在此處定義容器將使用的配置選項和秘密——例如使用者名稱和密碼。 - The
volumes選項用於在主機檔案系統中持久化資料。 - The
ports選項將主機機器的埠對映到容器。格式遵循'host_port:container_port'約定。在這種情況下,您將主機機器的埠5432對映到postgres容器的埠5432。5432通常是 PostgreSQL 使用的埠。
確保您的機器的埠 5432 上沒有執行任何其他程式。要啟動 postgres 容器,請開啟一個新的終端視窗並在專案主資料夾中執行以下命令:
如果一切正常,新的終端視窗應該顯示資料庫系統已準備好接受連線的日誌。您應該在終端視窗中看到與以下內容相似的日誌:
恭喜 🎉!您現在擁有了自己的 PostgreSQL 資料庫可以操作了!
注意:如果您關閉終端視窗,它也將停止容器。您可以透過在命令末尾新增
-d選項來避免這種情況,例如:docker-compose up -d。這將在後臺無限期地執行容器。
設定 Prisma
資料庫已準備就緒,現在是時候設定 Prisma 了!
初始化 Prisma
首先,安裝 Prisma CLI 作為開發依賴。Prisma CLI 將允許您執行各種命令並與您的專案進行互動。
您可以透過執行以下命令在專案中初始化 Prisma:
這將建立一個新的 prisma 目錄,其中包含 schema.prisma 檔案。這是包含您資料庫模式的主要配置檔案。此命令還會在您的專案中建立一個 .env 檔案。
設定您的環境變數
在 .env 檔案中,您應該會看到一個 DATABASE_URL 環境變數,其中包含一個虛擬連線字串。將其替換為您的 PostgreSQL 例項的連線字串。
注意:如果您沒有使用 Docker(如上一節所示)來建立 PostgreSQL 資料庫,您的連線字串將與上面所示的不同。PostgreSQL 的連線字串格式可在Prisma 文件中找到。
理解 Prisma 模式
如果您開啟 prisma/schema.prisma,您應該會看到以下預設模式:
此檔案採用 Prisma 模式語言編寫,Prisma 使用該語言定義您的資料庫模式。schema.prisma 檔案包含三個主要組成部分:
- 資料來源:指定您的資料庫連線。上述配置意味著您的資料庫提供者是 PostgreSQL,並且資料庫連線字串可在
DATABASE_URL環境變數中找到。 - 生成器:指示您要生成 Prisma Client,這是一個用於您資料庫的型別安全查詢構建器。它用於向資料庫傳送查詢。
- 資料模型:定義您的資料庫模型。每個模型都將對映到底層資料庫中的一個表。目前您的模式中沒有模型,您將在下一節中探討這部分內容。
注意:有關 Prisma 模式的更多資訊,請查閱Prisma 文件。
資料建模
現在是時候為您的應用程式定義資料模型了。對於本教程,您只需要一個 Article 模型來表示部落格上的每篇文章。
在 prisma/prisma.schema 檔案中,為您的模式新增一個名為 Article 的新模型:
這裡,您建立了一個包含多個欄位的 Article 模型。每個欄位都有一個名稱(id、title 等)、一個型別(Int、String 等)以及其他可選屬性(@id、@unique 等)。透過在欄位型別後新增 ? 可以使欄位變為可選。
The id 欄位有一個名為 @id 的特殊屬性。此屬性表示該欄位是模型的主鍵。@default(autoincrement()) 屬性表示該欄位應自動遞增並分配給任何新建立的記錄。
The published 欄位是一個標誌,用於指示文章是已釋出還是處於草稿模式。@default(false) 屬性表示此欄位預設應設定為 false。
兩個 DateTime 欄位 createdAt 和 updatedAt 將跟蹤文章的建立時間和上次更新時間。@updatedAt 屬性將在文章修改時自動用當前時間戳更新該欄位。
遷移資料庫
定義好 Prisma 模式後,您將執行遷移以在資料庫中建立實際的表。要生成並執行您的第一次遷移,請在終端中執行以下命令:
此命令將執行三件事:
- 儲存遷移:Prisma Migrate 將對您的模式進行快照,並計算出執行遷移所需的 SQL 命令。Prisma 會將包含 SQL 命令的遷移檔案儲存到新建立的
prisma/migrations資料夾中。 - 執行遷移:Prisma Migrate 將執行遷移檔案中的 SQL,以在您的資料庫中建立底層表。
- 生成 Prisma Client:Prisma 將根據您最新的模式生成 Prisma Client。由於您尚未安裝 Client 庫,CLI 也會為您安裝。您應該會在
package.json檔案的dependencies中看到@prisma/client包。Prisma Client 是一個從您的 Prisma 模式自動生成的 TypeScript 查詢構建器。它針對您的 Prisma 模式進行了定製,並將用於向資料庫傳送查詢。
注意:您可以在Prisma 文件中瞭解更多關於 Prisma Migrate 的資訊。
如果成功完成,您應該會看到類似以下的訊息:
檢查生成的遷移檔案,以瞭解 Prisma Migrate 在幕後做了什麼:
注意:您的遷移檔名會略有不同。
這是在您的 PostgreSQL 資料庫中建立 Article 表所需的 SQL。它是 Prisma 根據您的 Prisma 模式自動生成和執行的。
填充資料庫
當前資料庫是空的。因此,您將建立一個種子指令碼,用一些虛擬資料填充資料庫。
首先,建立一個名為 prisma/seed.ts 的種子檔案。此檔案將包含填充資料庫所需的虛擬資料和查詢。
然後,在種子檔案中新增以下程式碼:
在此指令碼中,您首先初始化 Prisma Client。然後,您使用 prisma.upsert() 函式建立兩篇文章。upsert 函式僅在沒有文章與 where 條件匹配時才建立新文章。您使用 upsert 查詢而不是 create 查詢,因為 upsert 可以避免意外嘗試插入相同記錄兩次所產生的錯誤。
您需要告訴 Prisma 在執行種子命令時執行哪個指令碼。您可以透過將 prisma.seed 鍵新增到 package.json 檔案末尾來完成此操作:
The seed 命令將執行您之前定義的 prisma/seed.ts 指令碼。此命令應該自動工作,因為 ts-node 已作為開發依賴安裝在您的 package.json 中。
使用以下命令執行資料填充:
您應該會看到以下輸出:
注意:您可以在Prisma 文件中瞭解更多關於資料填充的資訊。
建立 Prisma 服務
在您的 NestJS 應用程式中,最佳實踐是將 Prisma Client API 從應用程式中抽象出來。為此,您將建立一個包含 Prisma Client 的新服務。這個名為 PrismaService 的服務將負責例項化 PrismaClient 例項並連線到您的資料庫。
Nest CLI 提供了一種從命令列直接生成模組和服務的方式。在您的終端中執行以下命令:
注意 2:在某些情況下,當伺服器已在執行時執行
nest generate命令,可能導致 NestJS 丟擲異常,提示:Error: Cannot find module './app.controller'。如果您遇到此錯誤,請在終端中執行以下命令:rm -rf dist,然後重新啟動伺服器。
這應該會生成一個新的子目錄 ./src/prisma,其中包含 prisma.module.ts 和 prisma.service.ts 檔案。服務檔案應包含以下程式碼:
Prisma 模組將負責建立 單例例項的 PrismaService,並允許在整個應用程式中共享該服務。為此,您將把 PrismaService 新增到 prisma.module.ts 檔案中的 exports 陣列:
現在,任何匯入 PrismaModule 的模組都將可以訪問 PrismaService,並可以將其注入到自己的元件/服務中。這是 NestJS 應用程式的常見模式。
至此,您已完成 Prisma 的設定!現在您可以開始構建 REST API 了。
設定 Swagger
Swagger 是一個使用OpenAPI 規範來文件化您的 API 的工具。Nest 有一個專門用於 Swagger 的模組,您將很快使用它。
首先安裝所需的依賴:
現在開啟 main.ts 並使用 SwaggerModule 類初始化 Swagger:
應用程式執行時,開啟瀏覽器並導航到 https://:3000/api。您應該會看到 Swagger UI。

為 Article 模型實現 CRUD 操作
在本節中,您將為 Article 模型實現建立、讀取、更新和刪除 (CRUD) 操作以及任何附帶的業務邏輯。
生成 REST 資源
在實現 REST API 之前,您需要為 Article 模型生成 REST 資源。這可以使用 Nest CLI 快速完成。在您的終端中執行以下命令:
您會收到一些 CLI 提示。請相應地回答問題:
What name would you like to use for this resource (plural, e.g., "users")?articlesWhat transport layer do you use?REST APIWould you like to generate CRUD entry points?Yes
您現在應該會找到一個新的 src/articles 目錄,其中包含您的 REST 端點的所有樣板程式碼。在 src/articles/articles.controller.ts 檔案中,您將看到不同路由(也稱為路由處理程式)的定義。處理每個請求的業務邏輯封裝在 src/articles/articles.service.ts 檔案中。目前,此檔案包含模擬實現。
如果您再次開啟 Swagger API 頁面,您應該會看到類似以下內容:

The SwaggerModule 會搜尋路由處理程式上的所有 @Body()、@Query() 和 @Param() 裝飾器來生成此 API 頁面。
將 PrismaClient 新增到 Articles 模組
要在 Articles 模組中訪問 PrismaClient,您必須將 PrismaModule 作為匯入新增。將以下 imports 新增到 ArticlesModule:
現在,您可以在 ArticlesService 內部注入 PrismaService 並使用它來訪問資料庫。為此,請在 articles.service.ts 中新增一個建構函式,如下所示:
定義 GET /articles 端點
此端點的控制器名為 findAll。此端點將返回資料庫中所有已釋出的文章。findAll 控制器如下所示:
您需要更新 ArticlesService.findAll() 以返回資料庫中所有已釋出文章的陣列:
The findMany 查詢將返回所有符合 where 條件的 article 記錄。
您可以透過訪問 https://:3000/api 並點選 GET/articles 下拉選單來測試該端點。點選 Try it out (嘗試一下),然後點選 Execute (執行) 以檢視結果。

注意:您也可以直接在瀏覽器中或透過 REST 客戶端(例如 Postman)執行所有請求。Swagger 還會為每個請求生成 curl 命令,以防您想在終端中執行 HTTP 請求。
定義 GET /articles/drafts 端點
您將定義一個新的路由來獲取所有未釋出的文章。NestJS 沒有自動為該端點生成控制器路由處理程式,因此您必須自己編寫。
您的編輯器應該會顯示一個錯誤,提示不存在名為 articlesService.findDrafts() 的函式。要解決此問題,請在 ArticlesService 中實現 findDrafts 方法:
The GET /articles/drafts 端點現在將在 Swagger API 頁面中可用。
注意:我建議您在完成每個端點實現後,透過 Swagger API 頁面對其進行測試。
定義 GET /articles/:id 端點
此端點的控制器路由處理程式名為 findOne。它看起來像這樣:
該路由接受一個動態的 id 引數,該引數被傳遞給 findOne 控制器路由處理程式。由於 Article 模型有一個整數 id 欄位,因此需要使用 + 運算子將 id 引數轉換為數字。
現在,更新 ArticlesService 中的 findOne 方法,以返回具有給定 ID 的文章:
再次,透過訪問 https://:3000/api 來測試該端點。點選 GET /articles/{id} 下拉選單。點選 Try it out (嘗試一下),為 id 引數新增一個有效值,然後點選 Execute (執行) 以檢視結果。

定義 POST /articles 端點
這是用於建立新文章的端點。此端點的控制器路由處理程式名為 create。它看起來像這樣:
注意,它期望請求正文中包含 CreateArticleDto 型別的引數。DTO(資料傳輸物件)是一個定義資料如何透過網路傳送的物件。目前,CreateArticleDto 是一個空類。您將向其中新增屬性以定義請求正文的形狀。
The @ApiProperty 裝飾器是必需的,以使類屬性對 SwaggerModule 可見。有關此內容的更多資訊可在NestJS 文件中找到。
The CreateArticleDto 現在應該在 Swagger API 頁面中的 Schemas (模式) 下定義。UpdateArticleDto 的形狀是根據 CreateArticleDto 的定義自動推斷的。因此,UpdateArticleDto 也在 Swagger 中定義。

現在更新 ArticlesService 中的 create 方法,以在資料庫中建立新文章:
定義 PATCH /articles/:id 端點
此端點用於更新現有文章。此端點的路由處理程式名為 update。它看起來像這樣:
The updateArticleDto 的定義被定義為 CreateArticleDto 的PartialType。因此,它可以擁有 CreateArticleDto 的所有屬性。
就像之前一樣,您必須更新此操作對應的服務方法:
The article.update 操作將嘗試查詢具有給定 id 的 Article 記錄,並使用 updateArticleDto 的資料對其進行更新。
如果在資料庫中未找到此類 Article 記錄,Prisma 將返回錯誤。在這種情況下,API 不會返回使用者友好的錯誤訊息。您將在未來的教程中學習 NestJS 的錯誤處理。
定義 DELETE /articles/:id 端點
此端點用於刪除現有文章。此端點的路由處理程式名為 remove。它看起來像這樣:
就像之前一樣,前往 ArticlesService 並更新相應的方法:
這是 articles 端點的最後一個操作。恭喜,您的 API 幾乎準備就緒!🎉
在 Swagger 中分組端點
為 ArticlesController 類新增 @ApiTags 裝飾器,以便在 Swagger 中將所有 articles 端點分組在一起:
The API 頁面現在將 articles 端點分組在一起。

更新 Swagger 響應型別
如果您檢視 Swagger 中每個端點下的響應 (Responses) 選項卡,您會發現描述 (Description) 是空的。這是因為 Swagger 不知道任何端點的響應型別。您將使用一些裝飾器來解決這個問題。
首先,您需要定義一個實體,Swagger 可以用它來識別返回的 entity 物件的形狀。為此,請按如下方式更新 articles.entity.ts 檔案中的 ArticleEntity 類:
這是 Prisma Client 生成的 Article 型別的一個實現,為每個屬性添加了 @ApiProperty 裝飾器。
現在,是時候使用正確的響應型別來標註控制器路由處理程式了。NestJS 為此提供了一組裝飾器。
您為 GET、PATCH 和 DELETE 端點添加了 @ApiOkResponse,併為 POST 端點添加了 @ApiCreatedResponse。type 屬性用於指定返回型別。您可以在NestJS 文件中找到 NestJS 提供的所有響應裝飾器。
現在,Swagger 應該在 API 頁面上正確定義所有端點的響應型別。

總結與最終說明
恭喜!您已經使用 NestJS 構建了一個基本的 REST API。在本教程中,您:
- 使用 NestJS 構建了 REST API
- 在 NestJS 專案中順利集成了 Prisma
- 使用 Swagger 和 OpenAPI 文件化了您的 REST API
本教程的主要收穫之一是使用 NestJS 和 Prisma 構建 REST API 是多麼容易。這是一個極具生產力的技術棧,可用於快速構建結構良好、型別安全且易於維護的後端應用程式。
您可以在 GitHub 上找到此專案的原始碼。如果您發現問題,請隨時在倉庫中提出問題或提交 PR。您也可以直接在 Twitter 上聯絡我。
不要錯過下一篇文章!
訂閱 Prisma 郵件列表