NestJS プロジェクト立ち上げ
NestJS プロジェクト立ち上げ

NestJS プロジェクト立ち上げ

UMORiH
UMORiH投稿日:2024-06-24 最終更新日:2024-07-10

NestJS プロジェクト作成

// CLI のグローバルインストール
npm i -g @nestjs/cli

// NestJS プロジェクト作成
npx nest new sample-api

Module、Controller、Service の作成

// Module
npx nest g mo weapons

// Controller
npx nest g co weapons

// Service
npx nest g s weapons

Service 例

import { Injectable } from '@nestjs/common';
import { PrismaClient, Weapon } from '@prisma/client';
import {
  CreateWeaponDto,
  UpdateWeaponDto
} from '../types/dto/weapons.dto';

@Injectable()
export class WeaponsService {
  private prisma: PrismaClient;

  constructor() {
    this.prisma = new PrismaClient();
  }

  async getAllWeapons(): Promise<Weapon[]> {
    return this.prisma.weapon.findMany();
  }

  async getWeapon(id: number): Promise<Weapon> {
    return this.prisma.weapon.findUnique({ where: { id } });
  }

  async createWeapon(data: CreateWeaponDto): Promise<Weapon> {
    return this.prisma.weapon.create({ data });
  }

  async updateWeapon(id: number, data: UpdateWeaponDto): Promise<Weapon> {
    return this.prisma.weapon.update({ where: { id }, data });
  }

  async deleteWeapon(id: number): Promise<Weapon> {
    return this.prisma.weapon.delete({ where: { id } });
  }
}

Controller 例

// src/weapons/weapons.controller.ts
import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common';
import { WeaponsService } from './weapons.service';
import {
  CreateWeaponDto,
  UpdateWeaponDto,
  CreateWeaponResultDto,
  UpdateWeaponResultDto
} from '../types/dto/weapons.dto';
import { ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';

@ApiTags('weapons')
@Controller('weapons')
export class WeaponsController {
  constructor(private readonly weaponsService: WeaponsService) {}

  @Get()
  @ApiOperation({
    operationId: 'Weapons_get',
    summary: '武器一覧を取得する',
  })
  @ApiResponse({
    status: 200,
    description: 'Success'
  })
  getAllWeapons() {
    return this.weaponsService.getAllWeapons();
  }

  @Get(':id')
  @ApiOperation({
    operationId: 'Weapon_get',
    summary: '武器を取得する',
  })
  @ApiResponse({
    status: 200,
    description: 'Success'
  })
  getWeapon(@Param('id') id: string) {
    return this.weaponsService.getWeapon(+id);
  }

  @Post()
  @ApiOperation({
    operationId: 'Weapon_create',
    summary: '新規武器を作成する',
  })
  @ApiResponse({
    status: 201,
    description: 'Success',
    type: CreateWeaponResultDto
  })
  createWeapon(@Body() weaponData: CreateWeaponDto) {
    return this.weaponsService.createWeapon(weaponData);
  }

  @Put(':id')
  @ApiOperation({
    operationId: 'Weapon_create',
    summary: '武器を更新する',
  })
  @ApiResponse({
    status: 201,
    description: 'Success',
    type: UpdateWeaponResultDto
  })
  updateWeapon(@Param('id') id: string, @Body() weaponData: UpdateWeaponDto) {
    return this.weaponsService.updateWeapon(+id, weaponData);
  }

  @Delete(':id')
  @ApiOperation({
    operationId: 'Weapon_delete',
    summary: '武器を削除する',
  })
  @ApiResponse({
    status: 204,
    description: 'Success'
  })
  deleteWeapon(@Param('id') id: string) {
    return this.weaponsService.deleteWeapon(+id);
  }
}

Prisma の設定

cd sample-api
yarn add prisma --save-dev
npx prisma init

shema.prisma


datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

// ER 図の自動生成
generator erd {
  provider = "prisma-erd-generator"
  theme = "forest"
  output = "scheme.md"
}

generator client {
  provider = "prisma-client-js"
}

model Weapon {
  id          Int      @id @default(autoincrement())
  name        String
  attackPower Int @map("attack_power")
  attribute   String

  @@map("weapons")
}

model User {
  id          Int      @id @default(autoincrement())
  name        String

  @@map("users")
}

DB マイグレーション

yarn add @prisma/client
npx prisma migrate dev --name init

Swagger ドキュメント作成

import * as fs from 'fs';

import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';

async function bootstrap() {
  // (1) アプリケーションのインスタンスを作成する
  // 引数に渡しているAppModuleはアプリケーションのルートモジュール
  const app = await NestFactory.create(AppModule);

  // (2) DocumentBuilderでSwaggerのAPIドキュメントの設定を行う
  const config = new DocumentBuilder()
    .setTitle('DQ Weapons API')
    .setDescription('The DQ Weapons API description')
    .setVersion('1.0')
    .build();

  // (3) SwaggerモジュールにAPIドキュメントを出力させる
  const document = SwaggerModule.createDocument(app, config);
  // (4) 生成したAPIドキュメンテーションを指定したパス(/api)に公開する
  // /apiにアクセスすると、Swagger UIを経由してAPIドキュメンテーションを閲覧できる
  SwaggerModule.setup('api', app, document);

  // (5) API クライアント用に api-spce ファイルを生成する
  fs.writeFileSync(
    'src/api-spec/api-spec.json',
    JSON.stringify(document, undefined, 2),
  );

  // (6) NestJSアプリケーションを指定したポートで起動する。ここでは3000
  await app.listen(3000);
}
bootstrap();

DTO クラス

mkdir src/types/dto
cd src/types/dto
touch weapons.dto.ts

dto ファイル

import { ApiProperty } from '@nestjs/swagger';

export class CreateWeaponDto {
  @ApiProperty({
    description: '名前',
    example: 'sword',
    required: true,
  })
  name: string;

  @ApiProperty({
    description: '威力',
    example: 10,
    required: true,
  })
  attackPower: number;

  @ApiProperty({
    description: '属性',
    example: 'normal',
    required: true,
  })
  attribute: string;
}
export class CreateWeaponResultDto {
  @ApiProperty({
    description: '武器ID',
    example: 1,
    required: true,
  })
  id: number;

  @ApiProperty({
    description: '名前',
    example: 'sword',
    required: true,
  })
  name: string;

  @ApiProperty({
    description: '威力',
    example: 10,
    required: true,
  })
  attackPower: number;

  @ApiProperty({
    description: '属性',
    example: 'normal',
    required: true,
  })
  attribute: string;
}

Docker 環境構築

cd src
touch .env
touch docker-compose.yml

docker-compose.yml

version: '3.9'
services:
  mysql:
    image: mysql:8.0.34
    platform: linux/amd64
    container_name: mysql-container_dqApi
    ports:
      - 3307:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: dqApi_develop

.env

DATABASE_URL="mysql://root:root@localhost:3307/dqApi_develop"

Docker 立ち上げ

docker compose up -d // コンテナの作成
docker-compose exec mysql mysql -hlocalhost -u root -p monap_develop // MySQL の起動

Prisma migrate

npx prisma migrate dev --name init

参考文献

NestJS、PrismaとSwaggerでREST APIを開発するチュートリアル【Next.js】PrismaでMySQLローカル環境をDocker構築する方法