7
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

お題は不問!Qiita Engineer Festa 2023で記事投稿!

Todoアプリを作成してNest.jsのキャッチアップをしてみた

Last updated at Posted at 2023-07-17

はじめに

後述の記事を参考にNest.jsのキャッチアップを行いました。
ワンポイント追加として、DockerでDB(Postgres)を構築し、そこに接続するように設定してみました。
私が普段使っているバックエンドフレームワークはLaravelですが、そもそもの設計思想の違いなのかすんなりと理解が進まなかったので備忘録として記載します。

この記事の内容はほとんど下記2記事の内容をなぞったものです。
下記の記事に従って動かないとか、どんなふうに読んでいるんだろう的な時の参考になれば幸いです。

リポジトリ

https://github.com/ryosuke-horie/nest-todo-app/

参考記事

以下の2記事を参考に進めています。

Next.js

NestJSを触りながら学ぶ(TodoAPI作成)

Docker postgresql

【Docker】postgresqlの構築

開発環境

  • Windows 10
  • WSL2
  • node v18.16.0
  • nest v10.1.9

インストール

$ npm i -g @nestjs/cli
$ nest new NestTodoApp // npm を使用するように指定する
$ npm run start

rapture_20230717194128.jpg

初期画面がすごくシンプル。

データベース作成

docker-compose.ymlをルートに作成

version: '3'

services:
  db:
    image: postgres:14
    container_name: postgres
    ports:
      - 5432:5432
    volumes:
      - db-store:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=passw0rd
volumes:
  db-store:

environmentに必須項目のパスワードのみを指定

DB起動

docker-compose up -d

A5M2(DB接続ツール)を利用して、接続。

  • • DBファイルのパス(/var/lib/postgresql/data)をvolumeにマウントして永続化しています。

ファイル削除

記事に従う。

必要パッケージのインストール

npm i @nestjs/typeorm typeorm pg @nestjs/config class-validator class-transformer

開発

構成を確認

CLIでモジュールを生成

nest g module [module名]で自動生成できる

nest g module tasks

CLIでControllerを作成

nest g controller tasks --no-spec

--no-specオプションによってテスト用のファイルを生成しないようにしている。

Controllerを修正

記事の通り

import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from '@nestjs/common';

@Controller('tasks')
export class TasksController {
    
    @Get()
    getTasks() {
        return "getTasks Success!"
    }

    @Get('/:id')
    getTaskById(
        @Param('id', ParseIntPipe) id: number) {
        return `getTaskById Success! Parameter [id:${id}]`
    }

    @Post()
    createTask(
        @Body('title') title: string,
        @Body('description') description: string) {
        return `createTask Success! Prameter [title:${title}, descritpion:${description}]`
    }

    @Delete('/:id')
    deleteTask(
        @Param('id', ParseIntPipe) id: number) {
        return `deleteTask Success! Prameter [id:${id}]`
    }

    @Patch('/:id')
    updateTask(
        @Param('id', ParseIntPipe) id: number,
        @Body('status') status: string ) {
        return `updateTask Success! Prameter [id:${id}, status:${status}]`
    }
}
  • @Param()@Body()はHTTPリクエストを取得するためのデコレータ
  • ParseIntPipeはパイプという機能の1つ
    • コントローラのメソッドに値が引き渡される前に変換、もしくは検証を行います。
    • @Param('id', ParseIntPipe)ではidを数値型へと変換

開発中はnpm run start:devを使えば変更が即時反映できる。

DTO・PIPEを作成してPOSTメソッドにバリデーションを追加

記事に従ってDTOとPIPEを作成

Controllerに追記して、POSTメソッドのバリデーションを追加する。

バリデーションの中身は

  • statusが'OPEN','PROGRESS','DONE'のいづれかでないとエラーを返す
  • TitleとDescriptionの値が空ならエラーを返す

Service作成

nest g service tasks

tasks.module.tsに自動で追記される。

TypeORMの準備

接続設定 app.module.ts

ここはDockerを使っているので設定が一部変更している部分。

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TasksModule } from './tasks/tasks.module';

@Module({
  imports: [
    TasksModule,
    // importsに追加
    TypeOrmModule.forRoot({
      type: 'postgres',       // DBの種類
      port: 5432,             // 使用ポート
      database: 'postgres',    // データベース名
      host: 'localhost',      // DBホスト名
      username: 'postgres',       // DBユーザ名
      password: 'passw0rd',       // DBパスワード
      synchronize: true,      // モデル同期(trueで同期)
      entities: [__dirname + '/**/*.entity.{js,ts}'],  // ロードするエンティティ
    })
  ],
})
export class AppModule {}

Entitiyの作成

task.entity.tsを作成し、以下を記述

import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class Task extends BaseEntity {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;

    @Column()
    description: string;

    @Column()
    status: string;
}

この時点でA5M2で確認するとtaskテーブルが作成されている。

環境変数の更新

DBを同期するように設定しているが、本番でこの運用をするとよくないので記事に従って.envファイルを作成

TypeORMのConfigService

DBのパスワードに数字が盛り込まれている影響か、エラーが出たため、.env/default.envの値をシングルクオーテーションで囲んだ。

main.tsを書き替えてみるとDB_SYNCの値が設定されていなかったが、

NODE_ENV=development npm run start:dev

を利用することで反映されていることが確認できました。

Serviceの修正

記事に従って修正

Controllerから受け取った値で実処理するよう構成している。

async getTaskById(id: number): Promise<Task> {
        const found = await this.taskRepository.findOne(id);

ここでエラー:型 'number' には型 'FindOneOptions' と共通のプロパティがありません。

が出たので以下のように仮で修正

const found = await this.taskRepository.findOne({
            where: {
              id: id,
            },
          })

テストを作成する前にModule & Controller修正に進む

エラーが出るため。

Repositoryのimportがmoduleで不足してエラーが出るため。

テストを記述して実行

passしたので完了。

感想

ふわっとREST APIを実装できました。元記事を作成された方がすごいです。

TypeORMのドキュメントを読み込む必要があるかと思います。

ワンポイント追加でDockerでDBをローカル環境に作成して利用するように設定できました。

個人的にはEntityやRepositoryといったデザインパターン的な部分についても追加で学ぶ必要があるかと思います。

7
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?