国内精品久久久久影院日本,日本中文字幕视频,99久久精品99999久久,又粗又大又黄又硬又爽毛片

所有文章 > 如何集成API > 使用 NestJS 和 Prisma 構(gòu)建 REST API:錯誤處理
使用 NestJS 和 Prisma 構(gòu)建 REST API:錯誤處理

使用 NestJS 和 Prisma 構(gòu)建 REST API:錯誤處理

歡迎來到本系列教程的第三課,我們將探討如何使用 NestJS、Prisma 和 PostgreSQL 構(gòu)建 REST API。在這一課里,您將學(xué)習(xí)到如何在 NestJS 應(yīng)用中實施有效的錯誤處理機制。

使用 NestJS 和 Prisma 構(gòu)建 REST API:錯誤處理

介紹

在本系列教程的第一章中,您已經(jīng)成功創(chuàng)建了一個新的 NestJS 項目,并將其與 Prisma、PostgreSQL 數(shù)據(jù)庫以及 Swagger 進(jìn)行了集成。在此基礎(chǔ)上,您為博客應(yīng)用程序的后端構(gòu)建了一個基礎(chǔ)的 REST API。進(jìn)入第二章,您深入學(xué)習(xí)了如何進(jìn)行輸入驗證和轉(zhuǎn)換,以提升數(shù)據(jù)的準(zhǔn)確性和安全性。

在本章中,您將學(xué)習(xí)如何處理 NestJS 中的錯誤。您將了解兩種不同的策略:

  1. 首先,您將學(xué)習(xí)如何在 API 的控制器內(nèi)直接在應(yīng)用程序代碼中檢測和拋出錯誤。
  2. 接下來,您將學(xué)習(xí)如何使用異常過濾器來處理整個應(yīng)用程序中未處理的異常。

在本教程中,您只需使用在第一章中構(gòu)建的 REST API 即可。無需完成第二章的學(xué)習(xí),您也可以直接開始本章的教程。

開發(fā)環(huán)境

要學(xué)習(xí)本教程,您需要具備以下條件:

  • 已安裝Node.js。
  • 已安裝?Docker?和?Docker Compose。如果您使用的是 Linux,請確保您的 Docker 版本為 20.10.0 或更高版本。您可以通過在終端中運行?docker version?命令來檢查 Docker 版本。
  • (可選)安裝 Prisma VS Code 擴展。Prisma VS Code 擴展為 Prisma 添加了一些友好的 IntelliSense 和語法高亮顯示。
  • 可以選擇使用 Unix shell(如 Linux 和 macOS 中的終端/shell)來運行本系列教程中提供的命令。

如果您沒有 Unix shell(例如,您使用的是 Windows 計算機),您仍然可以繼續(xù)操作,但可能需要為您的計算機修改 shell 命令。

克隆存儲庫

本教程的起點是本系列第一部分教程的結(jié)束點。它包含了一個使用 NestJS 構(gòu)建的基礎(chǔ) REST API。

本教程的起點位于 end-rest-api-part-1 分支。要開始學(xué)習(xí),請克隆存儲庫并檢出該分支。

git clone -b end-rest-api-part-1 git@github.com:prisma/blog-backend-rest-api-nestjs-prisma.git

現(xiàn)在,執(zhí)行以下操作以開始使用:

  1. 導(dǎo)航到克隆的目錄:
cd blog-backend-rest-api-nestjs-prisma
  1. 安裝依賴項:
npm install
  1. 使用 Docker 啟動 PostgreSQL 數(shù)據(jù)庫:
docker-compose up -d
  1. 應(yīng)用數(shù)據(jù)庫遷移:
npx prisma migrate dev
  1. 啟動項目:
npm run start:dev

注意:步驟 4 還將生成 Prisma Client 并設(shè)定數(shù)據(jù)庫種子。

現(xiàn)在,您應(yīng)該能夠在以下位置訪問 API 文檔:http://localhost:3000/api/.

項目結(jié)構(gòu)和文件

您克隆的存儲庫應(yīng)具有以下結(jié)構(gòu):

median
├── node_modules
├── prisma
│ ├── migrations
│ ├── schema.prisma
│ └── seed.ts
├── src
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ ├── main.ts
│ ├── articles
│ └── prisma
├── test
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
├── README.md
├── .env
├── docker-compose.yml
├── nest-cli.json
├── package-lock.json
├── package.json
├── tsconfig.build.json
└── tsconfig.json

此存儲庫中值得注意的文件和目錄包括:

  • src 目錄:包含應(yīng)用程序的源代碼。該目錄下分為三個主要模塊:
    • app 模塊:位于 src 目錄的根目錄中,作為應(yīng)用程序的入口點,負(fù)責(zé)啟動 Web 服務(wù)器。
    • prisma 模塊:包含 Prisma Client,即您的數(shù)據(jù)庫接口。
    • articles 模塊:定義路由的端點和相關(guān)的業(yè)務(wù)邏輯。但注意,此處原描述中的“articles/articles”應(yīng)為筆誤,正常應(yīng)為 articles 目錄下的相關(guān)文件。
  • schema.prisma 文件:定義數(shù)據(jù)庫架構(gòu),位于 prisma 目錄下(注意,原描述中將 prisma 錯誤地重復(fù)列出在 articles 下)。
  • migrations 目錄:包含數(shù)據(jù)庫遷移的歷史記錄。
  • seed.ts 文件:包含一個腳本,用于使用虛擬數(shù)據(jù)為開發(fā)數(shù)據(jù)庫設(shè)定初始數(shù)據(jù)。
  • docker-compose.yml 文件:定義 PostgreSQL 數(shù)據(jù)庫的 Docker 映像。
  • .env 文件:包含 PostgreSQL 數(shù)據(jù)庫的數(shù)據(jù)庫連接字符串。

請注意,有關(guān)這些組件的更多詳細(xì)信息,請閱讀本教程系列的第一部分。

直接檢測并引發(fā)異常

本節(jié)將指導(dǎo)您如何在應(yīng)用程序代碼中直接觸發(fā)異常。您將針對一個終端節(jié)點的問題進(jìn)行修復(fù)。目前,若向該終端節(jié)點傳遞無效的值,它不會返回 HTTP 狀態(tài)碼,而是直接返回錯誤信息。

例如,對于 GET 請求 /articles/:id,如果傳遞的 ID(如 234235)不存在,則會出現(xiàn)問題。

請求不存在的文章會返回 HTTP 200

要解決此問題,您必須在 findOnearticles.controller.ts 文件中的方法做出更改。如果文章不存在,您應(yīng)該拋出一個 NotFoundException,這是 NestJS 提供的內(nèi)置異常。

更新 findOnearticles.controller.ts 文件中的相關(guān)方法。

// src/articles/articles.controller.ts

import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
NotFoundException,
} from '@nestjs/common';

@Get(':id')
@ApiOkResponse({ type: ArticleEntity })
findOne(@Param('id') id: string) {
return this.articlesService.findOne(+id);
async findOne(@Param('id') id: string) {
const article = await this.articlesService.findOne(+id);
if (!article) {
throw new NotFoundException(`Article with ${id} does not exist.`);
}
return article;
}

如果您再次發(fā)出相同的請求,您應(yīng)該會收到一條用戶友好的錯誤消息:

請求不存在的文章會返回 HTTP 404

使用異常篩選器處理異常

專用例外層的優(yōu)點

在上一節(jié)中,您學(xué)會了如何檢測錯誤狀態(tài)并手動拋出異常。然而,在許多情況下,應(yīng)用程序代碼會自動生成異常。此時,您應(yīng)該捕獲這些異常并向用戶返回合適的 HTTP 錯誤響應(yīng)。

盡管您可以在每個控制器中單獨處理異常,但這并非最佳實踐,原因如下:

  • 它將用大量錯誤處理代碼弄亂您的核心應(yīng)用程序邏輯。
  • 許多終端節(jié)點可能會遇到類似的錯誤,例如資源未找到。如果每個控制器都單獨處理這些錯誤,將會導(dǎo)致大量重復(fù)的代碼。
  • 由于錯誤處理邏輯分散在多個位置,因此很難對其進(jìn)行更改。

為了解決這些問題,NestJS 提供了一個異常層,用于處理整個應(yīng)用程序中未捕獲的異常。在 NestJS 中,您可以創(chuàng)建異常過濾器來定義如何響應(yīng)應(yīng)用程序內(nèi)部拋出的不同類型的異常。

NestJS 全局異常過濾器

NestJS 支持全局異常過濾器,它可以捕獲所有未處理的異常。為了理解全局異常過濾器的工作原理,我們來看一個示例。請向?/articles?終端節(jié)點發(fā)送 POST 請求,并觀察其響應(yīng)。

{
"title": "Let’s build a REST API with NestJS and Prisma.",
"description": "NestJS Series announcement.",
"body": "NestJS is one of the hottest Node.js frameworks around. In this series, you will learn how to build a backend REST API with NestJS, Prisma, PostgreSQL and Swagger.",
"published": true
}

第一個請求將會成功,但第二個請求會因為您已經(jīng)創(chuàng)建了具有相同標(biāo)題(title)的文章而失敗。您將會收到一個與標(biāo)題相關(guān)的錯誤。

{
"statusCode": 500,
"message": "Internal server error"
}

如果您查看運行 NestJS 服務(wù)器的終端窗口,您應(yīng)該會看到以下錯誤:

[Nest] 6803  - 12/06/2022, 3:25:40 PM   ERROR [ExceptionsHandler]
Invalid `this.prisma.article.create()` invocation in
/Users/tasinishmam/my-code/median/src/articles/articles.service.ts:11:32

8 constructor(private prisma: PrismaService) {}
9
10 create(createArticleDto: CreateArticleDto) {
→ 11 return this.prisma.article.create(
Unique constraint failed on the fields: (`title`)
Error:
Invalid `this.prisma.article.create()` invocation in
/Users/tasinishmam/my-code/median/src/articles/articles.service.ts:11:32
8 constructor(private prisma: PrismaService) {}
9
10 create(createArticleDto: CreateArticleDto) {
→ 11 return this.prisma.article.create(
Unique constraint failed on the fields: (`title`)

從日志中,您可以觀察到 Prisma Client 因為某個字段觸發(fā)了唯一性約束驗證錯誤,該字段在 Prisma 架構(gòu)中被標(biāo)記為唯一。引發(fā)的異常類型是?PrismaClientKnownRequestError,并且這個異常在 Prisma 的命名空間級別被導(dǎo)出。具體地說,是因為?title?字段的唯一性約束導(dǎo)致了這個問題。

由于這個異常不是由您的應(yīng)用程序直接捕獲和處理的,因此它會被內(nèi)置的全局異常過濾器自動捕獲。然而,這個全局異常過濾器默認(rèn)生成的是 HTTP “Internal Server Error”(500)響應(yīng)。

創(chuàng)建手動異常篩選條件

在本節(jié)中,您將創(chuàng)建一個自定義的異常過濾器來處理上述類型的異常。這個自定義過濾器將能夠捕獲所有類型的異常,并且能夠為用戶返回清晰、友好的錯誤消息,特別是針對?PrismaClientKnownRequestError?這類異常。

首先使用 Nest CLI 生成過濾器類:

npx nest generate filter prisma-client-exception

這將創(chuàng)建一個名為 src/prisma-client-exception.filter.ts 的新文件。

// src/prisma-client-exception.filter.ts

import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';

@Catch()
export class PrismaClientExceptionFilter<T> implements ExceptionFilter {
catch(exception: T, host: ArgumentsHost) {}
}

注意:請注意,已創(chuàng)建了一個名為 prisma-client-exception.filter.spec.ts 的測試文件。目前,您可以暫時忽略這個文件。

由于 prisma-client-exception.filter.ts 中的方法實現(xiàn)為空,您可能會收到來自 ESLint 的錯誤提示。為了解決這個問題,您需要更新該方法以實現(xiàn)一個捕獲 Prisma 客戶端異常的過濾器。這里假設(shè)您已經(jīng)有了相關(guān)的實現(xiàn)計劃或代碼框架。

// src/prisma-client-exception.filter.ts

import { ArgumentsHost, Catch } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
import { Prisma } from '@prisma/client';

@Catch(Prisma.PrismaClientKnownRequestError) // 1
export class PrismaClientExceptionFilter extends BaseExceptionFilter { // 2
catch(exception: Prisma.PrismaClientKnownRequestError, host: ArgumentsHost) {
console.error(exception.message); // 3

// default 500 error code
super.catch(exception, host);
}
}

在這里,您進(jìn)行了以下更改:

  1. 為了確保此過濾器能夠捕獲?PrismaClientKnownRequestError?類型的異常,您將其添加到了?@Catch(PrismaClientKnownRequestError)?裝飾器中。
  2. 異常過濾器擴展了 NestJS 核心包中的 BaseExceptionFilter 類,該類為向用戶返回“Internal server error”響應(yīng)的方法提供了默認(rèn)實現(xiàn)。您可以在 NestJS 文檔中了解更多相關(guān)信息。
  3. 您添加了一個 console.error 語句,用于將錯誤消息記錄到控制臺,這對于調(diào)試目的非常有用。

由于 Prisma 會引發(fā)許多不同類型的錯誤,您需要弄清楚如何從捕獲的異常中提取錯誤代碼。異常對象具有一個包含錯誤代碼的屬性,您可以在 Prisma 錯誤消息參考中找到所有錯誤代碼的列表。

您要查找的錯誤代碼是?P2002,它通常發(fā)生在唯一約束沖突中。接下來,您將更新?catch?方法,以便在捕獲到此錯誤時引發(fā)一個帶有 HTTP 409 Conflict 狀態(tài)碼的響應(yīng),并向用戶提供自定義錯誤消息。

更新您的異常過濾器實現(xiàn),如下所示:

//src/prisma-client-exception.filter.ts

import { ArgumentsHost, Catch, HttpStatus } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
import { Prisma } from '@prisma/client';
import { Response } from 'express';

@Catch(Prisma.PrismaClientKnownRequestError)
export class PrismaClientExceptionFilter extends BaseExceptionFilter {
catch(exception: Prisma.PrismaClientKnownRequestError, host: ArgumentsHost) {
console.error(exception.message);
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const message = exception.message.replace(/\n/g, '');

switch (exception.code) {
case 'P2002': {
const status = HttpStatus.CONFLICT;
response.status(status).json({
statusCode: status,
message: message,
});
break;
}
default:
// default 500 error code
super.catch(exception, host);
break;
}
}
}

在這里,您將訪問底層框架對象并直接修改響應(yīng)。默認(rèn)情況下,express 是 NestJS 在后臺使用的 HTTP 框架。對于除 之外的任何異常代碼,您將發(fā)送默認(rèn)的 “Internal server error” 響應(yīng)。

注意:對于生產(chǎn)應(yīng)用程序,請注意不要在錯誤消息中向用戶泄露任何敏感信息。

將異常篩選器應(yīng)用于應(yīng)用程序

要使?PrismaClientExceptionFilter?生效,您需要將其應(yīng)用于適當(dāng)?shù)姆秶.惓_^濾器的應(yīng)用范圍可以是單個路由(方法級)、整個控制器(控制器級)或整個應(yīng)用程序(全局級)。

為了將異常過濾器應(yīng)用于整個應(yīng)用程序,請更新 main.ts 文件。

// src/main.ts

import { HttpAdapterHost, NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { PrismaClientExceptionFilter } from './prisma-client-exception.filter';

async function bootstrap() {
const app = await NestFactory.create(AppModule);

const config = new DocumentBuilder()
.setTitle('Median')
.setDescription('The Median API description')
.setVersion('0.1')
.build();

const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);

const { httpAdapter } = app.get(HttpAdapterHost);
app.useGlobalFilters(new PrismaClientExceptionFilter(httpAdapter));

await app.listen(3000);
}
bootstrap();

現(xiàn)在,嘗試向 /articles 終端節(jié)點再次發(fā)出相同的 POST 請求。

{
"title": "Let’s build a REST API with NestJS and Prisma.",
"description": "NestJS Series announcement.",
"body": "NestJS is one of the hottest Node.js frameworks around. In this series, you will learn how to build a backend REST API with NestJS, Prisma, PostgreSQL and Swagger.",
"published": true
}

這次,您將收到一個更用戶友好的錯誤消息:

{
"statusCode": 409,
"message": "Invalid `this.prisma.article.create()` invocation in /Users/tasinishmam/my-code/median/src/articles/articles.service.ts:11:32 8 constructor(private prisma: PrismaService) {} 9 10 create(createArticleDto: CreateArticleDto) {→ 11 return this.prisma.article.create(Unique constraint failed on the fields: (`title`)"
}

由于?PrismaClientExceptionFilter?是一個全局過濾器,因此它能夠為應(yīng)用程序中的所有路由處理?PrismaClientKnownRequestError?這種特定類型的錯誤。

我建議您進(jìn)一步擴展異常過濾器的實現(xiàn),以處理其他類型的錯誤。例如,您可以添加一個分支來處理錯誤代碼 P2025,這個錯誤代碼通常在數(shù)據(jù)庫中找不到記錄時出現(xiàn)。對于這種情況,您應(yīng)該返回 HttpStatus.NOT_FOUND 狀態(tài)碼。這對于 PATCH /articles/:id 和 DELETE /articles/:id 端點特別有用,因為這些操作通常依賴于特定記錄的存在。

使用nest js-prime包處理 Prisma 異常

到目前為止,您已經(jīng)了解了在 NestJS 應(yīng)用程序中手動處理 Prisma 異常的不同技術(shù)。有一個用于將 Prisma 與 NestJS 一起使用的專用包,稱為nestjs-prisma您還可以使用它來處理 Prisma 異常。此包是一個很好的考慮選擇,因為它刪除了大量樣板代碼。

有關(guān)如何安裝和使用 nestjs-prisma 包的詳細(xì)說明,請參考其官方文檔。使用此包時,您無需手動創(chuàng)建與 Prisma 相關(guān)的單獨模塊和服務(wù),因為這些都會由包自動為您生成。

在?nestjs-prisma?文檔的“Exception Filter”部分,您可以了解到如何使用該包來處理 Prisma 異常。在本教程的后續(xù)章節(jié)中,我們將更深入地介紹這個軟件包。

總結(jié)和結(jié)束語

祝賀!在本教程中,您獲取了一個現(xiàn)有的 NestJS 應(yīng)用程序,并學(xué)習(xí)了如何集成錯誤處理。您學(xué)習(xí)了兩種不同的錯誤處理方法:直接在應(yīng)用程序代碼中處理和創(chuàng)建異常過濾器。

在本章中,您特別學(xué)習(xí)了如何處理由 Prisma 引發(fā)的錯誤。但請注意,這些技術(shù)不僅適用于 Prisma,它們同樣可以用于處理應(yīng)用程序中的其他任何類型錯誤。

您可以在 end-error-handling-part-3 分支上找到本教程的結(jié)束點。如果您在學(xué)習(xí)過程中遇到問題,請隨時在存儲庫中提出疑問或提交 PR(Pull Request)。當(dāng)然,您也可以直接在 Twitter 上與我聯(lián)系。

原文鏈接:https://www.prisma.io/blog/nestjs-prisma-error-handling-7D056s1kOop2

#你可能也喜歡這些API文章!