Open10

NestJS

Kazuki MatsudaKazuki Matsuda

Controllers

クエストハンドラがJavaScriptオブジェクトや配列を返すとき、それは自動的にJSONにシリアライズされます。しかし、JavaScript のプリミティブ型 (string,number,boolean など) を返す場合、Nest はシリアライズせずに値だけを送信します。これはレスポンスの処理をシンプルにする。値を返すだけで、あとはNestが処理してくれる。

DTO(Data Transfer Object)スキーマを決定する必要がある。DTOとは、ネットワーク上でデータがどのように送信されるかを定義するオブジェクトである。DTOスキーマを決定するには、TypeScriptのインターフェイスを使うか、単純なクラスを使う方法がある。興味深いことに、ここではクラスを使うことを推奨する。なぜか?クラスはJavaScript ES6標準の一部であるため、コンパイルされたJavaScriptの中で実際のエンティティとして保存される。一方、TypeScriptのインターフェイスはトランスパイル時に削除されるため、Nestは実行時にインターフェイスを参照できない。Pipesのような機能は、実行時に変数のメタタイプにアクセスすることで、さらなる可能性を可能にするため、これは重要である。

export class CreateCatDto {
  name: string;
  age: number;
  breed: string;
}
@Post()
async create(@Body() createCatDto: CreateCatDto) {
  return 'This action adds a new cat';
}
import { Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { CreateCatDto, UpdateCatDto, ListAllEntities } from './dto';

@Controller('cats')
export class CatsController {
  @Post()
  create(@Body() createCatDto: CreateCatDto) {
    return 'This action adds a new cat';
  }

  @Get()
  findAll(@Query() query: ListAllEntities) {
    return `This action returns all cats (limit: ${query.limit} items)`;
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return `This action returns a #${id} cat`;
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
    return `This action updates a #${id} cat`;
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return `This action removes a #${id} cat`;
  }
}
Kazuki MatsudaKazuki Matsuda

Providers

プロバイダはNestの基本的な概念です。サービス、リポジトリ、ファクトリー、ヘルパーなど、Nestの基本的なクラスの多くはプロバイダーとして扱われることがあります。プロバイダの主な考え方は、依存関係として注入できることです。これは、オブジェクトが互いにさまざまな関係を作成できることを意味し、これらのオブジェクトを「配線」する機能は、ネストのランタイムシステムにほぼ委譲することができます。

プロバイダは通常、アプリケーションのライフサイクルと同期したライフタイム("スコープ")を持つ。アプリケーションがブートストラップされると、すべての依存関係が解決されなければならず、したがって、すべてのプロバイダーがインスタンス化されなければなりません。同様に、アプリケーションがシャットダウンすると、各プロバイダは破棄されます。しかし、プロバイダーのライフタイムをリクエスト・スコープにする方法もあります。

import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';

@Controller('cats')
export class CatsController {
  constructor(private catsService: CatsService) {}

  @Post()
  async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
  }

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }
}
Kazuki MatsudaKazuki Matsuda

Modules

モジュールはデフォルトでプロバイダーをカプセル化する。これは、現在のモジュールの直接の一部でも、インポートされたモジュールからエクスポートされたものでもないプロバイダーを注入することは不可能であることを意味します。したがって、あるモジュールからエクスポートされたプロバイダを、そのモジュールのパブリックインターフェース、つまりAPIとみなすことができます。

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}
Kazuki MatsudaKazuki Matsuda

Middleware

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log('Request...');
    next();
  }
}
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('cats');
  }
}

関数でも書ける

import { Request, Response, NextFunction } from 'express';

export function logger(req: Request, res: Response, next: NextFunction) {
  console.log(`Request...`);
  next();
};
const app = await NestFactory.create(AppModule);
app.use(logger);
await app.listen(3000);
Kazuki MatsudaKazuki Matsuda

Exception filters

Nestには例外処理レイヤーが組み込まれており、アプリケーション全体で処理されない例外をすべて処理します。例外がアプリケーションコードによって処理されない場合、このレイヤーによってキャッチされ、適切なユーザーフレンドリーなレスポンスが自動的に送信されます。

@Get()
async findAll() {
  throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response
      .status(status)
      .json({
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
      });
  }
}
Kazuki MatsudaKazuki Matsuda

Microservices

従来の(モノリシックと呼ばれることもある)アプリケーションアーキテクチャに加えて、Nestはマイクロサービスアーキテクチャの開発スタイルをネイティブにサポートしています。依存性注入、デコレーター、例外フィルター、パイプ、ガード、インターセプターなど、このドキュメントの他の場所で説明されているコンセプトのほとんどは、マイクロサービスにも同様に適用されます。可能な限り、NestはHTTPベースのプラットフォーム、WebSocket、マイクロサービス間で同じコンポーネントを実行できるように、実装の詳細を抽象化しています。このセクションでは、マイクロサービスに特化したNestの側面をカバーします。

ネストでは、マイクロサービスは基本的にHTTPとは異なるトランスポートレイヤーを使用するアプリケーションである。