前言#
NestJS の世界に入ると、特に多くのモジュールや概念に直面すると、圧倒されるかもしれません。この記事では、優れた NestJS プロジェクトを深く分析し、一般的に使用される Nest の組み込みモジュールを紹介し、NestJS の高度な機能やベストプラクティスを解き明かして、あなたがこの強力な Node.js フレームワークをよりよく理解し、活用できるようにします。初心者でも経験豊富な開発者でも、この記事はあなたに貴重な洞察と実用的なテクニックを提供し、NestJS をより深く理解できるようにします。
私はGitHub の Awesome NestJS リストから優れたプロジェクトを選び、NestJS のさまざまな機能やモジュールの使用方法を分析します。また、@nestjs/core
などの一般的な Nest の組み込みモジュールについても詳しく説明し、コード例を通じてその適用シーンを示します。
この記事には、フレームワークをより包括的に理解するための重要なバックエンド用語の説明も含まれています。
この記事では、ゼロから NestJS プロジェクトを構築する方法を直接教えることはありません。なぜなら、そのようなチュートリアルや記事はすでにたくさん存在するからです。むしろ、この記事の主な目的は、深い分析と解釈を通じて、実際のアプリケーションでよりスムーズに使えるようにすることです。特定のモジュールや機能の使い方がわからないときに、この記事があなたの参考とインスピレーションの源となるでしょう。
このような視点と方法を通じて、私はあなたが NestJS を「使える」だけでなく「理解して使える」ようにし、より自信を持って効率的にバックエンド開発を行えるように手助けしたいと考えています。
さあ、一緒に NestJS の世界に深く入り込み、その無限の可能性を探求しましょう!
全体構造 & 用語解説#
NestJS のさまざまなモジュールや機能に深く入る前に、一般的な優れたプロジェクトの全体構造と関連用語を理解することが非常に重要です。これは、フレームワークの動作原理をよりよく理解するのに役立ち、開発プロセスでより賢明な決定を下すことができます。
ディレクトリ構造#
prisam // データベース関連
src
├─ auth // 認証ログインモジュール
│ ├─ auth.controller.ts
│ ├─ auth.guard.ts // ガード
│ ├─ auth.interface.ts // このモジュールの型宣言を格納
│ ├─ auth.module.ts
│ ├─ auth.service.ts
│ ├─ dto
│ │ ├─ sign-in.dto.ts
│ ├─ entities
│ │ └─ refresh-token.entity.ts
├─ common // グローバル共通モジュール
| ├─ configs // グローバル設定
| ├─ constants // 一部の定数を定義
| ├─ decorators // グローバルデコレーター
| ├─ filters // グローバルフィルター
| ├─ interceptors // グローバルインターセプター
| ├─ interfaces // グローバル型宣言
| ├─ services // グローバル共通サービス
| ├─ * // その他
├─ utils // ユーティリティ関数、できるだけ純粋な関数を格納
├─ app.*.ts // appモジュール、他のモジュールがappモジュールを参照する必要がある
├─ main.ts // アプリケーションエントリ
ユーザー認証モジュールの例を挙げると、通常はこれらのファイルが見られ、それぞれの用途は以下の通りです:
*.module.ts
: 通常はモジュールファイルで、コントローラー、サービス、ガードなどを整理・管理するために使用されます。これは Nest.js アプリケーションの基本単位です。*.service.ts
: サービス層は通常、モジュールのビジネスロジックを処理するために使用されます。これらは通常、コントローラーに注入され、データベースにアクセスしたり、計算を実行したりします。*.controller.ts
: コントローラーファイルは HTTP リクエストとレスポンスを処理します。これらは通常、ビジネスロジックを実行するためにサービスに依存します。*.guard.ts
: ガードファイルはルーティング保護を実現するために使用されます。例えば、認証や権限付与などです。*.interface.ts
: インターフェースファイルは、局所的に使用される型やデータ構造を定義し、コードの堅牢性を確保します。(ts 宣言など)*.dto.ts
: データ転送オブジェクト(DTO)は、クライアントが送信するデータを検証するために使用されます。*.entity.ts
: エンティティファイルはデータベースモデルを定義するために使用されます。
いくつかの用語の簡単な説明は以下の通りです:
- DTO(Data Transfer Object): データ転送オブジェクトで、オブジェクトと API 間でデータを転送するために使用されます。
- Guard: ガードは、権限管理とアクセス検証を実現するために使用されます。
- Module: モジュールは、NestJS の基本的な組織単位で、コントローラーやサービスなどを整理・管理するために使用されます。
- Service: サービスは、主なビジネスロジックを含み、通常はコントローラーに注入されます。
- Entity: エンティティは、データベースモデルを定義するために使用され、通常は ORM(オブジェクト関係マッピング)と一緒に使用されます。
- Interceptor: NestJS におけるインターセプターは、
@Injectable()
デコレーターで注釈されたクラスで、NestInterceptor
インターフェースを実装します。インターセプターは、関数の実行前または後にいくつかの操作を実行するために使用されます。例えば、ログ記録、例外処理、データ変換などです。 - Reflector: Reflector は、主にメタデータの反射と操作に使用されます。インターセプター内で、Reflector はメソッドやクラスに設定されたカスタムメタデータを取得するために使用され、より柔軟な操作を可能にします。
以上のディレクトリ構造と用語解説を通じて、NestJS の構造と設計理念をより包括的に理解するための明確な視点を提供できればと思います。次に、これらの概念を深く探求し、実際のコード例を通じてそれらが NestJS プロジェクトでどのように適用されるかを示します。
Module#
- ルートモジュール:各 Nest.js アプリケーションにはルートモジュールがあり、これは Nest がアプリケーショングラフ(application graph)を構築するための起点です。このグラフは、モジュールとプロバイダー(Providers)間の関係と依存関係を解決するために使用されます。
- コンポーネントの整理:モジュールは、コンポーネント(コントローラー、サービスなど)を整理・管理するための効果的な方法です。モジュールを使用することで、密接に関連する機能をまとめることができます。
- マルチモジュールアーキテクチャ:大規模なアプリケーションでは、通常、マルチモジュールアーキテクチャが採用されます。各モジュールは、特定の密接に関連する機能のセットをカプセル化しています。
// Nest.jsのコアモジュールをインポート
import { Module } from '@nestjs/common';
// 他の関連コンポーネントをインポート
import { AppController } from './app.controller';
import { AppService } from './app.service';
// @Moduleデコレーターを使用してモジュールを定義
@Module({
// 他のモジュールをインポート
imports: [],
// このモジュールのコントローラーを宣言
controllers: [AppController],
// このモジュールのプロバイダー(通常はサービス)を宣言
providers: [AppService],
})
export class AppModule {}
おすすめの読書#
サービス層(Service Layer)#
ソフトウェアアーキテクチャでは、通常、コードと機能を整理するためにいくつかの異なる層があります。これらの層は、関心の分離(Separation of Concerns)を実現し、コードの保守性と拡張性を向上させます。この例では、主に以下の層に焦点を当てます:サービス層とコントローラー層、DAO 層については:
nest や egg に関しては、公式のデモでは DAO 層について明確に言及されておらず、直接サービス層でデータベースを操作しています。これは単純なビジネスロジックには問題ありませんが、ビジネスロジックが複雑になると、サービス層の保守が非常に困難になります。ビジネスは最初は一般的に非常にシンプルですが、必ず複雑な方向に進化します。長期的に考えると、最初から DAO を保持すべきです。
サービス層は主にビジネスロジックの実装を担当します。この層は通常、データベースと対話し、CRUD(作成、読み取り、更新、削除)操作を実行し、ビジネスロジックに関連する他のタスクを実行します。
例えば、UserService
という名前のサービスには、registerUser
メソッドがあり、このメソッドはLoginUserDto
オブジェクトを受け取り、データを検証し、新しいユーザーをデータベースに追加します。
import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { LoginUserDto } from './dto/LoginUserDto';
@Injectable()
export class AuthService {
private prisma: PrismaClient;
constructor() {
this.prisma = new PrismaClient();
}
async registerUser(dto: LoginUserDto): Promise<void> {
await this.prisma.user.create({
data: {
userName: dto.userName,
password: dto.password,
},
});
}
}
おすすめの読書#
コントローラー層(Controller Layer)#
コントローラー層は主にクライアントからのリクエストを処理し、レスポンスを送信する役割を担います。コントローラーはサービス層が提供するメソッドを使用してビジネスロジックを実行し、その結果をクライアントに返します。
例えば、UserController
という名前のコントローラーには、クライアントから送信された HTTP POST リクエストとLoginUserDto
データを受け取るregister
メソッドがあります。
import { Controller, Post, Body } from '@nestjs/common';
import { UserService } from './user.service';
import { LoginUserDto } from './dto/LoginUserDto';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post('register')
async register(@Body() userDto: LoginUserDto) {
return await this.userService.registerUser(userDto);
}
}
おすすめの読書#
DTO(Data Transfer Object)#
PO と DTO を使用してエンティティとその周辺を説明します。PO は永続化オブジェクトで、データベースのテーブル構造と一対一で対応します。DTO データ転送オブジェクトは非常に柔軟で、豊富なシーンで入力パラメータや戻り値を説明できます。以下はユーザーエンティティの例です:
サービス層とコントローラー層との関係#
- コントローラー層では、DTO はクライアントからのリクエストデータを検証するために使用されます。クライアントがリクエストを送信すると、Nest.js は DTO を使用してリクエストボディ内のデータが期待される形式と型に合致しているかを検証します。
- サービス層では、DTO はビジネスロジックを実行するために使用されます。
このように、DTO はコントローラー層とサービス層の間の橋渡しを行い、これらの二つの層間でデータが流れ、変換されることを可能にし、同時に型安全性とデータ検証を保証します。
この例では、LoginUserDto
は DTO であり、ユーザー登録時に提出する必要があるデータ形式を定義しています。この DTO はコントローラー層でクライアントのデータを受け取るために使用され、サービス層でビジネスロジックを実行するために使用されます。
// module/dto/LoginUserDto.ts
import { IsString, IsNotEmpty } from 'class-validator';
export class LoginUserDto {
@IsString()
@IsNotEmpty()
userName: string;
@IsString()
@IsNotEmpty()
password: string;
}
上記のコードは、ユーザー登録時に提出する必要があるデータ形式を定義しています。データ検証にはclass-validatorライブラリを使用しています。
-
属性の説明
userName
: ユーザー名で、文字列型である必要があります。password
: パスワードで、文字列型である必要があります。
-
デコレーターの説明
@IsString()
: フィールドが文字列型であることを保証します。@IsOptional()
: フィールドがオプションであることを示します。
詳細な使用説明はhttps://github.com/typestack/class-validator#usage を参照してください。
おすすめの読書#
エンティティ(Entity)#
NestJS や他の TypeScript フレームワークにおいて、.entity.ts
ファイルはデータベースモデルを定義するために使用されます。これらのモデルは通常、データベースのテーブルと一対一で対応し、テーブルの構造と関係を記述するために使用されます。エンティティクラスは通常、フィールドとその型をマークするためにデコレーター(decorators)を使用します。これにより、ORM ツールがデータベースと正しく対話できるようになります。
例えば、UserEntity
という名前のエンティティは次のようになります:
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity('users')
export class UserEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 500 })
name: string;
@Column('text')
description: string;
}
この例では、UserEntity
クラスはデータベースのusers
テーブルに対応しています。id
、name
、description
の 3 つのフィールドがあり、これらのフィールドの型と長さもデコレーターを通じてマークされています。
Prisma ORM を使用する場合、エンティティファイルは通常、単純な型定義になります。
export class GameInfo {
id: number;
name: string | null;
description: string | null;
}
これは、Prisma の定義が schema.prisma にあるためです。
サンプルコード#
以下は、ユーザーのウォレットアドレスと JWT アクセストークンを保存するためのエンティティクラスRefreshTokenEntity
の例です。
import { Entity, Column, PrimaryColumn } from 'typeorm';
import { IsString } from 'class-validator';
import { Transform } from 'class-transformer';
@Entity('refresh_tokens')
export class RefreshTokenEntity {
/**
* ユーザーのウォレットアドレス
*/
@PrimaryColumn()
@IsString()
@Transform(({ value }) => getAddress(value))
public address: string;
/**
* Jwtトークン
*/
@Column('text')
public accessToken: string;
}
この例では、RefreshTokenEntity
クラスはデータベースのrefresh_tokens
テーブルに対応しています。address
とaccessToken
の 2 つのフィールドがあります。address
フィールドは、class-validator
とclass-transformer
ライブラリのデコレーターを使用して追加の検証と変換が行われています。
これにより、サービス層や DAO 層でこのエンティティクラスを使用してデータベース操作を行うことができます。
おすすめの読書#
ガード(Guard)#
NestJS や他のいくつかのバックエンドフレームワークにおいて、ガード(Guard)は特別なタイプのサービスで、ルーティング保護を実現するために使用されます。これらは通常、認証や権限付与に使用され、特定のルートにアクセスするための適切な権限を持つユーザーのみがアクセスできるようにします。
例えば、以下は JWT(JSON Web トークン)を使用して認証を行うシンプルなガードAuthGuard
の例です。
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Reflector } from '@nestjs/core';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private jwtService: JwtService,
private configService: ConfigService,
private reflector: Reflector
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = request.headers['authorization']?.split(' ')[1];
if (!token) {
throw new UnauthorizedException('トークンがありません');
}
try {
const decoded = this.jwtService.verify(token);
request.user = decoded;
return true;
} catch (error) {
throw new UnauthorizedException('無効なトークン');
}
}
}
この例では、AuthGuard
はCanActivate
インターフェースを実装し、canActivate
メソッドを定義しています。このメソッドは、リクエストヘッダーに有効な JWT が含まれているかどうかを確認します。含まれている場合、そのリクエストは続行されます。そうでない場合、UnauthorizedException
がスローされます。
おすすめの読書#
サービス層とガード層を使用することで、コードをより効果的に整理し、モジュール化と保守性を向上させることができます。同時に、より強力で柔軟なビジネスロジックとセキュリティ制御を実現するのにも役立ちます。
インターセプター(Interceptor)#
NestJS におけるインターセプター(Interceptor)は、@Injectable()
デコレーターで注釈されたクラスで、NestInterceptor
インターフェースを実装します。インターセプターは通常、関数の実行前または後にいくつかの操作を実行するために使用されます。インターセプターは、ログ記録、例外処理、データ変換など、さまざまな用途に使用できます。
シンプルなLoggingInterceptor
の例:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log('Before...');
const now = Date.now();
return next
.handle()
.pipe(
tap(() => console.log(`After... ${Date.now() - now}ms`)),
);
}
}
handle()
は RxJS のObservable
を返すため、さまざまな演算子を使用してストリームを操作できます。上記の例では、tap()
演算子を使用して、Observable が正常または異常に終了したときに匿名のログ記録関数を呼び出しますが、レスポンスサイクルには他の方法で干渉しません。
レスポンスデータ変換インターセプター#
以下は、レスポンスデータを変換するシンプルなインターセプターの例で、必要に応じて元のデータまたはラップされたデータを返すことができます。
レスポンスインターフェースとメタデータキーの定義#
まず、レスポンスインターフェースIResponse
とメタデータキーIS_RAW_DATA_KEY
を定義します。
import { SetMetadata } from '@nestjs/common';
export interface IResponse<T> {
code: number;
message: string;
data: T;
}
export const IS_RAW_DATA_KEY = 'is-raw-data';
/**
* レスポンスデータがResponseでラップされるかどうかを制御
* @constructor
*/
export const RawData = () => SetMetadata(IS_RAW_DATA_KEY, true);
IResponse<T>
: レスポンスデータをラップするためのインターフェース。IS_RAW_DATA_KEY
: 元のデータを返すかどうかをマークするためのメタデータキー。RawData()
: メタデータキーを設定するためのデコレーター。
メタデータが理解できない場合でも心配しないでください。次に進みましょう。
インターセプターの実装#
次に、レスポンスデータを変換するインターセプターを実装します。
// transform.interceptor.ts
import { IResponse, IS_RAW_DATA_KEY } from '@/common';
import { map, Observable } from 'rxjs';
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
/**
* レスポンスデータ変換を処理
*/
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, IResponse<T> | T> {
constructor(private reflector: Reflector) {}
intercept(context: ExecutionContext, next: CallHandler<T>): Observable<IResponse<T> | T> {
const isRawData = this.reflector.getAllAndOverride<boolean>(IS_RAW_DATA_KEY, [context.getHandler(), context.getClass()]);
return next.handle().pipe(map((data) => (isRawData ? data : { code: 200, message: 'success', data })));
}
}
TransformInterceptor
: インターセプターの主体。isRawData
: 元のデータを返す必要があるかどうかを確認します。next.handle().pipe(...)
:isRawData
の値に基づいて、元のデータを返すかラップされたデータを返すかを決定します。
AppModule でインターセプターを参照#
最後に、AppModule にインターセプターを追加します。
import { TransformInterceptor } from '@/common';
import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
// その他...
],
controllers: [AppController],
providers: [
// その他...
{
provide: APP_INTERCEPTOR,
useClass: TransformInterceptor,
},
AppService,
],
})
export class AppModule {}
RawData デコレーターの使用#
これで、コントローラー内で@RawData()
デコレーターを使用して、元のレスポンスデータを返すかどうかを制御できます。
@Controller('someResource')
export class SomeController {
constructor(private someService: SomeService) {}
@RawData()
@Get(':someParam')
someMethod(@Param('someParam') someParam: number): Promise<SomeEntity> {
// 実装の詳細
}
}
このようにして、レスポンスデータの形式を柔軟に制御できます。
Nest.js は本当に素晴らしいですね。
おすすめの読書#
これにより、NestJS におけるインターセプター層の役割と実装方法をよりよく理解できるようになります。これが NestJS のアーキテクチャとベストプラクティスをより深く理解する手助けになることを願っています。
リフレクター(Reflector)#
NestJS において、Reflector
はメタデータを取得するためのユーティリティクラスです。これは通常、カスタムデコレーターやインターセプター内で使用され、クラス、メソッド、またはプロパティに関する追加情報を取得します。これらの情報は、デコレーターによってコンパイル時に追加されたものです。
上記のインターセプターの例では、Reflector
は現在の実行コンテキスト(ExecutionContext
)に関連するメタデータを取得するために使用されます。ここでは、元のデータを返すべきか、データをレスポンスオブジェクトにラップすべきかを決定するために使用されます。
const isRawData = this.reflector.getAllAndOverride<boolean>(IS_RAW_DATA_KEY, [context.getHandler(), context.getClass()]);
この行のコードは、現在のハンドラーまたはクラスからIS_RAW_DATA_KEY
のメタデータを取得するためにgetAllAndOverride
メソッドを使用しています。その後、このメタデータはレスポンスデータの変換方法を決定するために使用されます。
使用シーン#
- カスタムデコレーター:カスタムデコレーターがある場合、
Reflector
を使用してそのデコレーターに関連するメタデータを読み取る必要があるかもしれません。 - 権限管理:インターセプターやガード内で、
Reflector
を使用してユーザーの役割や権限に関するメタデータを取得し、より細かい制御を実現できます。 - レスポンス変換:上記の例のように、
Reflector
を使用してレスポンスデータのフォーマットや変換方法を決定できます。
サンプルコード#
import { Reflector } from '@nestjs/core';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get<string[]>('roles', context.getHandler());
// ... 権限チェックロジック
}
}
おすすめの読書#
このように、Reflector
は NestJS において高度に構成可能で動的な動作を実現するための重要なツールとなります。
一般的な Nest の組み込みモジュール#
これは、さまざまな Nest プロジェクトの package.json からまとめたモジュールの概要です:
@nestjs/core#
- NPM: @nestjs/core
- ドキュメント: NestJS Core Module
- 概要: これは NestJS フレームワークのコアモジュールで、フレームワークの基本構成要素とコア機能を提供します。
- 使用シーン: NestJS アプリを構築・初期化するために使用され、ほぼすべての NestJS プロジェクトで使用されます。
- コード例:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
### @nestjs/jwt
- NPM: [@nestjs/jwt](https://www.npmjs.com/package/@nestjs/jwt)
- ドキュメント: [NestJS JWT Module](https://docs.nestjs.com/security/authentication#jwt-module)
- **概要**: このモジュールはJWT(JSON Webトークン)のサポートを提供し、NestJSアプリで**認証と権限付与**を実現します。
- **使用シーン**: 認証と権限付与、通常はルートやリソースを保護するために使用されます。
- **コード例**:
```ts
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(private readonly jwtService: JwtService) {}
async generateToken(user: User) {
return this.jwtService.sign({ user });
}
}
@nestjs/config#
- NPM: @nestjs/config
- ドキュメント: NestJS Config Module
- 概要: このモジュールは、NestJS アプリの設定情報を管理するために使用されます。環境変数、型変換などをサポートします。
- 使用シーン: アプリの設定情報を管理するために使用されます。例えば、データベース接続文字列や API キーなどです。
- コード例:
import { ConfigService } from '@nestjs/config';
@Injectable()
export class AppService {
constructor(private configService: ConfigService) {}
getDatabaseUrl(): string {
return this.configService.get<string>('DATABASE_URL');
}
}
@nestjs/common#
- NPM: @nestjs/common
- ドキュメント: NestJS Common Module
- 概要: これは NestJS の一般的なモジュールで、一般的に使用されるデコレーター、ヘルパー関数、その他のツールを提供します。例えば、
Injectable
,Module
,BadRequestException
,Body
,Controller
,Get
,Param
,Post
,Query
など。 - 使用シーン: コントローラー層、サービス層、モジュール内で使用され、ルーティングや依存性注入を定義するために使用されます。
- コード例:
import { Controller, Get } from '@nestjs/common';
@Controller('hello')
export class HelloController {
@Get()
sayHello(): string {
return 'こんにちは、世界!';
}
}
@nestjs/axios#
- NPM: @nestjs/axios
- ドキュメント: NestJS Axios Module
- 概要: このモジュールは NestJS に Axios HTTP クライアントのラッパーを提供し、NestJS アプリで HTTP リクエストをより簡単に行えるようにします。例えば、
HttpService
,HttpModule
など。 - 使用シーン: サービス層で HTTP リクエストを行うために使用されます。例えば、サードパーティ API を呼び出す場合など。
- コード例:
import { HttpService } from '@nestjs/axios';
@Injectable()
export class ApiService {
constructor(private httpService: HttpService) {}
async fetchData(url: string) {
const response = await this.httpService.get(url).toPromise();
return response.data;
}
}
実際のプロジェクトでは、HTTP サービスリクエストを再実装して、統一されたログなどを追加することが一般的です。以下のようになります:
import { HttpService } from '@nestjs/axios';
import { catchError, Observable, tap } from 'rxjs';
import { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import { BadRequestException, Injectable, Logger } from '@nestjs/common';
@Injectable()
export class HttpClientService {
constructor(private httpService: HttpService) {}
private logger: Logger = new Logger(HttpClientService.name);
/**
* HTTPサービスのGETリクエストを再実装し、リクエストとレスポンスをログに記録します。
* @param url
* @param config
*/
get<T = any>(url: string, config?: AxiosRequestConfig): Observable<AxiosResponse<T, any>> {
// リクエスト情報をログに記録
this.logger.log(`GET ${url}`);
return this.httpService.get<T>(url, config).pipe(
// Observableの流れを変更せずに受信したレスポンスをログに記録
tap((response) => this.logger.log(`Response ${url} ${JSON.stringify(response.data)}`)),
// エラーをキャッチし、エラーメッセージをログに記録
catchError((error: AxiosError) => {
const errorData = JSON.stringify(error.response?.data);
this.logger.error(`GET Error ${url} ${errorData}`);
throw new BadRequestException([errorData]);
}),
);
}
}
@nestjs/bull#
- NPM: @nestjs/bull
- ドキュメント: NestJS Bull Module
- 概要: このモジュールは Bull キューライブラリのラッパーを提供し、NestJS アプリでバックグラウンドジョブとメッセージキューを処理します。
- 使用シーン: バックグラウンドタスク処理、例えばメール送信やデータ処理など。
- コード例:
import { Processor, Process } from '@nestjs/bull';
import { Job } from 'bull';
@Processor('audio')
export class AudioProcessor {
@Process('transcode')
async transcode(job: Job<number>) {
// あなたのロジック
}
}
@nestjs/cache-manager#
- NPM: @nestjs/cache-manager
- ドキュメント: NestJS Caching
- 概要: このモジュールはキャッシュ管理機能を提供し、メモリ、Redis などのさまざまなキャッシュストレージ方式をサポートします。
- 使用シーン: データキャッシュ、例えばAPI レスポンス、データベースクエリ結果、セッションキャッシュなど。
- コード例: この例では、
CacheModule
を使用してキャッシュを登録し、CacheInterceptor
インターセプターを使用してキャッシュロジックを自動的に処理します。これにより、findAll
メソッドに何度もアクセスすると、結果がキャッシュされ、応答速度が向上します。
import { CacheModule, CacheInterceptor, Controller, UseInterceptors } from '@nestjs/common';
import { CachingConfigService } from './caching-config.service';
@Module({
imports: [
CacheModule.registerAsync({
useClass: CachingConfigService,
}),
],
})
export class AppModule {}
@Controller('posts')
export class PostsController {
@UseInterceptors(CacheInterceptor)
@Get()
findAll() {
// あなたのロジック
}
}
@nestjs/mongoose#
- NPM: @nestjs/mongoose
- ドキュメント: NestJS Mongoose Module
- 概要: このモジュールは Mongoose ODM(オブジェクトドキュメントマッピング)のラッパーを提供し、NestJS アプリで MongoDB データベースと対話します。
- 使用シーン: データベース操作、特に MongoDB データベースとの対話。
- コード例:
import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
@Schema()
export class Cat extends Document {
@Prop()
name: string;
}
export const CatSchema = SchemaFactory.createForClass(Cat);
@nestjs/platform-express#
- NPM: @nestjs/platform-express
- ドキュメント: NestJS Overview
- 概要: このモジュールは NestJS フレームワークの Express アダプターで、NestJS アプリで Express.js を使用するために使用されます。
- 使用シーン:
FileInterceptor
を使用してファイルアップロードを処理する際に使用されます。 - コード例: この例では、
@nestjs/platform-express
が提供するFileInterceptor
を使用してファイルアップロードを処理しています。これは実際には Express のmulter
ミドルウェアのラッパーです。
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
@Controller('upload')
export class UploadController {
@Post()
@UseInterceptors(FileInterceptor('file', {
storage: diskStorage({
destination: './uploads',
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${file.originalname}`);
},
}),
}))
uploadFile(@UploadedFile() file) {
return { url: `./uploads/${file.filename}` };
}
}
@nestjs/schedule#
- NPM: @nestjs/schedule
- ドキュメント: NestJS Schedule Module
- 概要: このモジュールはタスクスケジューリング機能を提供し、NestJS アプリで定期的なタスクを実行します。
- 使用シーン: 定期的なタスク、例えば毎日のデータバックアップや定期的なプッシュ通知など。
- コード例:
import { Cron, CronExpression } from '@nestjs/schedule';
@Injectable()
export class TasksService {
@Cron(CronExpression.EVERY_5_SECONDS)
handleCron() {
// あなたのロジック
}
}
@nestjs/swagger#
- NPM: @nestjs/swagger
- ドキュメント: NestJS Swagger Module
- 概要: このモジュールは API ドキュメントを生成・維持するために使用され、Swagger に基づいています。
- 使用シーン: API ドキュメントを自動生成するために使用されます。
- コード例:
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty()
username: string;
@ApiProperty()
password: string;
}
@nestjs/throttler#
- NPM: @nestjs/throttler
- ドキュメント: NestJS Throttler
- 概要: このモジュールはリクエスト制限(Rate Limiting)機能を提供し、API の乱用を防ぎます。
ThrottlerGuard
,SkipThrottle
などがあります。 - 使用シーン: API の乱用を防ぐために、例えば、1 分あたりのリクエスト数を制限するために使用されます。
- コード例:
import { ThrottlerGuard } from '@nestjs/throttler';
@Injectable()
export class AppGuard extends ThrottlerGuard {
// あなたのロジック
}
その他のパッケージ#
class-validator#
- NPM: class-validator
- ドキュメント: class-validator: Decorator-based property validation for classes.
- 概要: クラス内のプロパティ検証のためのデコレーターに基づくライブラリで、TypeScript および JavaScript クラスでデータ検証を行います。内部で validator.js を使用して検証を行います。
- 使用シーン: データ検証、例えばユーザー入力やリクエストボディなど。
- コード例:
import { IsEmail, IsNotEmpty } from 'class-validator';
export class CreateUserDto {
@IsNotEmpty()
name: string;
@IsEmail()
email: string;
}
class-transformer#
- NPM: class-transformer
- ドキュメント: class-transformer GitHub
- 概要: オブジェクトとクラスインスタンス間の変換を行うためのライブラリで、通常は
class-validator
と組み合わせて使用されます。 - 使用シーン: オブジェクトの変換やシリアル化。
- コード例:
import { plainToClass } from 'class-transformer';
const user = plainToClass(User, {
name: 'John Doe',
email: '[email protected]'
});
cache-manager#
- NPM: cache-manager
- ドキュメント: cache-manager GitHub
- 概要: 柔軟で拡張可能なキャッシュモジュールで、さまざまなストレージ方式をサポートします。
- 使用シーン: データキャッシュ、例えば API レスポンスやデータベースクエリ結果など。
- コード例:
import * as cacheManager from 'cache-manager';
const memoryCache = cacheManager.caching({ store: 'memory', max: 100, ttl: 10 });
async function getUser(id: string) {
const cachedUser = await memoryCache.get(id);
if (cachedUser) {
return cachedUser;
}
const user = await fetchUserFromDb(id);
await memoryCache.set(id, user);
return user;
}
hashids#
- NPM: hashids
- ドキュメント: Sqids JavaScript (formerly Hashids)
- 概要: 短い一意の非整数 ID を生成するためのライブラリです。
- 使用シーン: 短いリンクや一意の識別子を生成するために使用されます。
- コード例:
import Hashids from 'hashids';
const hashids = new Hashids();
const id = hashids.encode(12345); // 短い一意の文字列を出力
ioredis#
- NPM: ioredis
- ドキュメント: ioredis GitHub
- 概要: 信頼性が高く効率的な Redis クライアントです。
- 使用シーン: Redis データベース操作やキャッシュ管理など。
- コード例:
import Redis from 'ioredis';
const redis = new Redis();
redis.set('key', 'value');
mongoose#
- NPM: mongoose
- ドキュメント: Mongoose Documentation
- 概要: MongoDB と Node.js のためのオブジェクトデータモデル(ODM)ライブラリです。
- 使用シーン: MongoDB データベース操作やデータモデル定義など。
- コード例:
import mongoose from 'mongoose';
const userSchema = new mongoose.Schema({
username: String,
password: String,
});
const User = mongoose.model('User', userSchema);
nestgram#
- NPM: nestgram
- ドキュメント: About Nestgram - Nestgram
- 概要: NestJS 用の Telegram ボットライブラリです。
- 使用シーン: NestJS アプリに Telegram ボットを統合するために使用されます。
- コード例:
import { Nestgram } from 'nestgram';
const nestgram = new Nestgram({ token: 'YOUR_BOT_TOKEN' });
nestgram.on('message', (msg) => {
// メッセージを処理
});
nestjs-throttler-storage-redis#
- NPM: nestjs-throttler-storage-redis
- ドキュメント: GitHub - nestjs-throttler-storage-redis
- 概要: NestJS の Throttler モジュールを Redis と統合するために使用されます。
- 使用シーン: NestJS アプリで Redis ベースのリクエスト制限を実現するために使用されます。
- コード例:
import { ThrottlerModule } from '@nestjs/throttler';
import { RedisThrottlerStorage } from 'nestjs-throttler-storage-redis';
@Module({
imports: [
ThrottlerModule.forRoot({
storage: new RedisThrottlerStorage(),
}),
],
})
export class AppModule {}
ramda#
- NPM: ramda
- ドキュメント: Ramda Documentation
- 概要: 実用的な関数型プログラミングライブラリです。
- 使用シーン: データ変換や関数合成など。
- コード例:
import * as R from 'ramda';
const addOne = R.add(1);
const result = addOne(2); // 3を出力
redis#
- NPM: redis
- ドキュメント: redis GitHub
- 概要: Node.js の Redis クライアントです。
- 使用シーン: Node.js アプリで Redis データベースと対話するために使用されます。
- コード例:
import * as redis from 'redis';
const client = redis.createClient();
client.set('key', 'value');
client.get('key', (err, reply) => {
console.log(reply); // 'value'を出力
});
reflect-metadata#
- NPM: reflect-metadata
- ドキュメント: Metadata Proposal - ECMAScript
- 概要: メタデータ反射 API のライブラリです。
- 使用シーン: TypeScript でデコレーターと反射を使用するために使用されます。
- コード例:
import 'reflect-metadata';
@Reflect.metadata('role', 'admin')
class User {
constructor(public name: string) {}
}
const metadata = Reflect.getMetadata('role', User);
console.log(metadata); // 'admin'を出力
rxjs#
- NPM: rxjs
- ドキュメント: RxJS Documentation
- 概要: 可観測オブジェクトを使用して反応型プログラミングを行うためのライブラリです。
- 使用シーン: 非同期プログラミングやイベント処理など。
- コード例:
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
const source$ = of(1, 2, 3);
const result$ = source$.pipe(map(x => x * 2));
result$.subscribe(x => console.log(x)); // 2, 4, 6を出力