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

所有文章 > 如何集成API > 使用NestJS和Prisma構建REST API:輸入驗證和轉換
使用NestJS和Prisma構建REST API:輸入驗證和轉換

使用NestJS和Prisma構建REST API:輸入驗證和轉換

歡迎來到使用 NestJS、Prisma 和 PostgreSQL 構建 REST API 系列教程的第二個教程!在本教程中,您將學習如何在 API 中執行輸入數據的驗證和轉換。

使用NestJS和Prisma構建REST API:輸入驗證和轉換

介紹

在本系列教程的第一部分中,您已經成功創建了一個新的 NestJS 項目,并將其與 Prisma、PostgreSQL 數據庫以及 Swagger 進行了集成。在此基礎上,您為博客應用程序的后端構建了一個基礎的 REST API。

接下來的這一部分教程,將引導您學習如何驗證輸入數據,以確保其符合 API 規范。執行輸入驗證是至關重要的,因為它能夠確保只有格式正確的數據才能通過 API 傳遞給后端。最佳實踐是,對發送到 Web 應用程序的任何數據都進行正確性驗證。這樣做有助于防止因數據格式錯誤而導致的潛在問題,并防止濫用您的 API。

此外,您還將學習如何執行輸入轉換。輸入轉換是一種在數據到達路由處理程序之前,對其進行攔截和轉換的技術。這對于將數據轉換為適當的類型、為缺失的字段應用默認值、清理輸入數據等場景非常有用。

開發環境

要學習本教程,您需要具備以下條件:

  • 已安裝 Node.js。
  • 已安裝 Docker 或 PostgreSQL 數據庫。
  • (可選)已安裝 Prisma VSCode 擴展,以提升開發體驗。
  • (可選)能夠訪問 Unix shell(例如在 Linux 和 macOS 中的 terminal/shell),以便運行本系列教程中提供的命令。

注意

  1. Prisma 提供了一個可選的 VS Code 擴展,該擴展為 Prisma 腳本添加了 IntelliSense 和語法高亮功能,從而提升了編碼體驗。
  2. 若您的計算機未配備 Unix shell(例如,您正在使用 Windows 系統),您仍然可以繼續學習本教程,但可能需要根據您的系統環境對 shell 命令進行相應的調整。

克隆存儲庫

本教程的起點建立在系列教程第一部分的結束之處。它提供了一個基于 NestJS 構建的簡單 REST API 作為基礎。為了確保您能順利跟上本教程的節奏,我們建議您先完成第一個教程。

本教程的起始代碼位于 GitHub 存儲庫的 begin-validation 分支中。要開始本教程的學習,請首先克隆該存儲庫,并切換到 begin-validation 分支。

git clone -b begin-validation git@github.com:prisma/blog-backend-rest-api-nestjs-prisma.git

現在,執行以下操作以開始使用:

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

注意:步驟 4 還將生成 Prisma Client 并設定數據庫種子。

現在,您應該能夠在以下位置訪問 API 文檔:http://localhost:3000/api/.

項目結構和文件

您克隆的存儲庫應具有以下結構:

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 目錄:該目錄容納了應用程序的源代碼。具體而言,它包含了以下三個關鍵模塊:
    • app 模塊:位于目錄的根位置,是應用程序的啟動點,負責初始化并啟動 Web 服務器。
    • prisma 模塊:此模塊集成了 Prisma Client,它是您的數據庫查詢生成工具。
    • articles 模塊:定義了路由的端點以及相關的業務邏輯。
  • prisma 目錄:雖然名稱與上述模塊相同,但此目錄專門用于存放與 Prisma 相關的文件。其中包括:
    • schema.prisma 文件:該文件詳細描述了數據庫架構。
    • migrations 目錄:用于記錄數據庫的遷移歷史。
  • seed.ts 文件:此文件包含一個腳本,旨在使用模擬數據為開發數據庫進行初始化設定。
  • docker-compose.yml 文件:該文件定義了 PostgreSQL 數據庫的 Docker 映像配置。
  • .env 文件:包含了 PostgreSQL 數據庫的連接字符串信息。

注意:有關這些組件的更多信息,請閱讀本教程系列的第一部分。

執行輸入驗證

為了執行輸入驗證,您將借助 NestJS 中的管道功能。管道針對路由處理程序正在處理的參數進行操作。在路由處理程序之前,Nest 會調用管道,而管道則接收發往路由處理程序的參數。管道的功能多樣,不僅可以驗證輸入,還可以向輸入添加字段等。盡管 NestJS 提供了一些內置的管道,但您同樣可以創建自定義管道以滿足特定需求。

管道有兩個典型的用例:

  • 驗證:評估輸入數據的有效性。如果數據有效,則直接將其傳遞給路由處理程序;如果數據無效,則拋出異常。
  • Transformation(轉換):將輸入數據轉換為所需的形式(例如,從字符串轉換為整數)。

NestJS 的驗證管道會檢查傳遞給路由的參數。若參數有效,管道會將其原封不動地傳遞給路由處理程序;若參數違反任何指定的驗證規則,管道則會拋出異常。

以下示意圖展示了驗證管道在任意路由(如 /example)中的工作原理。

在本節中,您將重點介紹驗證使用案例。

全局設置 ValidationPipe

為了執行輸入驗證,您將利用 NestJS 內置的?ValidationPipeValidationPipe?提供了一種高效的方式,可以對所有傳入的客戶端請求有效負載自動執行驗證規則。這些驗證規則是通過?class-validator?包中的裝飾器來聲明的。

要使用此功能,您需要向項目添加兩個包:

npm install class-validator class-transformer

class-validator 包提供了用于驗證輸入數據的裝飾器,而 class-transformer 包則提供了用于將輸入數據轉換為所需形式的裝飾器。這兩個包都與 NestJS 的管道功能實現了良好的集成。

現在,您需要在 main.ts 文件中導入這些包,并通過 app.useGlobalPipes 方法使 ValidationPipe 在您的應用程序中全局可用。

// src/main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ValidationPipe } from '@nestjs/common';

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

app.useGlobalPipes(new ValidationPipe());

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);

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

將驗證規則添加到CreateArticDto

現在,您需要使用?class-validator?包中的驗證修飾器來增強?CreateArticleDto。以下是您需要應用的驗證規則:

  • title 不能為空,且長度不能少于 5 個字符。
  • description 的最大長度必須為 300 個字符。
  • body 不能為空(注意:原文中提到的“description”應為筆誤,根據上下文應為“body”)。
  • titledescription 和 body 的類型分別為 string
  • 添加一個名為 published 的屬性,其類型為 boolean

接下來,請打開 src/articles/dto/create-article.dto.ts 文件,并將其內容替換為符合上述規則的代碼。

// src/articles/dto/create-article.dto.ts

import { ApiProperty } from '@nestjs/swagger';
import {
IsBoolean,
IsNotEmpty,
IsOptional,
IsString,
MaxLength,
MinLength,
} from 'class-validator';

export class CreateArticleDto {
@IsString()
@IsNotEmpty()
@MinLength(5)
@ApiProperty()
title: string;

@IsString()
@IsOptional()
@IsNotEmpty()
@MaxLength(300)
@ApiProperty({ required: false })
description?: string;

@IsString()
@IsNotEmpty()
@ApiProperty()
body: string;

@IsBoolean()
@IsOptional()
@ApiProperty({ required: false, default: false })
published?: boolean = false;
}

這些驗證規則將被自動選取并應用于您的路由處理程序。使用裝飾器進行驗證的一個顯著優點是,this?關鍵字仍然是端點所有參數的單一事實來源,因此您無需定義單獨的驗證類。例如,對于?CreateArticleDto?在?POST /articles?路由中的應用,驗證規則會自動生效。

為了測試您設置的驗證規則,您可以嘗試通過端點創建一個文章,但故意使用非常短的占位符作為標題,如下所示:POST /articles 請求體中僅包含 title 字段且其值很短。

{
"title": "Temp",
"description": "Learn about input validation",
"body": "Input validation is...",
"published": false
}

您應該會收到 HTTP 400 錯誤響應,并在響應正文中收到有關違反了驗證規則的詳細信息。

帶有描述性錯誤消息的 HTTP 400 響應

下圖展示了 ValidationPipe 在后臺針對 /articles 路由的無效輸入所執行的操作。

使用 ValidationPipe 的輸入驗證流程

從客戶端請求中去除不必要的屬性

這確保 API 安全和穩定的重要步驟。這定義了創建新文章時需要發送到端點的必要屬性。對于創建文章的端點(POST /articles),我們使用 CreateArticleDTO 來明確這些屬性。同樣地,對于更新文章的端點(PATCH /articles/{id}),我們使用 UpdateArticleDTO 來指定哪些屬性可以更新。

然而,目前這兩個端點存在一個潛在問題:客戶端可以發送 DTO 中未定義的額外屬性。這可能會引發不可預見的錯誤或構成安全風險。例如,攻擊者可能會嘗試傳遞無效的值或惡意字段給終端節點。由于 TypeScript 的類型信息在運行時是不可用的,您的應用程序無法自動識別并拒絕這些不在 DTO 中定義的字段。

舉個例子,嘗試向POST /articles終端節點發送以下請求:

{
"title": "example-title",
"description": "example-description",
"body": "example-body",
"published": true,
"createdAt": "2010-06-08T18:20:29.309Z",
"updatedAt": "2021-06-02T18:20:29.310Z"
}

這樣,您可能會不小心注入無效值。例如,您可能會創建一篇文章,其中包含了像 precedesupdatedAt 或 createdAt 這樣沒有實際意義或不應該由客戶端指定的字段/屬性。

為了防止這種情況發生,您需要從客戶端請求中過濾掉任何不必要的字段/屬性。幸運的是,NestJS 提供了一個現成的解決方案。您只需在初始化應用程序時,為?ValidationPipe?傳遞一個選項,將?whitelist?設置為?true?即可。

// src/main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ValidationPipe } from '@nestjs/common';

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

app.useGlobalPipes(new ValidationPipe({ whitelist: true }));

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);

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

將此選項設置為 true 后,ValidationPipe 會自動移除所有未列入白名單的屬性。這里的“non-whitelisted”指的是那些沒有添加驗證裝飾器的屬性。請注意,此選項會過濾掉所有沒有驗證裝飾器的屬性,即使它們在 DTO(數據傳輸對象)中已被定義。

現在,當客戶端請求包含任何未經驗證的字段/屬性時,NestJS 會自動剝離這些字段,從而避免之前提到的安全漏洞。

注意:NestJS 提供了高度的可配置性。所有可用的配置選項都詳細記錄在 NestJS 官方文檔中。如果標準配置無法滿足您的需求,您還可以為應用程序構建自定義的驗證管道。

轉換動態 URL 路徑中的參數:ParseIntPipe

在您的 API 中,GET /articles/{id}PATCH /articles/{id}?和?DELETE /articles/{id}?這三個端點目前都接受一個?id?參數作為 URL 路徑的一部分。NestJS 默認會將路徑中的參數解析為字符串。然而,在將這些參數傳遞給?ArticlesService?之前,您需要在應用程序代碼中將這些字符串強制轉換為數字。為了簡化這一過程,您可以使用?ParseIntPipe。這個管道會自動將路徑參數從字符串轉換為整數,從而確保類型安全并減少出錯的可能性。

// src/articles/articles.controller.ts

@Delete(':id')
@ApiOkResponse({ type: ArticleEntity })
remove(@Param('id') id: string) { // id is parsed as a string
return this.articlesService.remove(+id); // id is converted to number using the expression '+id'
}

由于 id 被定義為字符串類型,Swagger API 在生成的 API 文檔中也會將此參數標記為字符串類型。然而,這種表示可能不夠直觀,甚至在某些情況下是不正確的,特別是當 id 實際上應該表示一個數字或特定格式的標識符時。

您可以在 NestJS 中使用管道來自動將 id 轉換為數字,而無需在路由處理程序中手動執行此轉換。為此,您可以將 ParseIntPipe(一個內置管道)添加到以下三個端點的控制器路由處理程序中,以便對 id 參數進行自動轉換。

// src/articles/articles.controller.ts

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

export class ArticlesController {
// ...

@Get(':id')
@ApiOkResponse({ type: ArticleEntity })
findOne(@Param('id', ParseIntPipe) id: number) {
return this.articlesService.findOne(id);
}

@Patch(':id')
@ApiCreatedResponse({ type: ArticleEntity })
update(
@Param('id', ParseIntPipe) id: number,
@Body() updateArticleDto: UpdateArticleDto,
) {
return this.articlesService.update(id, updateArticleDto);
}

@Delete(':id')
@ApiOkResponse({ type: ArticleEntity })
remove(@Param('id', ParseIntPipe) id: number) {
return this.articlesService.remove(id);
}
}

ParseIntPipe?會攔截字符串類型的參數,并在將其傳遞給路由處理程序之前,自動將其解析為數字。此外,它還具有在 Swagger 文檔中將參數正確記錄為數字類型的優勢。

總結和結束語

祝賀您!在本教程中,您對一個現有的 REST API 進行了增強,具體完成了以下任務:

  • 使用了 ValidationPipe 來自動去除客戶端請求中不必要的屬性。
  • 集成了 ParseIntPipe,以便將路徑變量從字符串解析并轉換為數字。

您可能已經發現,NestJS 大量使用了裝飾器。這是其設計中的一個核心特點,旨在通過裝飾器來處理各種橫切關注點,從而提高代碼的可讀性和模塊化程度。因此,在控制器和服務方法中,您無需編寫大量的樣板代碼來執行驗證、緩存、日志記錄等操作。

您可以在 GitHub 存儲庫的?end-validation?分支中找到本教程的完整代碼。如果您在代碼實現過程中遇到任何問題,歡迎在存儲庫中提出疑問或提交 Pull Request。當然,您也可以直接在 Twitter 上與我取得聯系。

原文鏈接:https://www.prisma.io/blog/nestjs-prisma-validation-7D056s1kOla1

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