React typeorm

ReactとNestでWebアプリケーションを作る4回目です。 最初からやりたい場合はナビゲーションから初回を開いてください。

NestからTypeOrmを使ってDBにデータを保存していきます。

データベースはPodmanというアプリケーションを利用して使用します。 PodmanはDockerというアプリケーションと同じような使い方ができます。 Dockerは一部、仕事で使うときに有償になってしまったので、ここではPodmanを使うことで、勉強したことがそのままお仕事でも使えるようにしています。

Podmanはこちらの手順でインストールしておいてください。

まずはPodmanでPostgresというデータベースを起動します。 コマンドが長いので、こちらもpackage.jsonに記載しておきます。

myreactapp/package.json を以下の内容に変更します。

{
  "name": "myreactapp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
    ,"watch:client": "npm start --prefix front"
    ,"watch:server": "npm run start:dev --prefix server"
    ,"watch": "run-p watch:**"
    ,"start:db": "podman run -d --rm -p 5432:5432 -v postgres:/var/lib/postgresql/data -e POSTGRES_PASSWORD=postgres --name postgres postgres:15-alpine" (←この行を追加します。)
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "npm-run-all": "^4.1.5"
  }
}

そして、ターミナルでmyreactappディレクトリで以下のコマンドを実行します。

npm run start:db

これでデータベースが起動します。

続きまして、Nestからデータベースに接続します。 まずはDatabaseにつなぐライブラリであるpgとつなぎやすくするTypeORMをインストールします。

ターミナルで以下のコマンドを実行します。

npm i typeorm pg --prefix server

続きまして、データベースに保存する型を定義します。 今回はアンケートをデータベースに保存できるアプリを作成するため、アンケートの型を作成します。

myreactapp/server/src/models というディレクトリを作成してください。 そして、その中に、Enquete.tsというファイルを作成します。内容は以下です。

import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from 'typeorm'

@Entity()
export default class Enquete extends BaseEntity {
  @PrimaryGeneratedColumn()
  public id: number = 0

  @Column()
  public point: number = 0

  @Column()
  public message: string = ""

  @Column()
  public mail: string = ""
}

一つのアンケート回答にユニークな番号をつけるためのid、ポイント、メッセージ、回答者のメールアドレスを保存できる型をつくりました。

次にデータベースにアクセスできるようにします。 myreactapp/server/src にdatabase.tsというファイルを作成します。 内容は以下です。

import { DataSource } from "typeorm";
import Enquete from "./models/Enquete";

let dataSource;

export async function initDataSource() {
    dataSource = new DataSource({
        type: "postgres",
        url: "postgres://postgres:postgres@127.0.0.1:5432/postgres",
        logging: true,
        synchronize: true,
        entities: [
            Enquete
        ],
    })
    await dataSource.initialize();
}
export function getDataSource() {
    return dataSource;
}

最後に、アクセス内容をデータベースに保存する仕組みを作成します。

myreactapp/server/src に enquete.controller.ts というファイルを作成します。 内容は以下です。

import { Controller, Post, Body, Res, HttpStatus, BadRequestException} from '@nestjs/common';
import { Response } from "express";
import { getDataSource } from './database'; 
import Enquete from './models/Enquete';

class EnqueteDto {
    public point: number = 0
    public message: string = ""
    public mail: string = ""
}

@Controller("/api/enquetes")
export class EnqueteController {
  @Post()
  async postEnquete(@Body() enqueteDto: EnqueteDto) {
    if(!enqueteDto.point || !enqueteDto.message || !enqueteDto.mail) {
      throw new BadRequestException();
    }
    const enquete = new Enquete();
    enquete.point = enqueteDto.point;
    enquete.message = enqueteDto.message;
    enquete.mail = enqueteDto.mail;
    await getDataSource().getRepository(Enquete).save(enquete);
    return enquete;
  }
}

内容を解説します。

 async postEnquete(@Body() enqueteDto: EnqueteDto) {
    //省略
 }

@Body() enqueteDto: EnqueteDto で、ブラウザからの通信内容をEnqueteDto型としてenqueteDtoという変数で受け取る処理を定義します。 この関数が実際に動くのは、ブラウザのアクセスをNestが受け取り、Nestがこの関数を実行したときです。

    if(!enqueteDto.point || !enqueteDto.message || !enqueteDto.mail) {
      throw new BadRequestException();
    }

では、ブラウザからの通信内容に必要事項が入っているかをチェックしています。 !enqueteDto.point || !enqueteDto.message || !enqueteDto.mail printか、messageか、mailがなかったら、res.status(HttpStatus.BAD_REQUEST).send(); おかしな通信で有るということを返答し、return;で処理を終了するようにしています。

    const enquete = new Enquete();
    enquete.point = enqueteDto.point;
    enquete.message = enqueteDto.message;
    enquete.mail = enqueteDto.mail;

では、ブラウザからの通信内容をEnqueteというデータベースに保存するための型にし、

    await getDataSource().getRepository(Enquete).save(enquete);

で、データベースに保存じています。 getDataSource()で、データベースに通信するためのオブジェクトを取得し、.getRepository(Enquete)で、アンケートに保存するためのオブジェクトを取得し、.save(enquete);で先程作ったEnqueteをデータベースに保存しています。awaitをすることによって、保存処理が終了するまで次の処理を行わないようにしています。

最後に

    return enquete;

することでブラウザに保存したデータを返却しています。

この処理をNestに組み込みます。

myreactapp/server/src/app.module.ts を編集します。

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { EnqueteController } from './enquete.controller'; // この行を追加

@Module({
  imports: [],
  controllers: [AppController, EnqueteController], //この行に , EnqueteControllerを追加
  providers: [AppService],
})
export class AppModule {}

これで外部からEnqueteControllerが呼び出し可能になります。

最後に、サーバ起動時にデータベースにつながるようにします。

myreactapp/src/main.ts を変更します。

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { initDataSource } from './database'; //この行を追加

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await initDataSource(); //この行を追加
  await app.listen(3001);
}
bootstrap();

では、Reactからの入力をデータベースに保存するようにしてみます。