Nest.js パラメータ検証とカスタム戻りデータ形式の詳細な説明

Nest.js パラメータ検証とカスタム戻りデータ形式の詳細な説明

0x0 パラメータ検証

Nest.jsでは、パラメータ検証業務のほとんどをパイプライン方式で実装しています。詳細はドキュメントを参照してください。しかし、ドキュメントがかなりわかりにくいため、執筆プロセス中にいくつかの問題に遭遇しました。

いくつかのパラメータを含み、それを dto 構造データにするクエリ インターフェイスを作成します。

'@nestjs/swagger' から { ApiProperty } をインポートします。

エクスポートクラスQueryUserDto {
 @ApiProperty({
 必須: false、
 説明: 'ページ番号'
 })
 読み取り専用現在のページ: 番号

 @ApiProperty({
 必須: false、
 説明: 'アイテム数'
 })
 読み取り専用ページサイズ: 数値

 @ApiProperty({
 必須: false、
 説明: 「ユーザーアカウント」
 })
 読み取り専用のユーザー名?: 文字列

 @ApiProperty({
 必須: false、
 説明: 'ユーザーステータス'
 })
 読み取り専用アクティブステータス: 数値

 @ApiProperty({
 必須: false、
 説明: '並べ替え: ASC、DESC'
 })
 読み取り専用順序: 'DESC' | 'ASC'
}
 タイプスクリプト

@Query リクエストで対応するパラメータが渡されると、取得されるデータ型はすべて String であることがわかります。次に、関連ドキュメントを参照した後、変換にはクラス トランスフォーマーの Type も必要であることがわかります。

'@nestjs/swagger' から { ApiProperty } をインポートします。
'class-transformer' から { Type } をインポートします

エクスポートクラスQueryUserDto {
 @ApiProperty({
 必須: false、
 説明: 'ページ番号'
 })
 @Type(() => 数値)
 読み取り専用現在のページ: 番号 = 1

 @ApiProperty({
 必須: false、
 説明: 'アイテム数'
 })
 @Type(() => 数値)
 読み取り専用ページサイズ: 数値 = 10

 @ApiProperty({
 必須: false、
 説明: 「ユーザーアカウント」
 })
 読み取り専用のユーザー名?: 文字列

 @ApiProperty({
 必須: false、
 説明: 'ユーザーステータス'
 })
 @Type(() => 数値)
 読み取り専用アクティブステータス: 数値 = 3

 @ApiProperty({
 必須: false、
 説明: '並べ替え: ASC、DESC'
 })
 読み取り専用順序: 'DESC' | 'ASC' = 'DESC'
}

次に、ValidationPipe パイプライン メソッドで変換オプションを有効にします。

app.useGlobalPipes(
 新しい検証パイプ({
 変換: 真
 })
)

または、app.modules.ts に挿入します:

'@nestjs/common' から ValidationPipe をインポートします。
'@nestjs/core' から { APP_PIPE } をインポートします。

@モジュール({
 輸入: [
 // ...
 ]、
 コントローラ: [AppController],
 プロバイダー:
 {
  提供: APP_PIPE、
  useValue: 新しいValidationPipe({
  変換: 真
  })
 }
 ]
})

2 つの使用方法の違いは、プログラムが混合アプリケーション タイプであるかどうかです。

手間を省くために、グローバルメソッド内に直接記述します。サービスが最終的に取得するデータはパイプライン業務で処理されたデータであり、サービス層で多くのデータ型判定を行う必要はありません。

0x1 戻りデータ形式をカスタマイズする

コントローラーによって返されるデータは、データベース テーブル構造から取得されます。

{
 "id": "d8d5a56c-ee9f-4e41-be48-5414a7a5712c",
 "ユーザー名": "Akeem.Cremin",
 「パスワード」: 「$2b$10$kRcsmN6ewFC2GOs0TEg6TuvDbNzf1VGCbQf2fI1UeyPAiZCq9rMKm」、
 "メール": "[email protected]",
 「ニックネーム」: 「ウォレス・ニコラス」
 「役割」: 「ユーザー」、
 "isActive": 真、
 "作成日時": "2021-03-24T15:24:26.806Z",
 「更新日時」: 「2021-03-24T15:24:26.806Z」
}

最終戻りインターフェースのデータ形式を定義する必要がある場合、たとえば次のようになります。

{
 「ステータスコード」: 200,
 "メッセージ": "成功を得る",
 "データ": {
  "id": "d8d5a56c-ee9f-4e41-be48-5414a7a5712c",
  "ユーザー名": "Akeem.Cremin",
  「パスワード」: 「$2b$10$kRcsmN6ewFC2GOs0TEg6TuvDbNzf1VGCbQf2fI1UeyPAiZCq9rMKm」、
  "メール": "[email protected]",
  「ニックネーム」: 「ウォレス・ニコラス」
  「役割」: 「ユーザー」、
  "isActive": 真、
  "作成日時": "2021-03-24T15:24:26.806Z",
  「更新日時」: 「2021-03-24T15:24:26.806Z」
 }
}

ここでは、カスタム成功リクエスト インターセプターを作成する必要があります。

shared/interceptor/transform に g をネストする
'@nestjs/common' から { CallHandler、ExecutionContext、Injectable、Logger、NestInterceptor } をインポートします。
'rxjs' から {Observable} をインポートします
'rxjs/operators' から { map } をインポートします。
'express' から {Request} をインポートします

インターフェースResponse<T> {
 データ: T
}

@インジェクタブル()
エクスポートクラス TransformInterceptor<T> は NestInterceptor<T, Response<T>> を実装します {
 インターセプト(コンテキスト: ExecutionContext、次: CallHandler<T>): Observable<any> {
 const リクエスト = context.switchToHttp().getRequest<Request>()
 Logger.log(request.url, '通常のインターフェースリクエスト')

 next.handle().pipe() を返す
  マップ(データ => {
  戻る {
   データ: データ、
   ステータスコード: 200,
   メッセージ: 'リクエストが成功しました'
  }
  })
 )
 }
}

次に、app.module.ts にインポートして使用します。

'@nestjs/common' から ValidationPipe をインポートします。
'@nestjs/core' から { APP_INTERCEPTOR } をインポートします。

'@/shared/interceptor/transform.interceptor' から { TransformInterceptor } をインポートします。

@モジュール({
 輸入: [
 // ...
 ]、
 コントローラ: [AppController],
 プロバイダー:
 {
  提供: APP_INTERCEPTOR、
  使用クラス: TransformInterceptor
 }
 ]
})

ただし、APP_INTERCEPTOR の順序に注意してください。TransformInterceptor を最初に配置するのが最適です。そうしないと失敗します。

エラーフィルター:

ネストGF共有/フィルター/httpException
'@nestjs/common' から { ArgumentsHost、Catch、ExceptionFilter、HttpException、Logger } をインポートします。
'express' から { Response, Request } をインポートします

@Catch(HttpException)
エクスポートクラス HttpExceptionFilter は ExceptionFilter を実装します {
 catch(例外: HttpException、ホスト: ArgumentsHost) {
 定数コンテキスト = host.switchToHttp()
 const レスポンス = context.getResponse<レスポンス>()
 const リクエスト = context.getRequest<リクエスト>()
 定数ステータス = exception.getStatus()
 const メッセージ = 例外.メッセージ

 Logger.log(`${request.url} - ${message}`, '異常なインターフェースリクエスト')

 レスポンス.ステータス(ステータス).json({
  ステータスコード: ステータス、
  メッセージ: メッセージ、
  パス: request.url、
  タイムスタンプ: 新しい Date().toISOString()
 })
 }
}

次に、app.module.ts にインポートして使用します。

'@nestjs/common' から ValidationPipe をインポートします。
'@nestjs/core' から { APP_FILTER } をインポートします。

'@/shared/filters/http-exception.filter' から { HttpExceptionFilter } をインポートします。

@モジュール({
 輸入: [
 // ...
 ]、
 コントローラ: [AppController],
 プロバイダー:
 {
  提供: APP_FILTER、
  使用クラス: HttpExceptionFilter
 }
 ]
})

0x2 エンティティクラスのフィールドを非表示にする

当初は、@Exclude 属性を使用してデータベース内の一部の機密フィールドを非表示にしたいと考えていましたが、特別なニーズを満たすことができないことがわかりました。単一のインスタンスが返される場合は非表示を実現できますが、実装できない findAll があります。上記は、Serialization | NestJS - A progressive Node.js framework ドキュメントで詳しく説明されていますが、別の方法もあります。まず、強度に敏感なデータ フィールドに属性を追加します。

'typeorm' から { BaseEntity、Entity、Column、PrimaryGeneratedColumn } をインポートします。

@Entity('ユーザー')
エクスポートクラス UserEntity は BaseEntity を拡張します {
 @PrimaryGeneratedColumn('uuid', {
  コメント: 'ユーザーID'
 })
 id: 文字列

 @カラム({
  タイプ: 'varchar',
  長さ: 50,
  ユニーク: 真、
  コメント: 'ログインしたユーザー'
 })
 ユーザー名: 文字列

 @カラム({
  タイプ: 'varchar',
  長さ: 200,
  選択: false、
  コメント: 'パスワード'
 })
 パスワード: 文字列

select: false は、クエリ結果を返すときにこのフィールドを非表示にすることができますが、このフィールドを含むすべてのクエリでは、user.service.ts のログイン クエリのように、このフィールドを追加する必要があります。

const ユーザー = getRepository(UserEntity) を待機します
   .createQueryBuilder('ユーザー')
   .where('user.username = :username', { username })
   .addSelect('user.password')
   .getOne()

.addSelect('user.password') この属性クエリを追加するとパスワード フィールドが含まれます。それ以外の場合、通常のクエリ メソッドにはこのフィールドは含まれません。

要約する

Nest.js パラメータ検証とカスタム戻りデータ形式に関するこの記事はこれで終わりです。Nest.js パラメータ検証とデータ形式の詳細については、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

<<:  nginx を https をサポートするように設定するためのサンプル コード

>>:  MySQL で重複レコードをクエリして削除する方法の完全なガイド

推薦する

axios でリクエストをキャンセルし、重複リクエストを防ぐ方法について簡単に説明します。

目次序文コア - キャンセルトークン実用的なアプリケーションとパッケージングいくつかの小さな詳細序文...

ネイティブ JS でスネーク ゲームを書く

この記事では、参考までに、JSでスネークゲームを書くための具体的なコードを紹介します。具体的な内容は...

Centos8 に nginx をインストールするための詳細なチュートリアル (画像とテキスト)

Nginx (「エンジン エックス」と発音) は、インターネット上の最大規模のサイトの負荷を処理す...

シンプルな画像ドラッグ効果を実現する js

この記事では、簡単な画像ドラッグ効果を実現するためのjsの具体的なコードを参考までに紹介します。具体...

Linux での MySQL データベースのアンインストール

Linux で MySQL データベースをアンインストールするにはどうすればいいですか? 以下では、...

MySQL テーブルデータのインポートとエクスポートの例

この記事では、MySQL テーブル データのインポートおよびエクスポート操作について説明します。ご参...

MySQL の char、varchar、text フィールド タイプの違い

MySQL では、char、varchar、text の各タイプのフィールドはすべて文字タイプのデー...

DockerプライベートイメージライブラリとAlibaba CloudオブジェクトストレージOSSの簡単な分析

Docker プライベートイメージライブラリDockerプライベートイメージライブラリとAlibab...

mysql5.7.19 winx64 インストールおよび構成方法のグラフィック チュートリアル (win10)

mysql 5.7.19 winx64のインストールチュートリアルは以下のように記録され、みんなと...

MySQL 5.x 以降を使用している場合のエラー #1929 列 ''createtime'' の日付時刻値が正しくありません: '''' の簡単な解決方法

MySQL をインストールした後、テーブル データを保存および削除しようとすると、常にエラー メッセ...

CentOS8 Linux 8.0.1905 のインストール手順(図解)

現在、CentOS の最新バージョンは CentOS 8 です。次に、CentOS Linux 8....

CentOS 6.5 i386 インストール MySQL 5.7.18 詳細チュートリアル

ほとんどの人はMySQLをコンパイルしてシステムディレクトリに置きますが、私のやり方はコンパイルした...

Vueのprops設定の詳細な説明

<テンプレート> <div class="demo">...

MySQL 5.7.18 のインストールと設定方法のグラフィックチュートリアル (CentOS7)

LinuxにMySQL 5.7.18をインストールする方法1. MySQLをダウンロードします。公...

テーブルを作成するための HTML dl、dt、dd タグとテーブル作成テーブル

ウェブサイトの開発とメンテナンスのコストが削減されるだけでなく、コードもよりセマンティックになります...