🦁

NestJSでREST(その2)

2023/04/12に公開

前回まで

https://zenn.dev/robon/articles/76d4ec767b72ae

NestJSのCLIでWebサーバー部分はできちゃいました。👏

データベースと繋ぐ

TypeORM(とPostgres)を導入

本家を含めて、mysqlが多いような気がしますが、今回は、別件でPostgesを使っていたので、Postgresでやります。

$ npm install --save @nestjs/typeorm typeorm pg

customersを実装する

まず、テーブルを作ります。

CREATE TABLE CUSTOMER (
    CUSTOMER_ID int,
    NAME text,
    ADDRESS text,
    CONSTRAINT PK_CUSTOMER PRIMARY KEY(CUSTOMER_ID)
);

ここで英大文字で書いても、Postgresさんは英小文字で認識されていて、後でハマります。

TypeORMの設定

TypeORMにデータベースの設定をしつつ、NestJSのモジュールとしてAppModuleに組み込みます。

src/app.modules.ts
@@ -1,10 +1,25 @@
 import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
 import { AppController } from './app.controller';
 import { AppService } from './app.service';
 import { CustomersModule } from './customers/customers.module';
+import { Customer } from './customers/entities/customer.entity';
 
 @Module({
-  imports: [CustomersModule],
+  imports: [
+    CustomersModule,
+    TypeOrmModule.forRoot({
+      type: 'postgres',
+      host: '■■■■',
+      port: 5432,
+      username: '■■■■',
+      password: '■■■■',
+      database: 'postgres',
+      entities: [Customer],
+      logging: true,
+      synchronize: false,
+    }),
+  ],
   controllers: [AppController],
   providers: [AppService],
 })

loggingをtrueにしておくとハマったときに助かります。(ハマってからtrueにしました)
設定がこんな感じだと丸見えなので、あとでなんとかします。

エンティティの設定

Java界隈でお馴染みの香りがします。

src/customers/entities/customer.entity.ts
@@ -1 +1,13 @@
-export class Customer {}
+import { Entity, Column, PrimaryColumn } from 'typeorm';
+
+@Entity()
+export class Customer {
+  @PrimaryColumn({ name: 'customer_id' })
+  customerId: number;
+
+  @Column()
+  name: string;
+
+  @Column()
+  address: string;
+}

ここでハマりました。TypeORMさんは、テーブル名やカラム名をダブルクォートで囲んで渡してます。SQLの世界では大文字小文字の区別はしないのですが、Postgresさんは、ダブルクォートで囲むと書かれたとおりの文字列としてマッチングするそうです。

ですから、上で、@PrimaryColumn({ name: 'customer_id' })としているところをCREATE TABLE文のとおりに'CUSTOMER_ID'としてしまうと、「そんなカラムはありません」の一点張りで動きません。

今回に限らず、実は、ORマッパー嫌いです(笑)。今回は、logging: trueにして、TypeORMが表示したSQLを直叩きしないと解決できませんでした。「な。だから最初から俺にSQL書かせろよ」

DTOの設定

前回のイメージのJSONになるように定義します。

src/customers/dto/create-customer.dto.ts
@@ -1 +1,5 @@
-export class CreateCustomerDto {}
+export class CreateCustomerDto {
+  customerId: number;
+  name: string;
+  address: string;
+}

Update用のクラスは、以下のように、生成された状態のまま変更しなくても大丈夫です。

src/customers/dto/update-customer.dto.ts
export class UpdateCustomerDto extends PartialType(CreateCustomerDto) {}

PartialTypeって何?ってなりますよね。

The PartialType() function returns a type (class) with all the properties of the input type set to optional.

https://docs.nestjs.com/openapi/mapped-types

むむむ。ということで、ソースコードを遡ると

typescript/lib/lib.es5.d.ts
/**
 * Make all properties in T optional
 */
type Partial<T> = {
    [P in keyof T]?: T[P];
};

ということで、?が付いてオプショナル。作成の時は全部だけど、更新の時は欠けてもいい。というのができるのね。TypeScriptは深い。

次回は

serviceからやります。

https://zenn.dev/robon/articles/f5e5907aa871a5

GitHubで編集を提案
株式会社ROBONの技術ブログ

Discussion