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 で重複レコードをクエリして削除する方法の完全なガイド

推薦する

Ubuntu 16.04 で FTP サーバーを構築するチュートリアル

Ubuntu 16.04 FTP サーバーをビルドするftpをインストールするftp をインストール...

Vue3 コンポジション API でロジックの再利用を実装する方法

Composition API はロジック再利用手順を実装します。ロジックコードを関数に抽出します。...

VMware Workstation に Windows Server 2019 をインストールする (グラフィック チュートリアル)

キーの入力を求められた場合は、[キーがありません]を選択します。デスクトップエクスペリエンスを選択す...

JavaScriptの知識ポイントの詳しい説明

目次1. JavaScriptの基礎2. 基本的なJavaScript構文3. JavaScript...

Linux システムでログを手動でスクロールする方法

ログローテーションは、Linux システムでは非常に一般的な機能です。ログローテーションは、システム...

Vue.jsはタイムライン機能を実装します

この記事では、タイムライン機能を実装するためのVue.jsの具体的なコードを参考までに共有します。具...

単一テーブルのMySQLバックアップとリストアに関する簡単な説明

A. MySQLバックアップツールxtrabackupのインストール1. Percona 公式 xt...

MySQLクエリステートメントの簡単な操作例

この記事では、例を使用して、MySQL クエリ ステートメントの簡単な操作を説明します。ご参考までに...

Centos7でのパーティションのフォーマットとマウントの実装

Linux では、ハードディスクの追加やパーティションの再マウントといった状況に頻繁に遭遇します。こ...

Linux リモートログイン実装チュートリアル分析

Linux は一般的にサーバーとして使用され、サーバーは一般的にコンピュータルーム内に置かれます。L...

MySQLビューの原理と使用法の詳細な説明

この記事では、例を使用して MySQL ビューの原理と使用方法を説明します。ご参考までに、詳細は以下...

centos7.2 オフラインインストール mysql5.7.18.tar.gz

ネットワークが分離されているため、MySQL は yum を使用してインストールできません。ここでは...

MySQL のデッドロックとデータベースおよびテーブル シャーディングの問題の詳細な説明

MySQL 運用上の問題点を記録します。ビジネスシナリオと問題の説明外部インターフェースをリクエスト...

Linux ディスクデバイスと LVM 管理コマンドの詳細な例

序文Linux オペレーティング システムでは、デバイス ファイルは特別なタイプのファイルです。これ...

テーブルの追加と削除の操作を実装する js

この記事の例では、テーブルを追加および削除するためのjsの具体的なコードを参考までに共有しています。...