たかぎとねこの忘備録

プログラミングに関する忘備録を自分用に残しときます。マサカリ怖い。

冷やし中華の代わりにNestJSはじめました

ずっとNestJSについては認知していたが、クラスを使用したり、デコレーターを使用したりと何かと難しそうな印象だったため今まで触れてこなかった。

しかし、本番環境で利用できるサーバーサイド用のフレームワークとしてはNestJSはある一定の知名度を誇っているがゆえ、このまま触らないでいるのはもったいない。

なので食わず嫌いを直すために、NestJSについて少し学んでみることにする。

docs.nestjs.com

プロジェクトを作る

2パターンあるぽい。Nest CLIから作る方法とTypeScriptのスタータープロジェクトをGitHubからクローンする方法。

今回はNest CLIを使ってみる。

# Nest CLIをインストールする
npm i -g @nestjs/cli

# プロジェクトを作成する
nest new nest-app

プロジェクトを立ち上げる

HTTPサーバーがリッスンしている状態でアプリを起動するにはnpm run startを実行する。

ファイルの変更を監視した状態でアプリを起動するにはnpm run start:devを実行する。

プロバイダとは

プロバイダは依存関係として注入可能であることが主に大事な要素。

なのでプロバイダのクラスを定義するときは@Injectableを使用する。

定義したプロバイダはコンストラクタベースの注入方法で使用される。

そしてapp.module.ts@Moduleデコレーターのprovidersにサービスを登録することで依存関係が解決できるようになる。

// src/app.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}

プロバイダは次のようにしてmoduleに登録する。

// src/app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';

@Module({
  imports: [UsersModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

サービスとは

サービスはデータの保存と取得を受け持つプロバイダ。

サービスを作るにはnest g service サービス名(小文字)コマンドを実行する。

// src/users/users.service.ts

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Injectable()
export class UsersService {
  create(createUserDto: CreateUserDto) {
    return 'This action adds a new user';
  }

  findAll() {
    return `This action returns all users`;
  }

  findOne(id: number) {
    return `This action returns a #${id} user`;
  }

  update(id: number, updateUserDto: UpdateUserDto) {
    return `This action updates a #${id} user`;
  }

  remove(id: number) {
    return `This action removes a #${id} user`;
  }
}

コントローラーとは

コントローラーの役割は、送られてくるリクエストを受け取って、レスポンスをクライアントに返すことである。 基本的に各コントローラーは複数のルートを持つ。

コントローラーを作るには、nest g coコマンドを実行する。

// src/users/users.controller.ts

import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }

  @Get()
  findAll() {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(+id);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.update(+id, updateUserDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(+id);
  }
}

DTOを定義する

Controllers | NestJS - A progressive Node.js framework

DTOはクライアントから、どのようなデータが送信されるべきかを定義するオブジェクトである。

DTOインターフェイスを使用して定義することもできるが、NestJSでは基本的にクラスを用いて定義することが推奨されている。

// src/users/dto/create-user.dto.ts
export class CreateUserDto {
  email: string;
  password: string;
  name: string;
}

次のようにして利用する

// src/users/users.service.ts

@Injectable()
export class UsersService {
  create(createUserDto: CreateUserDto) {
    console.log("送信されたデータ", createUserDto);
    return 'This action adds a new user';
  }
...

モジュールとは

Modules | NestJS - A progressive Node.js framework

モジュールは@Module()デコレータでアノテーションされたクラス。

機能モジュールを作ることで、特定の機能に関連するコードをまとめて整理することができる。

// src/users/users.module.ts

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';

@Module({
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

作成された機能モジュールはルートモジュールであるapp.module.tsで読み込む。

// src/app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';

@Module({
  imports: [UsersModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

リソースを作ってみる

NestJSにはCRUDジェネレータという機能が存在している。必要な度にサービスやコントローラーを1から作らなくても、コマンドを実行することで必要なファイル群を生成してくれる。

nest g resource

例えば、usersモジュールのリソースを作成しようとすると次のようなファイル群が自動的に作成される。

  • src
    • users
      • dto
        • create-user.dto.ts
        • update-user.dto.ts
      • entities
        • user.entity.ts
      • users.controller.spec.ts
      • users.controller.ts
      • users.module.ts
      • users.service.spec.ts
      • users.service.ts

こんな感じで、NestJSはSOLID原則に基づいて開発できるような仕組みが整っているので、迷子にならずに開発が行える。

なんで今まで触ってこなかったんだろうと思うくらい素晴らしいフレームワークぽい。。。